RFC-0157:支援 Fxfs 加密和多磁碟區支援

RFC-0157:Fxfs 加密與多磁碟區支援
狀態已接受
領域
  • 儲存空間
說明

說明 Fxfs 的加密和多磁碟區支援。

問題
毛皮變化
  • 666884
作者
審查人員
提交日期 (年-月-日)2022-04-07
審查日期 (年-月-日)2022-04-28

摘要

此 RFC 說明 Fxfs 中的加密與多磁碟區支援。

提振精神

Fuchsia 必須能支援多個使用 繫結至不同使用者密碼。

相關人員

審查人員:abarth@google.com、enoharemaien@google.com、 Palmer@google.com、 jfsulliv@google.com、jsankey@google.com、zarvox@google.com、

諮詢: Fuchsia 的安全性、儲存空間和隱私權團隊。

社交:這項設計經過儲存空間團隊的流通及審查 和上述審查人員,才能展開此 RFC 程序

設計

Fxfs 相關說明請參閱 RFC-0136

需求條件

  1. 應該可以建立、列舉及刪除磁碟區。

  2. 每個磁碟區應以不同的金鑰加密。

  3. 應為檔案名稱、大小和時間戳記等物件中繼資料 加密。

  4. 在沒有金鑰的情況下,您必須能夠刪除磁碟區。

  5. 系統應能支援鍵盤滾動機制,同時又省去麻煩 遷移工作。

  6. 應對磁碟區大小設限 (雖然設計主題 未來發展)。

  7. 你應該可以在不存取 鍵。

  8. 應該根據封鎖條件,防範指紋攻擊 數量。這種攻擊手法就是知道加密大小 (四捨五入至 最接近區塊) 可用於確認 檔案系統中存在這組檔案

範圍外

這項設計不包含以下領域:

  1. 在裝置之間轉移加密映像檔 (包含主機和目標) 裝置),但還是能協助偵錯 不是每次都能在正式環境中 開發的應用程式 但沒有先例

  2. 加密服務實作。本設計在其他地方就有了。

  3. 設計應支援關鍵滾動,但精準的 API 超出範圍

總覽

Fxfs 加密

Fxfs 內建加密支援個別檔案金鑰。Files 會 通常只有一個加密金鑰,但支援金鑰滾動和檔案 複製,這個格式可在每個檔案支援多個金鑰。金鑰將包裝 以及由 Fxf 通訊的加密服務加以包裝。

以下是根父項和根儲存庫中的以下物件 加密:

  1. 日誌 (位於根上層儲存庫中) 擁有異動項目 適用於以串流加密方式加密的子項儲存庫中繼資料。 這組加密的金鑰會是 每家商店的金鑰

  2. 子項儲存的圖層檔案 (位於根目錄中) 將會改為 加密。這些檔案的加密機制與 和其他檔案金鑰將使用個別商店金鑰包裝,並以 其他未加密的商店資訊。

根層級和根存放區中的其他物件不會經過加密,即 超區塊、所有與配置器相關的物件、 根物件儲存庫 (保存根儲存物件的中繼資料) 以及 。以上皆非 構成使用者資料。

這種情況的淨結果如下:

  • 使用者資料會加密
  • 所有中繼資料,包括檔案名稱、檔案大小、範圍資訊,以及 目錄資訊都會經過加密。

部分資訊不會加密:

  • 磁碟區中的檔案數量。
  • 分配給磁碟區的範圍組合。

物件 ID

Fxfs 內的物件 ID 目前是以單調遞增的方式分配 同時做為獨立管道使用如要解決這個問題, 系統會加密至少 32 位元的物件 ID (在分配時) 使用 ff1 加密。金鑰會在循環後經過 32 次輪替 物件 ID 值系統會包裝金鑰,並以 其餘未加密的商店資訊物件 ID 上限 32 位元 每次擲回鍵時,都會依單調遞增。

磁碟區中使用的物件數量和空間也提供了 側管道 (基本上可透過 statvfs 取得所有資訊)。定址 這不在 Fxfs 的創新設計範圍內 (這不是 Fxf 新手)。

金鑰管理

金鑰包裝和解除包裝是由另外一個「密封」負責服務 回應會類似以下的通訊協定:

/// Designates the purpose of a key.
type KeyPurpose = flexible enum {
    /// The key will be used to encrypt metadata.
    METADATA = 1;
    /// The key will be used to encrypt data.
    DATA = 2;
};

