tekartik / sembast.dart

Simple io database
BSD 2-Clause "Simplified" License
777 stars 63 forks source link

Encryption and already not encrypted databases #391

Open Sesa1988 opened 1 week ago

Sesa1988 commented 1 week ago

Hi,

I want to encrypt the database file but many of my users have already their databases not encrypted.

Is there a way to check if the database file is encrypted and if not call "encrypt"?

This way I could avoid a database migration what seams very dangerous to do locally.

alextekartik commented 1 week ago

Unfortunately no, you can just try to open a file with a codec (using encryption or not), it will fail if it does not match.

However the safest is to use a different file name for the regular and encrypted one (and delete the regular one when the encrypted database is created) and check if the encrypted database exists - DatabaseFactory.databaseExists() - first to find out whether you have an encrypted database.

Sesa1988 commented 1 week ago

Unfortunately no, you can just try to open a file with a codec (using encryption or not), it will fail if it does not match.

However the safest is to use a different file name for the regular and encrypted one (and delete the regular one when the encrypted database is created) and check if the encrypted database exists - DatabaseFactory.databaseExists() - first to find out whether you have an encrypted database.

Yes but thats very risky and could lead to data loss in the worst case.

I think it would be a cool feature if you configure encryption it will also open an not encrypted database and write it back encrypted.

Thats how I would expect it to work.

alextekartik commented 1 week ago

I think it would be a cool feature if you configure encryption it will also open an not encrypted database and write it back encrypted.

As you said that's risky and that might take a long time the first time the database is opened. I'll look into that to see if this is feasible without too much impact and risk

Sesa1988 commented 1 week ago

I think it would be a cool feature if you configure encryption it will also open an not encrypted database and write it back encrypted.

As you said that's risky and that might take a long time the first time the database is opened. I'll look into that to see if this is feasible without too much impact and risk

Its probably less risky and more of a default flow as deleting a database with real data and creating a new one or not?

I hope its possible :)

alextekartik commented 6 days ago

So I tried to...but that was getting too messy to handle 2 input format and having a mixed usage of encrypted and unencrypted data so I gave up.

However I added (somehow missing) DatabaseFactory.databaseExists() in sembast 3.7.4 and added documentation on how to perform a migration from a non encrypted to an encrypted database:

Encrypting an existing database

It is unfortunately not possible to encrypt an existing database in place as a database format is tight to the codec used. You have to create a new one and copy the data. You can use databaseMerge to copy the data in a single operation/transaction.

Below is an example of how to convert an existing non-encrypted database to an encrypted one:

// Encryption codec to use (to set as you wish)
SembastCodec? encryptionCodec;

// Existing db name, to convert and remove if it exists
var nonEncryptedDbName = 'my_database.db';
var encryptedDbName = 'my_database_encrypted.db';

late Database db;
// Check if non encrypted database exists
if (await factory.databaseExists(nonEncryptedDbName)) {
  // This should only happen once but could be a lengthy operation

  // Open the non encrypted database
  var nonEncryptedDb = await factory.openDatabase(nonEncryptedDbName);

  // Create a new encrypted database and copy the existing content
  await factory.deleteDatabase(encryptedDbName);
  db = await factory.openDatabase(encryptedDbName,
    codec: encryptionCodec);
  // Copy the content
  await databaseMerge(db, sourceDatabase: nonEncryptedDb);

  // Close and delete the non encrypted database
  await nonEncryptedDb.close();
  await factory.deleteDatabase(nonEncryptedDbName);
} else {
// Open the encrypted database
db = await factory.openDatabase(encryptedDbName,
    codec: encryptionCodec);
}
Sesa1988 commented 6 days ago

So I tried to...but that was getting too messy to handle 2 input format and having a mixed usage of encrypted and unencrypted data so I gave up.

However I added (somehow missing) DatabaseFactory.databaseExists() in sembast 3.7.4 and added documentation on how to perform a migration from a non encrypted to an encrypted database:

Encrypting an existing database

It is unfortunately not possible to encrypt an existing database in place as a database format is tight to the codec used. You have to create a new one and copy the data. You can use databaseMerge to copy the data in a single operation/transaction.

Below is an example of how to convert an existing non-encrypted database to an encrypted one:

// Encryption codec to use (to set as you wish)
SembastCodec? encryptionCodec;

// Existing db name, to convert and remove if it exists
var nonEncryptedDbName = 'my_database.db';
var encryptedDbName = 'my_database_encrypted.db';

late Database db;
// Check if non encrypted database exists
if (await factory.databaseExists(nonEncryptedDbName)) {
// This should only happen once but could be a lengthy operation

  // Open the non encrypted database
  var nonEncryptedDb = await factory.openDatabase(nonEncryptedDbName);

  // Create a new encrypted database and copy the existing content
  await factory.deleteDatabase(encryptedDbName);
  db = await factory.openDatabase(encryptedDbName,
    codec: encryptionCodec);
  // Copy the content
  await databaseMerge(db, sourceDatabase: nonEncryptedDb);

  // Close and delete the non encrypted database
  await nonEncryptedDb.close();
  await factory.deleteDatabase(nonEncryptedDbName);
} else {
// Open the encrypted database
db = await factory.openDatabase(encryptedDbName,
    codec: encryptionCodec);
}

Looks good thanks!

Will databaseExists open the database and prevent me from replacing it and reading the replaced content? Its for another usecase. I used the File-Type and appDir for exist checks.

alextekartik commented 2 days ago

Will databaseExists open the database

No it just checks whether the file exists