Menu Docs
Página inicial do Docs
/ /
Atlas Device SDKs
/ /

Criptografar um Realm - Swift SDK

Nesta página

  • Visão geral
  • Considerações
  • Armazenamento e reutilização de chaves
  • Impacto no desempenho
  • Criptografia e Atlas Device Sync
  • Acesso a um Realm criptografado a partir de vários processos
  • Exemplo

Você pode criptografar o arquivo de domínio no disco com AES-256 + SHA-2 fornecendo uma chave de criptografia de 64 bytes ao abrir um domínio.

O Realm criptografa e descriptografa dados de forma transparente com criptografia AES-256 padrão usando os primeiros 256 bits da 512chave de criptografia bits fornecida. O Realm usa os outros 256 bits da 512chave de criptografia de bits para validar a integridade usando um código de autenticação de mensagem baseado em hash (HMAC).

Aviso

Não use hashes criptograficamente fracos para chaves de encriptação de domínio. Para uma segurança ideal, recomendamos gerar chaves de encriptação aleatórias em vez de derivadas.

Observação

Não é possível criptografar um realm não criptografado existente

Você deve criptografar um realm na primeira vez que abri-lo. Se você tentar abrir um realm não criptografado existente usando uma configuração que contém uma chave de encriptação, o Realm exibirá um erro.

Veja a seguir os principais impactos a serem considerados ao criptografar um realm.

Você deve passar pela mesma chave de encriptação toda vez que abrir o domínio criptografado. Se você não fornecer uma chave ou especificar a chave errada para um domínio criptografado, o domínio SDK emitirá um erro.

Os aplicativos devem armazenar a chave de criptografia no Keychain para que outros aplicativos não possam ler a chave.

As leituras e gravações em realms criptografados podem ser até 10% mais lentas do que em realms não criptografados.

Você pode criptografar um realm sincronizado.

O Realm criptografa somente os dados no dispositivo e armazena os dados não criptografados na sua fonte de dados do Atlas. Qualquer usuário com acesso autorizado à fonte de dados do Atlas pode ler os dados, mas o seguinte ainda se aplica:

  • Os usuários devem ter as permissões de leitura corretas para ler os dados sincronizados.

  • Os dados armazenados no Atlas são sempre criptografados em nível de volume (disco).

  • A transferência entre cliente e servidor é sempre totalmente criptografada.

Você também pode ativar o Gerenciamento de chaves de cliente para criptografar os dados armazenados no Atlas usando a chave do seu provedor de nuvem (por exemplo, AWS KMS, Azure Key Vault, Google Cloud KMS).

Se precisar de chaves exclusivas para cada usuário do seu aplicativo, você poderá usar um provedor OAuth ou um dos provedores de autenticação Realm e um trigger de autenticação para criar uma chave 64bits e armazenar essa chave em um objeto de usuário.

Alterado na versão 10.38.0.

Começando com o Realm Swift SDK versão 10.38.0, o Realm é compatível com a abertura do mesmo domínio criptografado em vários processos.

Se o seu aplicativo usar o Realm Swift SDK versão 10.37.2 ou anterior, tentar abrir um domínio criptografado de vários processos gera esse erro: Encrypted interprocess sharing is currently unsupported.

Os aplicativos que usam versões anteriores do SDK têm duas opções para trabalhar com realms em vários processos:

  • Use um domínio não criptografado.

  • Armazene os dados que você deseja criptografar como propriedades do NSData em objetos de domínio. Em seguida, você pode criptografar e descriptografar campos individuais.

Uma ferramenta possível para criptografar e descriptografar campos é a estrutura do CryptoKit da Apple. Você pode usar o Swift Crypto para simplificar o desenvolvimento de aplicativos com o CryptoKit.

O seguinte código demonstra como gerar uma chave de encriptação e abrir um realm criptografado:

// Generate a random encryption key
NSMutableData *key = [NSMutableData dataWithLength:64];
(void)SecRandomCopyBytes(kSecRandomDefault, key.length, (uint8_t *)key.mutableBytes);
// Open the encrypted Realm file
RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
config.encryptionKey = key;
NSError *error = nil;
RLMRealm *realm = [RLMRealm realmWithConfiguration:config error:&error];
if (!realm) {
// If the encryption key is wrong, `error` will say that it's an invalid database
NSLog(@"Error opening realm: %@", error);
} else {
// Use the realm as normal...
}
// Generate a random encryption key
var key = Data(count: 64)
_ = key.withUnsafeMutableBytes { (pointer: UnsafeMutableRawBufferPointer) in
SecRandomCopyBytes(kSecRandomDefault, 64, pointer.baseAddress!) }
// Configure for an encrypted realm
var config = Realm.Configuration(encryptionKey: key)
do {
// Open the encrypted realm
let realm = try Realm(configuration: config)
// ... use the realm as normal ...
} catch let error as NSError {
// If the encryption key is wrong, `error` will say that it's an invalid database
fatalError("Error opening realm: \(error.localizedDescription)")
}

O seguinte exemplo de Swift demonstra como armazenar e recuperar uma chave gerada a partir do Keychain:

// Retrieve the existing encryption key for the app if it exists or create a new one
func getKey() -> Data {
// Identifier for our keychain entry - should be unique for your application
let keychainIdentifier = "io.Realm.EncryptionExampleKey"
let keychainIdentifierData = keychainIdentifier.data(using: String.Encoding.utf8, allowLossyConversion: false)!
// First check in the keychain for an existing key
var query: [NSString: AnyObject] = [
kSecClass: kSecClassKey,
kSecAttrApplicationTag: keychainIdentifierData as AnyObject,
kSecAttrKeySizeInBits: 512 as AnyObject,
kSecReturnData: true as AnyObject
]
// To avoid Swift optimization bug, should use withUnsafeMutablePointer() function to retrieve the keychain item
// See also: http://stackoverflow.com/questions/24145838/querying-ios-keychain-using-swift/27721328#27721328
var dataTypeRef: AnyObject?
var status = withUnsafeMutablePointer(to: &dataTypeRef) { SecItemCopyMatching(query as CFDictionary, UnsafeMutablePointer($0)) }
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")
})
// Store the key in the keychain
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
}
// ...
// Use the getKey() function to get the stored encryption key or create a new one
var config = Realm.Configuration(encryptionKey: getKey())
do {
// Open the realm with the configuration
let realm = try Realm(configuration: config)
// Use the realm as normal
} catch let error as NSError {
// If the encryption key is wrong, `error` will say that it's an invalid database
fatalError("Error opening realm: \(error)")
}

Voltar

Reduzir o tamanho do arquivo de domínio