protocol Crypt {
    /// Creates a new wrapped key.  `owner`, effectively a nonce, identifies the
    /// owner (an object ID) of the key and must be supplied to `UnwrapKey`.
    /// `metadata` indicates that the key will be used to encrypt metadata which
    /// might influence the choice of wrapping key used by the service.  Returns
    /// the wrapping key ID used to wrap this key along with the wrapped and
    /// unwrapped key.  Errors:
    ///   ZX_ERR_INVALID_ARGS: purpose is not recognised.
    ///   ZX_ERR_BAD_STATE: the crypt service has not been correctly initialized
    ///     with a wrapping key for the specified purpose.
    CreateKey(struct {
        owner uint64;
        purpose KeyPurpose;
    }) -> (struct {
        wrapping_key_id uint64;
        wrapped_key bytes:48;
        unwrapped_key bytes:32;
    }) error zx.status;

    /// Unwraps keys that are wrapped by the key identified by `wrapping_key_id`.
    /// `owner` must be the same as that passed to `CreateKey`.  This can fail due
    /// to permission reasons or if an incorrect key is supplied.
    UnwrapKey(struct {
        wrapping_key_id uint64;
        owner uint64;
        key bytes:48;
    }) -> (struct {
        unwrapped_key bytes:32;
    }) error zx.status;
};
  • wrapping_key_id 的意義取決於地下室的實作者。 課程中也會快速介紹 Memorystore 這是 Google Cloud 的全代管 Redis 服務Fxfs 的數值不會有任何意義。

  • 您應該會為每個加密過的個別加密產品建立不同的連線 Fxfs 磁碟區,因此伺服器得以放置於不同程序、 預期的類型。

  • 目前支援 256 位元的金鑰 (與 Zxcrypt 一致)。

  • 地下室服務會使用 AEAD 來包裝金鑰 這表示包裝鍵的大小可能為 48 個位元組。

  • purpose 可用來分隔用於資料的中繼資料和鍵。 並是為了協助進行鍵滾動作業 (請見下方說明)。

精確實作 Crypt 服務和金鑰管理政策。 則不在這項設計的範圍內

磁碟上格式

每個檔案都會包含下列項目:

#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub enum EncryptionKeys {
    None,
    AES256XTS(WrappedKeys),
}

#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct WrappedKeys {
    /// The keys (wrapped).  To support key rolling and clones, there can be more
    /// than one key.  Each of the keys is given an identifier.  The identifier is
    /// unique to the object.  AES256-XTS requires a 512 bit key, which is made
    /// of two 256 bit keys, one for the data and one for the tweak.  Both those
    /// keys are derived from the single 256 bit key we have here.
    pub keys: Vec<(/* wrapping_key_id= */ u64, /* id= */ u64, [u8; 48])>,
}

各個範圍都會類似如下:

pub enum ExtentValue {
    /// Indicates a deleted extent; that is, the logical range described by the
    /// extent key is considered to be deleted.
    None,
    /// The location of the extent and other related information.  `key_id`
    /// identifies which of the object's keys should be used.  `checksums` hold
    /// post-encryption checksums.
    Some { device_offset: u64, checksums: Checksums, key_id: u64 },
}

系統會使用 AES-XTS-256 來加密資料區塊 (與 Zxcrypt)。檔案內的邏輯偏移用於調整。

中繼資料

物件儲存庫會保留記錄檔結構化合併 (LSM) 樹狀結構,用來保存中繼資料 系統會以與商店內檔案相同的方式加密 系統會建立圖層檔案所使用的金鑰,並將用途設為 「中繼資料」。

當交易進行時,變動會寫入日誌。這些 變異會套用至 LSM 樹狀結構的記憶體內層。一段時間 之後記憶體中的層會排入永久層中任何異動內容 將物件中繼資料樹狀結構寫入 日誌。為支援此特性,Fxfs 使用新的異動項目:

EncryptedObjectStore(Box<[u8]>),

Chacha20 將用於加密這些異動。此鍵的鍵會經過包裝, 能與其他未加密商店資料一併儲存。

在重播中,金鑰可能無法使用,在這種情況下會執行這些異動 會以加密形式儲存在記憶體中如果必須在記憶體內清除 來釋出日誌空間),這些經過加密的變動才會 寫入根存放區中的物件

