+//! Store Tape encryptions keys
+//!
+//! This module can store 256bit encryption keys for tape backups,
+//! indexed by key fingerprint.
+//!
+//! We store the plain key (unencrypted), as well as a encrypted
+//! version protected by password (see struct `KeyConfig`)
+//!
+//! Tape backups store the password protected version on tape, so that
+//! it is possible to restore the key from tape if you know the
+//! password.
+
use std::collections::HashMap;
use anyhow::{bail, Error};
};
use crate::{
- api2::types::Kdf,
backup::{
Fingerprint,
KeyConfig,
- CryptConfig,
},
};
}
}
-/// Store Hardware Encryption keys (private part)
+/// Store Hardware Encryption keys (plain, unprotected keys)
#[derive(Deserialize, Serialize)]
pub struct EncryptionKeyInfo {
+ /// Key fingerprint (we verify the fingerprint on load)
pub fingerprint: Fingerprint,
+ /// The plain encryption key
#[serde(with = "hex_key")]
pub key: [u8; 32],
}
-pub fn compute_tape_key_fingerprint(key: &[u8; 32]) -> Result<Fingerprint, Error> {
- let crypt_config = CryptConfig::new(key.clone())?;
- Ok(crypt_config.fingerprint())
-}
-
-pub fn generate_tape_encryption_key(password: &[u8], kdf: Kdf) -> Result<([u8; 32], KeyConfig), Error> {
- let (key, mut key_config) = KeyConfig::new(password, kdf)?;
- key_config.fingerprint = Some(compute_tape_key_fingerprint(&key)?);
- Ok((key, key_config))
-}
-
impl EncryptionKeyInfo {
pub fn new(key: [u8; 32], fingerprint: Fingerprint) -> Self {
Self { fingerprint, key }
pub const TAPE_KEY_CONFIG_FILENAME: &str = "/etc/proxmox-backup/tape-encryption-key-config.json";
pub const TAPE_KEYS_LOCKFILE: &str = "/etc/proxmox-backup/.tape-encryption-keys.lck";
-/// Load tape encryption keys (private part)
+/// Load tape encryption keys (plain, unprotected keys)
pub fn load_keys() -> Result<(HashMap<Fingerprint, EncryptionKeyInfo>, [u8;32]), Error> {
let content = file_read_optional_string(TAPE_KEYS_FILENAME)?;
let mut map = HashMap::new();
for item in key_list {
- let expected_fingerprint = compute_tape_key_fingerprint(&item.key)?;
+ let key_config = KeyConfig::without_password(item.key)?; // to compute fingerprint
+ let expected_fingerprint = key_config.fingerprint.unwrap();
if item.fingerprint != expected_fingerprint {
bail!(
"inconsistent fingerprint ({} != {})",
Ok((map, digest))
}
-/// Load tape encryption key configurations (public part)
+/// Load tape encryption key configurations (password protected keys)
pub fn load_key_configs() -> Result<(HashMap<Fingerprint, KeyConfig>, [u8;32]), Error> {
let content = file_read_optional_string(TAPE_KEY_CONFIG_FILENAME)?;
Ok((map, digest))
}
+/// Store tape encryption keys (plain, unprotected keys)
+///
+/// The file is only accessible by user root (mode 0600).
pub fn save_keys(map: HashMap<Fingerprint, EncryptionKeyInfo>) -> Result<(), Error> {
let mut list = Vec::new();
Ok(())
}
+/// Store tape encryption key configurations (password protected keys)
pub fn save_key_configs(map: HashMap<Fingerprint, KeyConfig>) -> Result<(), Error> {
let mut list = Vec::new();
let raw = serde_json::to_string_pretty(&list)?;
let backup_user = crate::backup::backup_user()?;
- let mode = nix::sys::stat::Mode::from_bits_truncate(0o0600);
+ let mode = nix::sys::stat::Mode::from_bits_truncate(0o0640);
// set the correct owner/group/permissions while saving file
// owner(rw) = root, group(r)= backup
let options = CreateOptions::new()
Ok(())
}
-pub fn insert_key(key: [u8;32], key_config: KeyConfig) -> Result<(), Error> {
+/// Insert a new key
+///
+/// Get the lock, load both files, insert the new key, store files.
+pub fn insert_key(key: [u8;32], key_config: KeyConfig, force: bool) -> Result<(), Error> {
let _lock = open_file_locked(
TAPE_KEYS_LOCKFILE,
None => bail!("missing encryption key fingerprint - internal error"),
};
- if let Some(_) = config_map.get(&fingerprint) {
- bail!("encryption key '{}' already exists.", fingerprint);
+ if !force {
+ if config_map.get(&fingerprint).is_some() {
+ bail!("encryption key '{}' already exists.", fingerprint);
+ }
}
let item = EncryptionKeyInfo::new(key, fingerprint.clone());
}
// shell completion helper
+/// Complete tape encryption key fingerprints
pub fn complete_key_fingerprint(_arg: &str, _param: &HashMap<String, String>) -> Vec<String> {
let data = match load_key_configs() {
Ok((data, _digest)) => data,