Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Database encryption key backup / recovery feature for entropy-tss #1249

Merged
merged 86 commits into from
Feb 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
86 commits
Select commit Hold shift + click to select a range
1de907a
Dont allow mnemonic to be passed in via CLI, or environment variable …
ameba23 Oct 22, 2024
6b97f8f
Changelog
ameba23 Oct 22, 2024
7bd4358
Error handling
ameba23 Oct 22, 2024
4fcfc30
Add endpoint giving public keys
ameba23 Oct 23, 2024
e1649a4
Document new endpoint
ameba23 Oct 23, 2024
b12149b
Changelog
ameba23 Oct 23, 2024
53d5175
Clippy
ameba23 Oct 23, 2024
7c7acc7
Merge master
ameba23 Nov 8, 2024
a2c9cd7
Merge master
ameba23 Nov 18, 2024
5b8db51
Merge master
ameba23 Dec 5, 2024
1de6e81
Fix lockfile
ameba23 Dec 5, 2024
e97aa16
Merge branch 'master' into peg/generate-mnemonic
ameba23 Dec 13, 2024
8a8cb52
Add keys to appstate
ameba23 Dec 13, 2024
542849e
Rm persisted TSS keys
ameba23 Dec 13, 2024
15d3bbe
Tidy following app state change
ameba23 Dec 13, 2024
1ca0a0c
Fixes for tests and test helpers
ameba23 Dec 16, 2024
1303be2
Revert commented out import
ameba23 Dec 16, 2024
ebc339e
Clippy
ameba23 Dec 16, 2024
87c6afd
Update unsafe get test
ameba23 Dec 16, 2024
e71cc72
Rm setup only option, tidy
ameba23 Dec 16, 2024
6831f49
Tidy AppState interface
ameba23 Dec 16, 2024
1c36ae0
Allow for entropy-tss to be put in a non-ready state
ameba23 Dec 16, 2024
e416800
Update node info test
ameba23 Dec 16, 2024
7d8690b
Make app state ready in tests
ameba23 Dec 17, 2024
96c6a1a
Comments
ameba23 Dec 17, 2024
91ac834
Fix node info test
ameba23 Dec 17, 2024
b59d78d
Update pre-requisite checks
ameba23 Dec 17, 2024
c7d5ca2
Clippy
ameba23 Dec 17, 2024
a05a2a3
Force getting minimum balance before start
ameba23 Dec 17, 2024
079c394
Clippy
ameba23 Dec 17, 2024
12e940d
Comments
ameba23 Dec 17, 2024
a71521b
Fixes, add helper
ameba23 Dec 17, 2024
9d2f80d
Merge master
ameba23 Dec 18, 2024
7cb7ac6
Changelog
ameba23 Dec 18, 2024
3c08c75
Improve display of failed balance check errors
ameba23 Dec 18, 2024
c18124e
Improve display of failed registration checks
ameba23 Dec 18, 2024
35f6c9a
Add a 15 minutes maximum time limit for connecting to chain, funding …
ameba23 Jan 8, 2025
f67fa3d
Minor edits from PR review
ameba23 Jan 8, 2025
3dbf710
Minor edits from PR review
ameba23 Jan 8, 2025
db93f38
Merge master
ameba23 Jan 8, 2025
af51f2d
Add key provider module
ameba23 Jan 14, 2025
a6a9838
KVDB - replace password with 32 byte key
ameba23 Jan 14, 2025
55e4847
KVDB - rm password.rs
ameba23 Jan 14, 2025
d9c0a3c
Rm commented code
ameba23 Jan 14, 2025
10ab4bd
Add key provider logic
ameba23 Jan 15, 2025
06fe850
Improve key provider and add test
ameba23 Jan 16, 2025
d5922da
Kvdb stores key for backup
ameba23 Jan 16, 2025
374c98f
Actually back up keyshares in production
ameba23 Jan 16, 2025
974cdc8
Doccomments
ameba23 Jan 17, 2025
9043c95
Store backed-up keys in memory not kvdb
ameba23 Jan 17, 2025
b06a721
Encrypt keys when sending to be backed up
ameba23 Jan 17, 2025
39f3f68
Error handling, quote handling
ameba23 Jan 17, 2025
7a6b4b7
Fix test
ameba23 Jan 17, 2025
88ac607
Use tss_account id from signed message, not one provided by user
ameba23 Jan 20, 2025
e2558a8
Copy quote validation logic into entropy-tss and verify quotes when r…
ameba23 Jan 20, 2025
cb7dd4f
Error handling, tidy
ameba23 Jan 20, 2025
aacb5fc
Check measurement values when verifying quote
ameba23 Jan 20, 2025
ac6b312
Merge master
ameba23 Jan 20, 2025
bc60ec7
Rm unused import
ameba23 Jan 20, 2025
b8ecee8
Merge peg/non-persistant-tss-keys
ameba23 Jan 20, 2025
76c9443
Handle tdx-quote errors
ameba23 Jan 20, 2025
184c2dd
Use known encryption keys for test validators
ameba23 Jan 21, 2025
6aa01fd
Rename to backup provider, quote nonce getting api
ameba23 Jan 21, 2025
74b3927
Clippy
ameba23 Jan 21, 2025
1d10dab
Require node is ready in http route handlers
ameba23 Jan 21, 2025
5911e08
Mv quote measurement checking fn to attestation module
ameba23 Jan 21, 2025
e73ad94
Error handling
ameba23 Jan 21, 2025
7005f44
Changelog
ameba23 Jan 21, 2025
dcdaa67
Changelog
ameba23 Jan 21, 2025
054bcbc
Doccomments following review
ameba23 Jan 22, 2025
b33d261
Choose backup provider randomly, not from TSS id
ameba23 Jan 22, 2025
8c513cc
Refactor duplicated quote verifying fn
ameba23 Jan 22, 2025
d1ecf5b
Taplo
ameba23 Jan 22, 2025
05f5f3c
Update test-cli
ameba23 Jan 22, 2025
1de72b6
Fix for building entropy-shared for wasm
ameba23 Jan 22, 2025
9991f6d
Fix staking pallet mock
ameba23 Jan 22, 2025
c4c7e42
Fix staking pallet benchmarks
ameba23 Jan 22, 2025
57924d9
Fix attestation pallet tests
ameba23 Jan 22, 2025
0822704
Fix client tests
ameba23 Jan 22, 2025
9c68e94
Use sp_core::crypto::AccountId32 as key for hashmap to be more explicit
ameba23 Jan 23, 2025
57d22e2
Rename struct field following review
ameba23 Jan 23, 2025
18105ee
Minor edits from PR review
ameba23 Jan 23, 2025
ef46c51
Clippy
ameba23 Jan 23, 2025
a31ff0e
Flatten HTTP API structure following review
ameba23 Jan 24, 2025
f6146f4
Add an extra TSS state for connected to chain but not funded / fully …
ameba23 Jan 28, 2025
ca67e33
Merge master
ameba23 Feb 4, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ runtime
- On-chain unresponsiveness reporting [(#1215)](https://github.com/entropyxyz/entropy-core/pull/1215)
- Report unstable peers from TSS [(#1228)](https://github.com/entropyxyz/entropy-core/pull/1228)
- Add cli options for adding validator [(#1242)](https://github.com/entropyxyz/entropy-core/pull/1242)
- Database encryption key backup / recovery feature for entropy-tss [(#1249)](https://github.com/entropyxyz/entropy-core/pull/1249)
- Add no hash option [(#1266)](https://github.com/entropyxyz/entropy-core/pull/1266)

### Changed
Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion crates/client/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ pub use crate::{
errors::{ClientError, SubstrateError},
};
pub use entropy_protocol::{sign_and_encrypt::EncryptedSignedMessage, KeyParams};
pub use entropy_shared::{HashingAlgorithm, QuoteContext};
pub use entropy_shared::{attestation::QuoteContext, HashingAlgorithm};
use parity_scale_codec::Decode;
use rand::Rng;
use std::str::FromStr;
Expand Down
6 changes: 3 additions & 3 deletions crates/client/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use crate::{
update_programs,
};

use entropy_shared::{QuoteContext, QuoteInputData};
use entropy_shared::attestation::{QuoteContext, QuoteInputData};
use entropy_testing_utils::{
constants::{TEST_PROGRAM_WASM_BYTECODE, TSS_ACCOUNTS, X25519_PUBLIC_KEYS},
helpers::{encode_verifying_key, spawn_tss_nodes_and_start_chain},
Expand Down Expand Up @@ -129,7 +129,7 @@ async fn test_change_threshold_accounts() {
let encoded_pck = encode_verifying_key(&pck.verifying_key()).unwrap().to_vec();

let quote = {
let input_data = entropy_shared::QuoteInputData::new(
let input_data = QuoteInputData::new(
tss_public_key,
*x25519_public_key.as_bytes(),
nonce,
Expand Down Expand Up @@ -368,7 +368,7 @@ async fn test_set_session_key_and_declare_validate() {
let encoded_pck = encode_verifying_key(&pck.verifying_key()).unwrap().to_vec();

let quote = {
let input_data = entropy_shared::QuoteInputData::new(
let input_data = QuoteInputData::new(
tss_public_key,
*x25519_public_key.as_bytes(),
nonce,
Expand Down
2 changes: 0 additions & 2 deletions crates/kvdb/src/encrypted_sled/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,3 @@
//! Constants for [encrypted_sled](crate::encrypted_sled)
pub(super) const PASSWORD_VERIFICATION_KEY: &str = "verification_key";
pub(super) const PASSWORD_VERIFICATION_VALUE: &str = "verification_value";
pub(super) const PASSWORD_SALT_KEY: &[u8] = b"password_salt_key";
pub(super) const UNSAFE_PASSWORD: &str = "entropy_unsafe_password";
37 changes: 2 additions & 35 deletions crates/kvdb/src/encrypted_sled/kv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@
//! to be inserted, forming a [EncryptedRecord]:<encrypted value, nonce>. The nonce is later
//! used to decrypt and retrieve the originally inserted value.

use std::convert::TryInto;

use chacha20poly1305::{
self,
aead::{AeadInPlace, NewAead},
Expand All @@ -32,7 +30,6 @@ use zeroize::Zeroize;

use super::{
constants::*,
password::{Password, PasswordSalt},
record::EncryptedRecord,
result::{EncryptedDbError::*, EncryptedDbResult},
};
Expand All @@ -48,26 +45,13 @@ impl EncryptedDb {
/// Creates an XChaCha20 stream cipher from a password-based-key-derivation-function and
/// verifies that the password is valid.
/// See [super::Password] for more info on pdkdf.
pub fn open<P>(db_name: P, password: Password) -> EncryptedDbResult<Self>
pub fn open<P>(db_name: P, mut key: [u8; 32]) -> EncryptedDbResult<Self>
where
P: AsRef<std::path::Path>,
{
let kv = sled::open(db_name).map_err(CorruptedKv)?;

let password_salt: PasswordSalt = if kv.was_recovered() {
// existing kv: get the existing password salt
kv.get(PASSWORD_SALT_KEY)?.ok_or(MissingPasswordSalt)?.try_into()?
} else {
// new kv: choose a new password salt and store it
let mut password_salt = [0u8; 32];
rand::thread_rng().fill_bytes(&mut password_salt);
kv.insert(PASSWORD_SALT_KEY, &password_salt)?;
password_salt.into()
};

// zeroize key since we are no longer using it after creating cipher
let mut key = Self::chacha20poly1305_kdf(password, password_salt)?;
let cipher = XChaCha20Poly1305::new(&key);
let cipher = XChaCha20Poly1305::new(&key.into());
key.zeroize();

let encrypted_db = EncryptedDb { kv, cipher };
Expand All @@ -84,23 +68,6 @@ impl EncryptedDb {
Ok(encrypted_db)
}

fn chacha20poly1305_kdf(
password: Password,
salt: PasswordSalt,
) -> EncryptedDbResult<chacha20poly1305::Key> {
let mut output = chacha20poly1305::Key::default();

// default params: log_n = 15, r = 8, p = 1
scrypt::scrypt(
password.as_ref(),
salt.as_ref(),
&scrypt::Params::default(),
output.as_mut_slice(),
)?;

Ok(output)
}

/// get a new random nonce to use for value encryption using [rand::thread_rng]
fn generate_nonce() -> chacha20poly1305::XNonce {
let mut bytes = chacha20poly1305::XNonce::default();
Expand Down
5 changes: 0 additions & 5 deletions crates/kvdb/src/encrypted_sled/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,12 @@

mod constants;
mod kv;
mod password;
mod record;
mod result;

// match the API of sled
pub use kv::EncryptedDb as Db;
pub use password::{Password, PasswordMethod, PasswordSalt};
pub use result::{EncryptedDbError as Error, EncryptedDbResult as Result};

#[cfg(test)]
mod tests;

#[cfg(test)]
pub use tests::get_test_password;
91 changes: 0 additions & 91 deletions crates/kvdb/src/encrypted_sled/password.rs

This file was deleted.

37 changes: 12 additions & 25 deletions crates/kvdb/src/encrypted_sled/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,17 @@

use serial_test::serial;

use super::{kv::EncryptedDb, Password};
use super::kv::EncryptedDb;
use crate::{clean_tests, encrypted_sled::Db, get_db_path};

fn setup_db(require_password: bool) -> Db {
let db = if !require_password {
EncryptedDb::open(get_db_path(true), get_test_password())
} else {
EncryptedDb::open(get_db_path(true), Password::from("super-secret password."))
};
assert!(db.is_ok());
db.unwrap()
fn setup_db(key: [u8; 32]) -> Db {
EncryptedDb::open(get_db_path(true), key).unwrap()
}

#[test]
#[serial]
fn test_encrypted_sled() {
let db = setup_db(false);
let db = setup_db([1; 32]);

// insert <key: value> -> returns None
let res = db.insert("key", "value").unwrap();
Expand Down Expand Up @@ -73,36 +67,33 @@ fn test_encrypted_sled() {

#[test]
#[serial]
fn test_use_existing_salt() {
let db = setup_db(false);
fn test_use_existing_key() {
let db = setup_db([1; 32]);
let db_path = get_db_path(true);
drop(db);
// open existing db
assert!(EncryptedDb::open(db_path, get_test_password()).is_ok());
assert!(EncryptedDb::open(db_path, [1; 32]).is_ok());
clean_tests();
}

#[test]
#[serial]
fn test_password() {
let db = setup_db(true);
fn test_key() {
let db = setup_db([1; 32]);
let db_path = get_db_path(true);

drop(db);

// try to open the kv store using a different password
let db = EncryptedDb::open(
db_path,
Password::from("super-secret password!"), // replace '.' with '!'
);
// try to open the kv store using a different key
let db = EncryptedDb::open(db_path, [2; 32]);
assert!(matches!(db, Err(super::result::EncryptedDbError::WrongPassword)));
clean_tests();
}

#[test]
#[serial]
fn test_large_input() {
let db = setup_db(false);
let db = setup_db([1; 32]);

let large_value = vec![0; 100000];
let res = db.insert("key", large_value.clone()).unwrap();
Expand All @@ -112,7 +103,3 @@ fn test_large_input() {
assert_eq!(res, Some(sled::IVec::from(large_value)));
clean_tests();
}

pub fn get_test_password() -> Password {
crate::encrypted_sled::PasswordMethod::NoPassword.execute().unwrap()
}
17 changes: 7 additions & 10 deletions crates/kvdb/src/kv_manager/kv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use super::{
KeyReservation, DEFAULT_KV_NAME, DEFAULT_KV_PATH,
},
};
use crate::encrypted_sled::{self, Password};
use crate::encrypted_sled;

#[derive(Clone)]
pub struct Kv<V> {
Expand All @@ -44,22 +44,22 @@ where
{
/// Creates a new kv service. Returns [InitErr] on failure.
/// the path of the kvstore is `root_path` + "/kvstore/" + `kv_name`
pub fn new(root_path: PathBuf, password: Password) -> KvResult<Self> {
pub fn new(root_path: PathBuf, key: [u8; 32]) -> KvResult<Self> {
let kv_path = root_path.join(DEFAULT_KV_PATH).join(DEFAULT_KV_NAME);
// use to_string_lossy() instead of to_str() to avoid handling Option<&str>
let kv_path = kv_path.to_string_lossy().to_string();
Self::with_db_name(kv_path, password)
Self::with_db_name(kv_path, key)
}

/// Creates a kvstore at `full_db_name` and spawns a new kv_manager. Returns [InitErr] on
/// failure. `full_db_name` is the name of the path of the kvstrore + its name
/// Example: ~/entropy/kvstore/database_1
pub fn with_db_name(full_db_name: String, password: Password) -> KvResult<Self> {
pub fn with_db_name(full_db_name: String, encryption_key: [u8; 32]) -> KvResult<Self> {
let (sender, rx) = mpsc::unbounded_channel();

// get kv store from db name before entering the kv_cmd_handler because
// it's more convenient to return an error from outside of a tokio::span
let kv = get_kv_store(&full_db_name, password)?;
let kv = get_kv_store(&full_db_name, encryption_key)?;

tokio::spawn(kv_cmd_handler(rx, kv));
Ok(Self { sender })
Expand Down Expand Up @@ -129,13 +129,10 @@ where
/// let my_db = get_kv_store(&"my_current_dir_db")?;
/// let my_db = get_kv_store(&"/tmp/my_tmp_bd")?;
#[tracing::instrument(skip_all, fields(db_name))]
pub fn get_kv_store(
db_name: &str,
password: Password,
) -> encrypted_sled::Result<encrypted_sled::Db> {
pub fn get_kv_store(db_name: &str, key: [u8; 32]) -> encrypted_sled::Result<encrypted_sled::Db> {
// create/open DB
tracing::debug!("Decrypting KV store");
let kv = encrypted_sled::Db::open(db_name, password)?;
let kv = encrypted_sled::Db::open(db_name, key)?;

// log whether the DB was newly created or not
if kv.was_recovered() {
Expand Down
Loading