金鑰可供使用時,已加密的異動 (可能為 在記憶體內或上述檔案中,也可解密及套用。目的地: 解密變異作業,必須提供加密串流中的偏移量;這是 儲存在商店的未加密資訊中。

這些新增至 StoreInfo 的新欄位 (Google 日曆的未加密資訊) 商店):

    // The (wrapped) key that encrypted mutations should use.
    mutations_key: Option<Box<[u8]>>,

    // Mutations for the store are encrypted using a stream cipher.  To decrypt the
    // mutations, we need to know the offset in the cipher stream to start it.
    mutations_cipher_offset: u64,

    // If we have to flush the store whilst we do not have the key, we need to
    // write the encrypted mutations to an object. This is the object ID of that
    // file if it exists.
    encrypted_mutations_object_id: u64,

刪除磁碟區

如要支援刪除磁碟區,配置中繼資料會包含下列項目的物件 ID: 擁有中繼資料的商店 ID:

pub struct AllocatorKey {
    pub device_range: Range<u64>,
}

pub enum AllocationRefCount {
    // Tombstone variant indicating an extent is no longer allocated.
    None,
    // Used when we know there are no possible allocations below us in the stack.
    // (e.g. on the first allocation of an extent.)
    // This variant also tracks the owning ObjectStore for the extent.
    Abs { count: u64, owner_object_id: u64 },
}

pub struct AllocatorValue {
     /// Reference count for the allocated range.
     /// (A zero reference count is treated as a 'tombstone', indicating that older
     /// values in the LSM Tree for this range should be ignored).
     pub refs: AllocationRefCount,
}

刪除磁碟區會連帶變更配置器,確保其符合所有 。經過大幅壓縮後 請確認這些記錄已不存在,而我們也能忘記 磁碟區已存在。分配器會保留已刪除磁碟區清單的相關資訊 與其餘中繼資料搭配使用

內嵌資料

Fxfs 目前不支援內嵌資料,但如果支援內嵌資料,將會 以用來加密中繼資料的金鑰加密。使用這些金鑰 也會隨著新的圖層檔案寫入而發展

安全清除

安全清除檔案時,即使金鑰仍無法復原 (除了硬體中的容器以外) 之後也會遭受入侵。考量到這一點 檔案系統通常在 Flash 裝置上運作 (這類裝置會使用垃圾 但清除所有出現的資料並不容易。唯一實用的 方法就是滾動包裝金鑰 (不應儲存在 Flash 中)。

「安全清除」並非預計實作的功能,不過這應該 完成下列程序:

  1. 開始使用新的包裝金鑰包裝新的中繼資料鍵。

  2. Fxfs 會使用舊的中繼資料金鑰重新編寫所有物件。

  3. 舊的中繼資料包裝金鑰遭到截斷 (通常是使用 TPM 功能) 。

步驟 2 可在 Fxfs 內執行 壓縮此為正常現象 方法包括定期和隨選的情況如要 安排 Fxf 每週一次 (例如每週) 發出大量壓縮 就取決於可用的金鑰

這個程序要求中繼資料鍵是以不同的 將金鑰包入資料中 (否則會強制重寫所有資料, 是禁止性質),因此提供給 create_key 的中繼資料引數 方法。

請注意,這項程序需要重新寫入磁碟區的「所有」中繼資料, 因此不應經常執行這些動作

按鍵滾動

上文概述的中繼資料包裝金鑰,以確保安全 清除。使用 下列程序:

  1. 開始使用新的包裝金鑰包裝新金鑰。傳回新的 wrapping_key_id 的鍵/值

  2. 要求 Fxfs 重新包裝所有符合特定 wrapping_key_id 的金鑰。用於 但後續設計則不需要使用磁碟中格式 變更。

  3. 按照「安全清除」程序包裝中繼資料金鑰。由於鍵屬於 一律寫入中繼資料檔案,應確保資料包裝 金鑰滑過舊包裝金鑰後,就會成功擲出金鑰。

請注意,步驟 2 和 3 可以合併。 這些金鑰會同時進行主要的壓縮及重新包裝

與「安全清除」一樣,金鑰滾動支援功能不打算實作 最初

雀斑

如果未使用這個金鑰,系統會執行有限度檢查。一致性, 加密儲存庫是不可能的 其他所有未加密儲存庫的程度和一致性

如果有可用的金鑰,就能實現完整的一致性 檢查或檢查個別磁碟區的中繼資料。

多磁碟區支援

fshost 會匯出新的目錄:磁碟區。目錄中的節點 ,代表 fshost 匯出的磁碟區,且會支援新的磁碟區通訊協定 (節點不支援其他通訊協定,也就是說,節點不支援其他通訊協定) 所以無法複製 fuchsia.io Node 通訊協定)。通訊協定將會是 例如:

