Microdroid: Map a dm-crypt dev on (virtio-blk)disk

1. microdroid_manager, on seeing a (named) block device dedicated for
   storage, will run encryptedstore binary.
2. The key derived for the encryption will be derived from the dice
   using the CDIs of *payload* as hashes.
3. encryptedstore binary will create the dm-crypt device using the
   libdm_rust library.

Note: The salt used for the key is deterministic but I randomly got from
/dev/urandom. This ensures the key & payload secret are different.

Test: Run bin/vm run-app using --storage & --storage-size flag
Test: Write into the crypt device & check persistence by running another
VM with same instance image.
Bug: 241541860

Change-Id: I11d00343a040935dd90a232fe7c5ab4e06b6d145
diff --git a/encryptedstore/src/main.rs b/encryptedstore/src/main.rs
new file mode 100644
index 0000000..9a701ed
--- /dev/null
+++ b/encryptedstore/src/main.rs
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! `encryptedstore` is a program that (as the name indicates) provides encrypted storage
+//! solution in a VM. This is based on dm-crypt & requires the (64 bytes') key & the backing device.
+//! It uses dm_rust lib.
+
+use anyhow::{ensure, Context, Result};
+use clap::{arg, App};
+use dm::{crypt::CipherType, util};
+use log::info;
+use std::os::unix::fs::FileTypeExt;
+use std::path::Path;
+
+fn main() -> Result<()> {
+    android_logger::init_once(
+        android_logger::Config::default()
+            .with_tag("encryptedstore")
+            .with_min_level(log::Level::Info),
+    );
+    info!("Starting encryptedstore binary");
+
+    let matches = App::new("encryptedstore")
+        .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),
+        ])
+        .get_matches();
+
+    let blkdevice = Path::new(matches.value_of("blkdevice").unwrap());
+    let key = matches.value_of("key").unwrap();
+    ensure!(
+        std::fs::metadata(&blkdevice)
+            .context(format!("Failed to get metadata of {:?}", blkdevice))?
+            .file_type()
+            .is_block_device(),
+        "The path:{:?} is not of a block device",
+        blkdevice
+    );
+
+    enable_crypt(blkdevice, key, "cryptdev")?;
+    Ok(())
+}
+
+fn enable_crypt(data_device: &Path, key: &str, name: &str) -> Result<()> {
+    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");
+
+    // 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.
+        .key(&key)
+        .build()
+        .context("Couldn't build the DMCrypt target")?;
+    let dm = dm::DeviceMapper::new()?;
+    dm.create_crypt_device(name, &target).context("Failed to create dm-crypt device")?;
+
+    Ok(())
+}