Change block cipher mode from XTS -> HCTR2
We will be using aes-hctr2-plain64 cipher for encryptedstore.
Reason: With XTS, an attacker can tamper or replay at 16-byte
granularity. A bit flip in the encrypted text diffuses randomly in
plaintext, but only within an aligned 16-byte range. But with HCTR2 this
diffusion will be at crypto sector size.
For IV we use the 64 bytes' sector number referred to as "plain64".
Bug: 259253336
Test: Run a vm with --storage & --storage-size flag
Change-Id: I1ecd98072d6cb552d93fbc4053a3e6f004e0854e
diff --git a/encryptedstore/src/main.rs b/encryptedstore/src/main.rs
index d7d2382..5f27fd7 100644
--- a/encryptedstore/src/main.rs
+++ b/encryptedstore/src/main.rs
@@ -45,7 +45,7 @@
.args(&[
arg!(--blkdevice <FILE> "the block device backing the encrypted storage")
.required(true),
- arg!(--key <KEY> "key (in hex) equivalent to 64 bytes)").required(true),
+ arg!(--key <KEY> "key (in hex) equivalent to 32 bytes)").required(true),
arg!(--mountpoint <MOUNTPOINT> "mount point for the storage").required(true),
])
.get_matches();
@@ -87,12 +87,12 @@
fn enable_crypt(data_device: &Path, key: &str, name: &str) -> Result<PathBuf> {
let dev_size = util::blkgetsize64(data_device)?;
let key = hex::decode(key).context("Unable to decode hex key")?;
- ensure!(key.len() == 64, "We need 64 bytes' key for aes-xts cipher for block encryption");
+ ensure!(key.len() == 32, "We need 32 bytes' key for aes-hctr2 cipher for block encryption");
// Create the dm-crypt spec
let target = dm::crypt::DmCryptTargetBuilder::default()
.data_device(data_device, dev_size)
- .cipher(CipherType::AES256XTS) // TODO(b/259253336) Move to HCTR2 based encryption.
+ .cipher(CipherType::AES256HCTR2)
.key(&key)
.build()
.context("Couldn't build the DMCrypt target")?;
diff --git a/libs/devicemapper/src/crypt.rs b/libs/devicemapper/src/crypt.rs
index 9b715a5..75105ce 100644
--- a/libs/devicemapper/src/crypt.rs
+++ b/libs/devicemapper/src/crypt.rs
@@ -33,9 +33,21 @@
/// Supported ciphers
pub enum CipherType {
- // TODO(b/253394457) Include ciphers with authenticated modes as well
+ // AES-256-HCTR2 takes a 32-byte key
+ AES256HCTR2,
+ // XTS requires key of twice the length of the underlying block cipher i.e., 64B for AES256
AES256XTS,
}
+impl CipherType {
+ fn get_kernel_crypto_name(&self) -> &str {
+ match *self {
+ // We use "plain64" as the IV/nonce generation algorithm -
+ // which basically is the sector number.
+ CipherType::AES256HCTR2 => "aes-hctr2-plain64",
+ CipherType::AES256XTS => "aes-xts-plain64",
+ }
+ }
+}
pub struct DmCryptTarget(Box<[u8]>);
@@ -59,7 +71,7 @@
impl<'a> Default for DmCryptTargetBuilder<'a> {
fn default() -> Self {
DmCryptTargetBuilder {
- cipher: CipherType::AES256XTS,
+ cipher: CipherType::AES256HCTR2,
key: None,
iv_offset: 0,
device_path: None,
@@ -121,7 +133,7 @@
// <offset> [<#opt_params> <opt_params>]
let mut body = String::new();
use std::fmt::Write;
- write!(&mut body, "{} ", get_kernel_crypto_name(&self.cipher))?;
+ write!(&mut body, "{} ", self.cipher.get_kernel_crypto_name())?;
write!(&mut body, "{} ", key)?;
write!(&mut body, "{} ", self.iv_offset)?;
write!(&mut body, "{} ", device_path)?;
@@ -145,9 +157,3 @@
Ok(DmCryptTarget(buf.into_boxed_slice()))
}
}
-
-fn get_kernel_crypto_name(cipher: &CipherType) -> &str {
- match cipher {
- CipherType::AES256XTS => "aes-xts-plain64",
- }
-}
diff --git a/microdroid_manager/src/main.rs b/microdroid_manager/src/main.rs
index a706dbe..341105c 100644
--- a/microdroid_manager/src/main.rs
+++ b/microdroid_manager/src/main.rs
@@ -85,7 +85,7 @@
const ENCRYPTEDSTORE_BACKING_DEVICE: &str = "/dev/block/by-name/encryptedstore";
const ENCRYPTEDSTORE_BIN: &str = "/system/bin/encryptedstore";
const ENCRYPTEDSTORE_KEY_IDENTIFIER: &str = "encryptedstore_key";
-const ENCRYPTEDSTORE_KEYSIZE: u32 = 64;
+const ENCRYPTEDSTORE_KEYSIZE: u32 = 32;
const ENCRYPTEDSTORE_MOUNTPOINT: &str = "/mnt/encryptedstore";
#[derive(thiserror::Error, Debug)]