type MountOptions = table {
    // A handle to the crypt service. Unencrypted volumes will ignore this option.
    crypt client_end:Crypt;
}

protocol Volume {
    // Mounts the volume and starts serving the filesystem. An error will be
    // returned if the volume is currently being served from a previous call
    // to Mount.
    Mount(resource struct {
        export_root server_end:Directory;
        options MountOptions;
    }) -> () error zx.status;
}

如提供的加密服務有誤,掛接就會失敗,但基準應該是 出色;使用者呼叫 Mount 時,應預期 掛接項目會 succeed;不應做為測試憑證的方式。

匯出根目錄看起來就會像現在由檔案系統公開。 fs.Admin 服務會公開,並使用 關機方法。如果所有連線 音量已關閉音量進入鎖定時,我們會謹慎確保音量 系統將捨棄所有未包裝的金鑰。

列舉和移除作業將透過 fuchsia.io Directory 通訊協定執行 磁碟區目錄移除作業不一定非同步,但成功完成 到一定的供應量後 已移除系統可以立即重複使用這個名稱,但聊天室可能需要一些時間 才能使用

新磁碟區無法使用 Directory 通訊協定的開放式方法,因為我們必須 提供地下室服務和其他設施。系統會改為新增新的通訊協定:

type CreateVolumeOptions = table {
    // Reserved for future use.
}

protocol Manager {
    // Creates a new data volume.
    CreateVolume(resource struct {
        name string:MAX_FILENAME;
        crypt client_end:Crypt;
        export_root server_end: Directory;
        options CreateVolumeOptions;
    }) -> () error zx.status;;
}

一開始,我們會假設 Fxfs 會管理所有 但未來應該會提供元件 可支援 Zxcrypt 支援的檔案系統

磁碟區中可能存在的名稱和精確磁碟區組合, 且不屬於此 RFC 的範圍。

實作

我們會按照一般做法,支援多個磁碟區和加密機制 。

目前沒有支援金鑰滾動、安全清除與 內嵌資料。

AES-XTS-256、ChaCha20 和 ff1 加密將由第三方 Crate 提供。

屆時必須進行安全性稽核。

成效

加密程序會影響效能,現有的檔案系統基準 會用於評估成效實作之後,Zxcrypt ,不限 會對目前成效造成的迴歸現象進行調查。

回溯相容性

這將是 Fxfs 的破壞性變更,需要重新格式化。

安全性考量

安全團隊已審查過這個 RFC。

基於下列需求,安全性取決於:

  1. 每個磁碟區應以不同的金鑰加密。

  2. 檔案資料和中繼資料應經過加密。

  3. 物件 ID 要用做副管道並不容易。

實作將需要通過安全性審查。

隱私權注意事項

隱私權團隊已審查這個 RFC。

主要的隱私權考量是下列資料不會 已加密:

  • 磁碟區中的檔案數量。
  • 分配給磁碟區的一組範圍 (包括 分配給磁碟區)。
  • 磁碟區的名稱。

所有其他資料和中繼資料都必須加密。這應該足以 解決包括指紋攻擊等相關要求

實作的安全性審查應可驗證設計是否符合 Google Cloud 就是最佳選擇

測試

我們將使用常見的單位、整合和 端對端測試Fxfs 將用於資料分區 這些測試會在 CQ 中執行,因此能夠這樣獲取曝光。

說明文件

有時必須提供說明文件,協助系統設計人員 為此產品提供不同的儲存空間方案不過 設定中的項目尚未決定, 此 RFC 1916 範圍

這個 RFC 中導入的 API 一開始 (但非常有可能無限期) 且目前都會記錄為 FIDL 的一部分。

缺點、替代方案和未知

此 RFC 中提到的加密設計比 Zxcrypt 使用的分區型加密。

系統設計人員仍可使用以分區為基礎的 但磁碟區之間的空間共用會受到限制: 靈活配合空間的分區型配置,需要 磁碟區管理工具 (因額外 間歇性) 會造成資料片段化問題 (在 分區可能需要重組)。此外,更不容易 支援以分區為基礎的配置安全清除和索引鍵滾動機制。

既有藝術品和參考資料

Zxcrypt 使用 AES-256 XTS 以類似於這個 RFC 將區塊加密, 使用的調整項目不同

這裡的設計與 Android 12 的加密機制大部分相容 需求。最大的差異在於 Fxfs 的日誌必須以非下列的串流加密方式加密 明確列為可接受