Merge "Allow CompOS to use DICE from C++"
diff --git a/keystore2/aidl/android/security/compat/IKeystoreCompatService.aidl b/keystore2/aidl/android/security/compat/IKeystoreCompatService.aidl
index 50bfa19..8e347f0 100644
--- a/keystore2/aidl/android/security/compat/IKeystoreCompatService.aidl
+++ b/keystore2/aidl/android/security/compat/IKeystoreCompatService.aidl
@@ -29,8 +29,17 @@
  */
 interface IKeystoreCompatService {
     /**
-     * Return an implementation of IKeyMintDevice, that it implemented by Keystore 2.0 itself
-     * by means of Keymaster 4.1 or lower.
+     * Return an implementation of IKeyMintDevice, that it implemented by Keystore 2.0 itself.
+     * The underlying implementation depends on the requested securityLevel:
+     * - TRUSTED_ENVIRONMENT or STRONGBOX: implementation is by means of a hardware-backed
+     *   Keymaster 4.x instance. In this case, the returned device supports version 1 of
+     *   the IKeyMintDevice interface, with some small omissions:
+     *     - KeyPurpose::ATTEST_KEY is not supported (b/216437537)
+     *     - Specification of the MGF1 digest for RSA-OAEP is not supported (b/216436980)
+     *     - Specification of CERTIFICATE_{SUBJECT,SERIAL} is not supported for keys attested
+     *       by hardware (b/216468666).
+     * - SOFTWARE: implementation is entirely software based.  In this case, the returned device
+     *   supports the current version of the IKeyMintDevice interface.
      */
     IKeyMintDevice getKeyMintDevice (SecurityLevel securityLevel);
 
diff --git a/keystore2/src/authorization.rs b/keystore2/src/authorization.rs
index 81790af..8265dd0 100644
--- a/keystore2/src/authorization.rs
+++ b/keystore2/src/authorization.rs
@@ -16,7 +16,7 @@
 
 use crate::error::Error as KeystoreError;
 use crate::error::anyhow_error_to_cstring;
-use crate::globals::{ENFORCEMENTS, SUPER_KEY, DB, LEGACY_MIGRATOR};
+use crate::globals::{ENFORCEMENTS, SUPER_KEY, DB, LEGACY_IMPORTER};
 use crate::permission::KeystorePerm;
 use crate::super_key::UserState;
 use crate::utils::{check_keystore_permission, watchdog as wd};
@@ -170,7 +170,7 @@
                     .with(|db| {
                         skm.unlock_and_get_user_state(
                             &mut db.borrow_mut(),
-                            &LEGACY_MIGRATOR,
+                            &LEGACY_IMPORTER,
                             user_id as u32,
                             &password,
                         )
diff --git a/keystore2/src/crypto/Android.bp b/keystore2/src/crypto/Android.bp
index 76c02c5..c3f6f3c 100644
--- a/keystore2/src/crypto/Android.bp
+++ b/keystore2/src/crypto/Android.bp
@@ -62,6 +62,7 @@
     shared_libs: ["libcrypto"],
     bindgen_flags: [
         "--size_t-is-usize",
+        "--allowlist-function", "hmacSha256",
         "--allowlist-function", "randomBytes",
         "--allowlist-function", "AES_gcm_encrypt",
         "--allowlist-function", "AES_gcm_decrypt",
diff --git a/keystore2/src/crypto/crypto.cpp b/keystore2/src/crypto/crypto.cpp
index 5d360a1..34a9a40 100644
--- a/keystore2/src/crypto/crypto.cpp
+++ b/keystore2/src/crypto/crypto.cpp
@@ -25,6 +25,7 @@
 #include <openssl/ecdh.h>
 #include <openssl/evp.h>
 #include <openssl/hkdf.h>
+#include <openssl/hmac.h>
 #include <openssl/rand.h>
 #include <openssl/x509.h>
 
@@ -66,6 +67,14 @@
     return cipher;
 }
 
+bool hmacSha256(const uint8_t* key, size_t key_size, const uint8_t* msg, size_t msg_size,
+                uint8_t* out, size_t out_size) {
+    const EVP_MD* digest = EVP_sha256();
+    unsigned int actual_out_size = out_size;
+    uint8_t* p = HMAC(digest, key, key_size, msg, msg_size, out, &actual_out_size);
+    return (p != nullptr);
+}
+
 bool randomBytes(uint8_t* out, size_t len) {
     return RAND_bytes(out, len);
 }
diff --git a/keystore2/src/crypto/crypto.hpp b/keystore2/src/crypto/crypto.hpp
index f841eb3..d66532f 100644
--- a/keystore2/src/crypto/crypto.hpp
+++ b/keystore2/src/crypto/crypto.hpp
@@ -22,6 +22,8 @@
 #include <stddef.h>
 
 extern "C" {
+  bool hmacSha256(const uint8_t* key, size_t key_size, const uint8_t* msg, size_t msg_size,
+                  uint8_t* out, size_t out_size);
   bool randomBytes(uint8_t* out, size_t len);
   bool AES_gcm_encrypt(const uint8_t* in, uint8_t* out, size_t len,
                        const uint8_t* key, size_t key_size, const uint8_t* iv, uint8_t* tag);
diff --git a/keystore2/src/crypto/error.rs b/keystore2/src/crypto/error.rs
index c6476f9..48a2d4c 100644
--- a/keystore2/src/crypto/error.rs
+++ b/keystore2/src/crypto/error.rs
@@ -95,6 +95,10 @@
     #[error("Failed to extract certificate subject.")]
     ExtractSubjectFailed,
 
+    /// This is returned if the C implementation of hmacSha256 failed.
+    #[error("Failed to calculate HMAC-SHA256.")]
+    HmacSha256Failed,
+
     /// Zvec error.
     #[error(transparent)]
     ZVec(#[from] zvec::Error),
diff --git a/keystore2/src/crypto/lib.rs b/keystore2/src/crypto/lib.rs
index 92da965..14bdf04 100644
--- a/keystore2/src/crypto/lib.rs
+++ b/keystore2/src/crypto/lib.rs
@@ -19,8 +19,8 @@
 pub mod zvec;
 pub use error::Error;
 use keystore2_crypto_bindgen::{
-    extractSubjectFromCertificate, generateKeyFromPassword, randomBytes, AES_gcm_decrypt,
-    AES_gcm_encrypt, ECDHComputeKey, ECKEYGenerateKey, ECKEYMarshalPrivateKey,
+    extractSubjectFromCertificate, generateKeyFromPassword, hmacSha256, randomBytes,
+    AES_gcm_decrypt, AES_gcm_encrypt, ECDHComputeKey, ECKEYGenerateKey, ECKEYMarshalPrivateKey,
     ECKEYParsePrivateKey, ECPOINTOct2Point, ECPOINTPoint2Oct, EC_KEY_free, EC_KEY_get0_public_key,
     EC_POINT_free, HKDFExpand, HKDFExtract, EC_KEY, EC_MAX_BYTES, EC_POINT, EVP_MAX_MD_SIZE,
 };
@@ -39,6 +39,8 @@
 pub const AES_128_KEY_LENGTH: usize = 16;
 /// Length of the expected salt for key from password generation.
 pub const SALT_LENGTH: usize = 16;
+/// Length of an HMAC-SHA256 tag in bytes.
+pub const HMAC_SHA256_LEN: usize = 32;
 
 /// Older versions of keystore produced IVs with four extra
 /// ignored zero bytes at the end; recognise and trim those.
@@ -72,6 +74,21 @@
     }
 }
 
+/// Perform HMAC-SHA256.
+pub fn hmac_sha256(key: &[u8], msg: &[u8]) -> Result<Vec<u8>, Error> {
+    let mut tag = vec![0; HMAC_SHA256_LEN];
+    // Safety: The first two pairs of arguments must point to const buffers with
+    // size given by the second arg of the pair.  The final pair of arguments
+    // must point to an output buffer with size given by the second arg of the
+    // pair.
+    match unsafe {
+        hmacSha256(key.as_ptr(), key.len(), msg.as_ptr(), msg.len(), tag.as_mut_ptr(), tag.len())
+    } {
+        true => Ok(tag),
+        false => Err(Error::HmacSha256Failed),
+    }
+}
+
 /// Uses AES GCM to decipher a message given an initialization vector, aead tag, and key.
 /// This function accepts 128 and 256-bit keys and uses AES128 and AES256 respectively based
 /// on the key length.
@@ -565,4 +582,18 @@
         assert_eq!(left_key, right_key);
         Ok(())
     }
+
+    #[test]
+    fn test_hmac_sha256() {
+        let key = b"This is the key";
+        let msg1 = b"This is a message";
+        let msg2 = b"This is another message";
+        let tag1a = hmac_sha256(key, msg1).unwrap();
+        assert_eq!(tag1a.len(), HMAC_SHA256_LEN);
+        let tag1b = hmac_sha256(key, msg1).unwrap();
+        assert_eq!(tag1a, tag1b);
+        let tag2 = hmac_sha256(key, msg2).unwrap();
+        assert_eq!(tag2.len(), HMAC_SHA256_LEN);
+        assert_ne!(tag1a, tag2);
+    }
 }
diff --git a/keystore2/src/enforcements.rs b/keystore2/src/enforcements.rs
index ade4751..cb6a266 100644
--- a/keystore2/src/enforcements.rs
+++ b/keystore2/src/enforcements.rs
@@ -450,7 +450,7 @@
                         KeyParameterValue::Algorithm(Algorithm::RSA)
                         | KeyParameterValue::Algorithm(Algorithm::EC) => {
                             return Err(Error::Km(Ec::UNSUPPORTED_PURPOSE)).context(
-                                "In authorize_create: public operations on asymmetric keys are not
+                                "In authorize_create: public operations on asymmetric keys are not \
                                  supported.",
                             );
                         }
@@ -566,8 +566,7 @@
         // if both NO_AUTH_REQUIRED and USER_SECURE_ID tags are present, return error
         if !user_secure_ids.is_empty() && no_auth_required {
             return Err(Error::Km(Ec::INVALID_KEY_BLOB)).context(
-                "In authorize_create: key has both NO_AUTH_REQUIRED
-                and USER_SECURE_ID tags.",
+                "In authorize_create: key has both NO_AUTH_REQUIRED and USER_SECURE_ID tags.",
             );
         }
 
@@ -576,8 +575,8 @@
             || (user_auth_type.is_none() && !user_secure_ids.is_empty())
         {
             return Err(Error::Km(Ec::KEY_USER_NOT_AUTHENTICATED)).context(
-                "In authorize_create: Auth required, but either auth type or secure ids
-                are not present.",
+                "In authorize_create: Auth required, but either auth type or secure ids \
+                 are not present.",
             );
         }
 
@@ -587,8 +586,7 @@
             && op_params.iter().any(|kp| kp.tag == Tag::NONCE)
         {
             return Err(Error::Km(Ec::CALLER_NONCE_PROHIBITED)).context(
-                "In authorize_create, NONCE is present,
-                    although CALLER_NONCE is not present",
+                "In authorize_create, NONCE is present, although CALLER_NONCE is not present",
             );
         }
 
diff --git a/keystore2/src/globals.rs b/keystore2/src/globals.rs
index 2819314..14b3601 100644
--- a/keystore2/src/globals.rs
+++ b/keystore2/src/globals.rs
@@ -18,7 +18,7 @@
 
 use crate::gc::Gc;
 use crate::legacy_blob::LegacyBlobLoader;
-use crate::legacy_migrator::LegacyMigrator;
+use crate::legacy_importer::LegacyImporter;
 use crate::super_key::SuperKeyManager;
 use crate::utils::watchdog as wd;
 use crate::{async_task::AsyncTask, database::MonotonicRawTime};
@@ -27,6 +27,7 @@
     database::Uuid,
     error::{map_binder_status, map_binder_status_code, Error, ErrorCode},
 };
+use crate::km_compat::{KeyMintV1, BacklevelKeyMintWrapper};
 use crate::{enforcements::Enforcements, error::map_km_error};
 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
     IKeyMintDevice::IKeyMintDevice, IRemotelyProvisionedComponent::IRemotelyProvisionedComponent,
@@ -175,8 +176,8 @@
     pub static ref LEGACY_BLOB_LOADER: Arc<LegacyBlobLoader> = Arc::new(LegacyBlobLoader::new(
         &DB_PATH.read().expect("Could not get the database path for legacy blob loader.")));
     /// Legacy migrator. Atomically migrates legacy blobs to the database.
-    pub static ref LEGACY_MIGRATOR: Arc<LegacyMigrator> =
-        Arc::new(LegacyMigrator::new(Arc::new(Default::default())));
+    pub static ref LEGACY_IMPORTER: Arc<LegacyImporter> =
+        Arc::new(LegacyImporter::new(Arc::new(Default::default())));
     /// Background thread which handles logging via statsd and logd
     pub static ref LOGS_HANDLER: Arc<AsyncTask> = Default::default();
 
@@ -197,14 +198,15 @@
 
 static KEYMINT_SERVICE_NAME: &str = "android.hardware.security.keymint.IKeyMintDevice";
 
-/// Make a new connection to a KeyMint device of the given security level.
-/// If no native KeyMint device can be found this function also brings
-/// up the compatibility service and attempts to connect to the legacy wrapper.
-fn connect_keymint(
+/// Determine the service name for a KeyMint device of the given security level
+/// which implements at least the specified version of the `IKeyMintDevice`
+/// interface.
+fn keymint_service_name_by_version(
     security_level: &SecurityLevel,
-) -> Result<(Strong<dyn IKeyMintDevice>, KeyMintHardwareInfo)> {
+    version: i32,
+) -> Result<Option<(i32, String)>> {
     let keymint_instances =
-        get_aidl_instances("android.hardware.security.keymint", 1, "IKeyMintDevice");
+        get_aidl_instances("android.hardware.security.keymint", version as usize, "IKeyMintDevice");
 
     let service_name = match *security_level {
         SecurityLevel::TRUSTED_ENVIRONMENT => {
@@ -222,12 +224,36 @@
             }
         }
         _ => {
-            return Err(Error::Km(ErrorCode::HARDWARE_TYPE_UNAVAILABLE))
-                .context("In connect_keymint.")
+            return Err(Error::Km(ErrorCode::HARDWARE_TYPE_UNAVAILABLE)).context(format!(
+                "In keymint_service_name_by_version: Trying to find keymint V{} for security level: {:?}",
+                version, security_level
+            ));
         }
     };
 
-    let (keymint, hal_version) = if let Some(service_name) = service_name {
+    Ok(service_name.map(|service_name| (version, service_name)))
+}
+
+/// Make a new connection to a KeyMint device of the given security level.
+/// If no native KeyMint device can be found this function also brings
+/// up the compatibility service and attempts to connect to the legacy wrapper.
+fn connect_keymint(
+    security_level: &SecurityLevel,
+) -> Result<(Strong<dyn IKeyMintDevice>, KeyMintHardwareInfo)> {
+    // Count down from the current interface version back to one in order to
+    // also find out the interface version -- an implementation of V2 will show
+    // up in the list of V1-capable devices, but not vice-versa.
+    let service_name = keymint_service_name_by_version(security_level, 2)
+        .and_then(|sl| {
+            if sl.is_none() {
+                keymint_service_name_by_version(security_level, 1)
+            } else {
+                Ok(sl)
+            }
+        })
+        .context("In connect_keymint.")?;
+
+    let (keymint, hal_version) = if let Some((version, service_name)) = service_name {
         let km: Strong<dyn IKeyMintDevice> =
             map_binder_status_code(binder::get_interface(&service_name))
                 .context("In connect_keymint: Trying to connect to genuine KeyMint service.")?;
@@ -235,11 +261,7 @@
         // - V1 is 100
         // - V2 is 200
         // etc.
-        let hal_version = km
-            .getInterfaceVersion()
-            .map(|v| v * 100i32)
-            .context("In connect_keymint: Trying to determine KeyMint AIDL version")?;
-        (km, Some(hal_version))
+        (km, Some(version * 100))
     } else {
         // This is a no-op if it was called before.
         keystore2_km_compat::add_keymint_device_service();
@@ -260,6 +282,48 @@
         )
     };
 
+    // If the KeyMint device is back-level, use a wrapper that intercepts and
+    // emulates things that are not supported by the hardware.
+    let keymint = match hal_version {
+        Some(200) => {
+            // Current KeyMint version: use as-is.
+            log::info!(
+                "KeyMint device is current version ({:?}) for security level: {:?}",
+                hal_version,
+                security_level
+            );
+            keymint
+        }
+        Some(100) => {
+            // KeyMint v1: perform software emulation.
+            log::info!(
+                "Add emulation wrapper around {:?} device for security level: {:?}",
+                hal_version,
+                security_level
+            );
+            BacklevelKeyMintWrapper::wrap(KeyMintV1::new(*security_level), keymint)
+                .context("In connect_keymint: Trying to create V1 compatibility wrapper.")?
+        }
+        None => {
+            // Compatibility wrapper around a KeyMaster device: this roughly
+            // behaves like KeyMint V1 (e.g. it includes AGREE_KEY support,
+            // albeit in software.)
+            log::info!(
+                "Add emulation wrapper around Keymaster device for security level: {:?}",
+                security_level
+            );
+            BacklevelKeyMintWrapper::wrap(KeyMintV1::new(*security_level), keymint).context(
+                "In connect_keymint: Trying to create km_compat V1 compatibility wrapper .",
+            )?
+        }
+        _ => {
+            return Err(Error::Km(ErrorCode::HARDWARE_TYPE_UNAVAILABLE)).context(format!(
+                "In connect_keymint: unexpected hal_version {:?} for security level: {:?}",
+                hal_version, security_level
+            ))
+        }
+    };
+
     let wp = wd::watch_millis("In connect_keymint: calling getHardwareInfo()", 500);
     let mut hw_info = map_km_error(keymint.getHardwareInfo())
         .context("In connect_keymint: Failed to get hardware info.")?;
diff --git a/keystore2/src/km_compat.rs b/keystore2/src/km_compat.rs
new file mode 100644
index 0000000..84855df
--- /dev/null
+++ b/keystore2/src/km_compat.rs
@@ -0,0 +1,579 @@
+// Copyright 2020, 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.
+
+//! Provide a wrapper around a KeyMint device that allows up-level features to
+//! be emulated on back-level devices.
+
+use crate::error::{map_binder_status, map_binder_status_code, map_or_log_err, Error, ErrorCode};
+use android_hardware_security_keymint::binder::{BinderFeatures, StatusCode, Strong};
+use android_hardware_security_secureclock::aidl::android::hardware::security::secureclock::TimeStampToken::TimeStampToken;
+use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
+    AttestationKey::AttestationKey, BeginResult::BeginResult, EcCurve::EcCurve,
+    HardwareAuthToken::HardwareAuthToken, IKeyMintDevice::BnKeyMintDevice,
+    IKeyMintDevice::IKeyMintDevice, KeyCharacteristics::KeyCharacteristics,
+    KeyCreationResult::KeyCreationResult, KeyFormat::KeyFormat,
+    KeyMintHardwareInfo::KeyMintHardwareInfo, KeyParameter::KeyParameter,
+    KeyParameterValue::KeyParameterValue, KeyPurpose::KeyPurpose, SecurityLevel::SecurityLevel,
+    Tag::Tag,
+};
+use android_security_compat::aidl::android::security::compat::IKeystoreCompatService::IKeystoreCompatService;
+use anyhow::Context;
+use keystore2_crypto::{hmac_sha256, HMAC_SHA256_LEN};
+
+/// Key data associated with key generation/import.
+#[derive(Debug, PartialEq, Eq)]
+pub enum KeyImportData<'a> {
+    None,
+    Pkcs8(&'a [u8]),
+    Raw(&'a [u8]),
+}
+
+impl<'a> KeyImportData<'a> {
+    /// Translate import parameters into a `KeyImportData` instance.
+    fn new(key_format: KeyFormat, key_data: &'a [u8]) -> binder::Result<Self> {
+        match key_format {
+            KeyFormat::PKCS8 => Ok(KeyImportData::Pkcs8(key_data)),
+            KeyFormat::RAW => Ok(KeyImportData::Raw(key_data)),
+            _ => Err(binder::Status::new_service_specific_error(
+                ErrorCode::UNSUPPORTED_KEY_FORMAT.0,
+                None,
+            )),
+        }
+    }
+}
+
+/// A key blob that may be software-emulated or may be directly produced by an
+/// underlying device.  In either variant the inner data is the keyblob itself,
+/// as seen by the relevant device.
+#[derive(Debug, PartialEq, Eq)]
+pub enum KeyBlob<'a> {
+    Raw(&'a [u8]),
+    Wrapped(&'a [u8]),
+}
+
+/// Trait for detecting that software emulation of a current-version KeyMint
+/// feature is required for a back-level KeyMint implementation.
+pub trait EmulationDetector: Send + Sync {
+    /// Indicate whether software emulation is required for key
+    /// generation/import using the provided parameters.
+    fn emulation_required(&self, params: &[KeyParameter], import_data: &KeyImportData) -> bool;
+}
+
+const KEYBLOB_PREFIX: &[u8] = b"SoftKeyMintForV1Blob";
+const KEYBLOB_HMAC_KEY: &[u8] = b"SoftKeyMintForV1HMACKey";
+
+/// Wrap the provided keyblob:
+/// - prefix it with an identifier specific to this wrapper
+/// - suffix it with an HMAC tag, using the [`KEYBLOB_HMAC_KEY`] and `keyblob`.
+fn wrap_keyblob(keyblob: &[u8]) -> anyhow::Result<Vec<u8>> {
+    let mut result = Vec::with_capacity(KEYBLOB_PREFIX.len() + keyblob.len() + HMAC_SHA256_LEN);
+    result.extend_from_slice(KEYBLOB_PREFIX);
+    result.extend_from_slice(keyblob);
+    let tag = hmac_sha256(KEYBLOB_HMAC_KEY, keyblob)
+        .context("In wrap_keyblob, failed to calculate HMAC-SHA256")?;
+    result.extend_from_slice(&tag);
+    Ok(result)
+}
+
+/// Return an unwrapped version of the provided `keyblob`, which may or may
+/// not be associated with the software emulation.
+fn unwrap_keyblob(keyblob: &[u8]) -> KeyBlob {
+    if !keyblob.starts_with(KEYBLOB_PREFIX) {
+        return KeyBlob::Raw(keyblob);
+    }
+    let without_prefix = &keyblob[KEYBLOB_PREFIX.len()..];
+    if without_prefix.len() < HMAC_SHA256_LEN {
+        return KeyBlob::Raw(keyblob);
+    }
+    let (inner_keyblob, want_tag) = without_prefix.split_at(without_prefix.len() - HMAC_SHA256_LEN);
+    let got_tag = match hmac_sha256(KEYBLOB_HMAC_KEY, inner_keyblob) {
+        Ok(tag) => tag,
+        Err(e) => {
+            log::error!("Error calculating HMAC-SHA256 for keyblob unwrap: {:?}", e);
+            return KeyBlob::Raw(keyblob);
+        }
+    };
+    // Comparison does not need to be constant-time here.
+    if want_tag == got_tag {
+        KeyBlob::Wrapped(inner_keyblob)
+    } else {
+        KeyBlob::Raw(keyblob)
+    }
+}
+
+/// Wrapper around a real device that implements a back-level version of
+/// `IKeyMintDevice`
+pub struct BacklevelKeyMintWrapper<T: EmulationDetector> {
+    /// The `real` device implements some earlier version of `IKeyMintDevice`
+    real: Strong<dyn IKeyMintDevice>,
+    /// The `soft`ware device implements the current version of `IKeyMintDevice`
+    soft: Strong<dyn IKeyMintDevice>,
+    /// Detector for operations that are not supported by the earlier version of
+    /// `IKeyMintDevice`. Or possibly a large flightless bird, who can tell.
+    emu: T,
+}
+
+impl<T> BacklevelKeyMintWrapper<T>
+where
+    T: EmulationDetector + 'static,
+{
+    /// Create a wrapper around the provided back-level KeyMint device, so that
+    /// software emulation can be performed for any current-version features not
+    /// provided by the real device.
+    pub fn wrap(
+        emu: T,
+        real: Strong<dyn IKeyMintDevice>,
+    ) -> anyhow::Result<Strong<dyn IKeyMintDevice>> {
+        // This is a no-op if it was called before.
+        keystore2_km_compat::add_keymint_device_service();
+
+        let keystore_compat_service: Strong<dyn IKeystoreCompatService> = map_binder_status_code(
+            binder::get_interface("android.security.compat"),
+        )
+        .context("In BacklevelKeyMintWrapper::wrap: Trying to connect to compat service.")?;
+        let soft =
+            map_binder_status(keystore_compat_service.getKeyMintDevice(SecurityLevel::SOFTWARE))
+                .map_err(|e| match e {
+                    Error::BinderTransaction(StatusCode::NAME_NOT_FOUND) => {
+                        Error::Km(ErrorCode::HARDWARE_TYPE_UNAVAILABLE)
+                    }
+                    e => e,
+                })
+                .context("In BacklevelKeyMintWrapper::wrap: Trying to get software device.")?;
+
+        Ok(BnKeyMintDevice::new_binder(
+            Self { real, soft, emu },
+            BinderFeatures { set_requesting_sid: true, ..BinderFeatures::default() },
+        ))
+    }
+}
+
+impl<T> binder::Interface for BacklevelKeyMintWrapper<T> where T: EmulationDetector {}
+
+impl<T> IKeyMintDevice for BacklevelKeyMintWrapper<T>
+where
+    T: EmulationDetector + 'static,
+{
+    // For methods that don't involve keyblobs, forward to either the real
+    // device, or to both real & emulated devices.
+    fn getHardwareInfo(&self) -> binder::Result<KeyMintHardwareInfo> {
+        self.real.getHardwareInfo()
+    }
+    fn addRngEntropy(&self, data: &[u8]) -> binder::Result<()> {
+        self.real.addRngEntropy(data)
+    }
+    fn deleteAllKeys(&self) -> binder::Result<()> {
+        self.real.deleteAllKeys()
+    }
+    fn destroyAttestationIds(&self) -> binder::Result<()> {
+        self.real.destroyAttestationIds()
+    }
+    fn deviceLocked(
+        &self,
+        password_only: bool,
+        timestamp_token: Option<&TimeStampToken>,
+    ) -> binder::Result<()> {
+        // Propagate to both real and software devices, but only pay attention
+        // to the result from the real device.
+        let _ = self.soft.deviceLocked(password_only, timestamp_token);
+        self.real.deviceLocked(password_only, timestamp_token)
+    }
+    fn earlyBootEnded(&self) -> binder::Result<()> {
+        // Propagate to both real and software devices, but only pay attention
+        // to the result from the real device.
+        let _ = self.soft.earlyBootEnded();
+        self.real.earlyBootEnded()
+    }
+
+    // For methods that emit keyblobs, check whether the underlying real device
+    // supports the relevant parameters, and forward to the appropriate device.
+    // If the emulated device is used, ensure that the created keyblob gets
+    // prefixed so we can recognize it in future.
+    fn generateKey(
+        &self,
+        key_params: &[KeyParameter],
+        attestation_key: Option<&AttestationKey>,
+    ) -> binder::Result<KeyCreationResult> {
+        if self.emu.emulation_required(key_params, &KeyImportData::None) {
+            let mut result = self.soft.generateKey(key_params, attestation_key)?;
+            result.keyBlob = map_or_log_err(wrap_keyblob(&result.keyBlob), Ok)?;
+            Ok(result)
+        } else {
+            self.real.generateKey(key_params, attestation_key)
+        }
+    }
+    fn importKey(
+        &self,
+        key_params: &[KeyParameter],
+        key_format: KeyFormat,
+        key_data: &[u8],
+        attestation_key: Option<&AttestationKey>,
+    ) -> binder::Result<KeyCreationResult> {
+        if self.emu.emulation_required(key_params, &KeyImportData::new(key_format, key_data)?) {
+            let mut result =
+                self.soft.importKey(key_params, key_format, key_data, attestation_key)?;
+            result.keyBlob = map_or_log_err(wrap_keyblob(&result.keyBlob), Ok)?;
+            Ok(result)
+        } else {
+            self.real.importKey(key_params, key_format, key_data, attestation_key)
+        }
+    }
+    fn importWrappedKey(
+        &self,
+        wrapped_key_data: &[u8],
+        wrapping_key_blob: &[u8],
+        masking_key: &[u8],
+        unwrapping_params: &[KeyParameter],
+        password_sid: i64,
+        biometric_sid: i64,
+    ) -> binder::Result<KeyCreationResult> {
+        // A wrapped key cannot be software-emulated, as the wrapping key is
+        // likely hardware-bound.
+        self.real.importWrappedKey(
+            wrapped_key_data,
+            wrapping_key_blob,
+            masking_key,
+            unwrapping_params,
+            password_sid,
+            biometric_sid,
+        )
+    }
+
+    // For methods that use keyblobs, determine which device to forward the
+    // operation to based on whether the keyblob is appropriately prefixed.
+    fn upgradeKey(
+        &self,
+        keyblob_to_upgrade: &[u8],
+        upgrade_params: &[KeyParameter],
+    ) -> binder::Result<Vec<u8>> {
+        match unwrap_keyblob(keyblob_to_upgrade) {
+            KeyBlob::Raw(keyblob) => self.real.upgradeKey(keyblob, upgrade_params),
+            KeyBlob::Wrapped(keyblob) => {
+                // Re-wrap the upgraded keyblob.
+                let upgraded_keyblob = self.soft.upgradeKey(keyblob, upgrade_params)?;
+                map_or_log_err(wrap_keyblob(&upgraded_keyblob), Ok)
+            }
+        }
+    }
+    fn deleteKey(&self, keyblob: &[u8]) -> binder::Result<()> {
+        match unwrap_keyblob(keyblob) {
+            KeyBlob::Raw(keyblob) => self.real.deleteKey(keyblob),
+            KeyBlob::Wrapped(keyblob) => {
+                // Forward to the software implementation for completeness, but
+                // this should always be a no-op.
+                self.soft.deleteKey(keyblob)
+            }
+        }
+    }
+    fn begin(
+        &self,
+        purpose: KeyPurpose,
+        keyblob: &[u8],
+        params: &[KeyParameter],
+        auth_token: Option<&HardwareAuthToken>,
+    ) -> binder::Result<BeginResult> {
+        match unwrap_keyblob(keyblob) {
+            KeyBlob::Raw(keyblob) => self.real.begin(purpose, keyblob, params, auth_token),
+            KeyBlob::Wrapped(keyblob) => self.soft.begin(purpose, keyblob, params, auth_token),
+        }
+    }
+    fn getKeyCharacteristics(
+        &self,
+        keyblob: &[u8],
+        app_id: &[u8],
+        app_data: &[u8],
+    ) -> binder::Result<Vec<KeyCharacteristics>> {
+        match unwrap_keyblob(keyblob) {
+            KeyBlob::Raw(keyblob) => self.real.getKeyCharacteristics(keyblob, app_id, app_data),
+            KeyBlob::Wrapped(keyblob) => self.soft.getKeyCharacteristics(keyblob, app_id, app_data),
+        }
+    }
+    fn convertStorageKeyToEphemeral(&self, storage_keyblob: &[u8]) -> binder::Result<Vec<u8>> {
+        // Storage keys should never be associated with a software emulated device.
+        self.real.convertStorageKeyToEphemeral(storage_keyblob)
+    }
+}
+
+/// Detector for current features that are not implemented by KeyMint V1.
+#[derive(Debug)]
+pub struct KeyMintV1 {
+    sec_level: SecurityLevel,
+}
+
+impl KeyMintV1 {
+    pub fn new(sec_level: SecurityLevel) -> Self {
+        Self { sec_level }
+    }
+}
+
+impl EmulationDetector for KeyMintV1 {
+    fn emulation_required(&self, params: &[KeyParameter], _import_data: &KeyImportData) -> bool {
+        // No current difference from KeyMint v1 for STRONGBOX (it doesn't
+        // support curve 25519).
+        if self.sec_level == SecurityLevel::STRONGBOX {
+            return false;
+        }
+
+        // KeyMint V1 does not support the use of curve 25519, so hunt for that
+        // in the parameters.
+        if params.iter().any(|p| {
+            p.tag == Tag::EC_CURVE && p.value == KeyParameterValue::EcCurve(EcCurve::CURVE_25519)
+        }) {
+            return true;
+        }
+        // In theory, if the `import_data` is `KeyImportData::Pkcs8` we could
+        // check the imported keymaterial for the Ed25519 / X25519 OIDs in the
+        // PKCS8 keydata, and use that to decide to route to software. However,
+        // the KeyMint spec doesn't require that so don't attempt to parse the
+        // key material here.
+        false
+    }
+}
+
+/// Detector for current features that are not implemented by KeyMaster, via the
+/// km_compat wrapper.
+#[derive(Debug)]
+pub struct Keymaster {
+    v1: KeyMintV1,
+}
+
+/// TODO(b/216434270): This could be used this to replace the emulation routing
+/// in the km_compat C++ code, and allow support for imported ECDH keys along
+/// the way. Would need to figure out what would happen to existing emulated
+/// keys though.
+#[allow(dead_code)]
+impl Keymaster {
+    pub fn new(sec_level: SecurityLevel) -> Self {
+        Self { v1: KeyMintV1::new(sec_level) }
+    }
+}
+
+impl EmulationDetector for Keymaster {
+    fn emulation_required(&self, params: &[KeyParameter], import_data: &KeyImportData) -> bool {
+        // The km_compat wrapper on top of Keymaster emulates the KeyMint V1
+        // interface, so any feature from > v1 needs to be emulated.
+        if self.v1.emulation_required(params, import_data) {
+            return true;
+        }
+
+        // Keymaster does not support ECDH (KeyPurpose::AGREE_KEY), so hunt for
+        // that in the parameters.
+        if params.iter().any(|p| {
+            p.tag == Tag::PURPOSE && p.value == KeyParameterValue::KeyPurpose(KeyPurpose::AGREE_KEY)
+        }) {
+            return true;
+        }
+        false
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_key_import_data() {
+        let data = vec![1, 2, 3];
+        assert_eq!(KeyImportData::new(KeyFormat::PKCS8, &data), Ok(KeyImportData::Pkcs8(&data)));
+        assert_eq!(KeyImportData::new(KeyFormat::RAW, &data), Ok(KeyImportData::Raw(&data)));
+        assert!(KeyImportData::new(KeyFormat::X509, &data).is_err());
+    }
+
+    #[test]
+    fn test_wrap_keyblob() {
+        let keyblob = vec![1, 2, 3];
+        let wrapped = wrap_keyblob(&keyblob).unwrap();
+        assert_eq!(&wrapped[..KEYBLOB_PREFIX.len()], KEYBLOB_PREFIX);
+        assert_eq!(&wrapped[KEYBLOB_PREFIX.len()..KEYBLOB_PREFIX.len() + keyblob.len()], &keyblob);
+        assert_eq!(unwrap_keyblob(&keyblob), KeyBlob::Raw(&keyblob));
+        assert_eq!(unwrap_keyblob(&wrapped), KeyBlob::Wrapped(&keyblob));
+
+        let mut corrupt_prefix = wrapped.clone();
+        corrupt_prefix[0] ^= 0x01;
+        assert_eq!(unwrap_keyblob(&corrupt_prefix), KeyBlob::Raw(&corrupt_prefix));
+
+        let mut corrupt_suffix = wrapped.clone();
+        corrupt_suffix[wrapped.len() - 1] ^= 0x01;
+        assert_eq!(unwrap_keyblob(&corrupt_suffix), KeyBlob::Raw(&corrupt_suffix));
+
+        let too_short = &wrapped[..wrapped.len() - 4];
+        assert_eq!(unwrap_keyblob(too_short), KeyBlob::Raw(too_short));
+    }
+
+    #[test]
+    fn test_keymintv1_emulation_required() {
+        let tests = vec![
+            (SecurityLevel::TRUSTED_ENVIRONMENT, vec![], false),
+            (
+                SecurityLevel::TRUSTED_ENVIRONMENT,
+                vec![
+                    KeyParameter {
+                        tag: Tag::PURPOSE,
+                        value: KeyParameterValue::KeyPurpose(KeyPurpose::SIGN),
+                    },
+                    KeyParameter {
+                        tag: Tag::PURPOSE,
+                        value: KeyParameterValue::KeyPurpose(KeyPurpose::VERIFY),
+                    },
+                ],
+                false,
+            ),
+            (
+                SecurityLevel::TRUSTED_ENVIRONMENT,
+                vec![KeyParameter {
+                    tag: Tag::PURPOSE,
+                    value: KeyParameterValue::KeyPurpose(KeyPurpose::AGREE_KEY),
+                }],
+                false,
+            ),
+            (
+                SecurityLevel::TRUSTED_ENVIRONMENT,
+                vec![
+                    KeyParameter {
+                        tag: Tag::PURPOSE,
+                        value: KeyParameterValue::KeyPurpose(KeyPurpose::AGREE_KEY),
+                    },
+                    KeyParameter {
+                        tag: Tag::EC_CURVE,
+                        value: KeyParameterValue::EcCurve(EcCurve::P_256),
+                    },
+                ],
+                false,
+            ),
+            (
+                SecurityLevel::TRUSTED_ENVIRONMENT,
+                vec![
+                    KeyParameter {
+                        tag: Tag::PURPOSE,
+                        value: KeyParameterValue::KeyPurpose(KeyPurpose::AGREE_KEY),
+                    },
+                    KeyParameter {
+                        tag: Tag::EC_CURVE,
+                        value: KeyParameterValue::EcCurve(EcCurve::CURVE_25519),
+                    },
+                ],
+                true,
+            ),
+            (
+                SecurityLevel::STRONGBOX,
+                vec![
+                    KeyParameter {
+                        tag: Tag::PURPOSE,
+                        value: KeyParameterValue::KeyPurpose(KeyPurpose::AGREE_KEY),
+                    },
+                    KeyParameter {
+                        tag: Tag::EC_CURVE,
+                        value: KeyParameterValue::EcCurve(EcCurve::CURVE_25519),
+                    },
+                ],
+                false,
+            ),
+        ];
+        for (sec_level, params, want) in tests {
+            let v1 = KeyMintV1::new(sec_level);
+            let got = v1.emulation_required(&params, &KeyImportData::None);
+            assert_eq!(got, want, "emulation_required({:?})={}, want {}", params, got, want);
+        }
+    }
+
+    #[test]
+    fn test_keymaster_emulation_required() {
+        let tests = vec![
+            (SecurityLevel::TRUSTED_ENVIRONMENT, vec![], false),
+            (
+                SecurityLevel::TRUSTED_ENVIRONMENT,
+                vec![
+                    KeyParameter {
+                        tag: Tag::PURPOSE,
+                        value: KeyParameterValue::KeyPurpose(KeyPurpose::SIGN),
+                    },
+                    KeyParameter {
+                        tag: Tag::PURPOSE,
+                        value: KeyParameterValue::KeyPurpose(KeyPurpose::VERIFY),
+                    },
+                ],
+                false,
+            ),
+            (
+                SecurityLevel::TRUSTED_ENVIRONMENT,
+                vec![KeyParameter {
+                    tag: Tag::PURPOSE,
+                    value: KeyParameterValue::KeyPurpose(KeyPurpose::AGREE_KEY),
+                }],
+                true,
+            ),
+            (
+                SecurityLevel::TRUSTED_ENVIRONMENT,
+                vec![
+                    KeyParameter {
+                        tag: Tag::PURPOSE,
+                        value: KeyParameterValue::KeyPurpose(KeyPurpose::AGREE_KEY),
+                    },
+                    KeyParameter {
+                        tag: Tag::EC_CURVE,
+                        value: KeyParameterValue::EcCurve(EcCurve::P_256),
+                    },
+                ],
+                true,
+            ),
+            (
+                SecurityLevel::TRUSTED_ENVIRONMENT,
+                vec![
+                    KeyParameter {
+                        tag: Tag::PURPOSE,
+                        value: KeyParameterValue::KeyPurpose(KeyPurpose::AGREE_KEY),
+                    },
+                    KeyParameter {
+                        tag: Tag::EC_CURVE,
+                        value: KeyParameterValue::EcCurve(EcCurve::CURVE_25519),
+                    },
+                ],
+                true,
+            ),
+            (
+                SecurityLevel::STRONGBOX,
+                vec![
+                    KeyParameter {
+                        tag: Tag::PURPOSE,
+                        value: KeyParameterValue::KeyPurpose(KeyPurpose::AGREE_KEY),
+                    },
+                    KeyParameter {
+                        tag: Tag::EC_CURVE,
+                        value: KeyParameterValue::EcCurve(EcCurve::CURVE_25519),
+                    },
+                ],
+                true,
+            ),
+            (
+                SecurityLevel::STRONGBOX,
+                vec![
+                    KeyParameter {
+                        tag: Tag::PURPOSE,
+                        value: KeyParameterValue::KeyPurpose(KeyPurpose::SIGN),
+                    },
+                    KeyParameter {
+                        tag: Tag::EC_CURVE,
+                        value: KeyParameterValue::EcCurve(EcCurve::CURVE_25519),
+                    },
+                ],
+                false,
+            ),
+        ];
+        for (sec_level, params, want) in tests {
+            let v0 = Keymaster::new(sec_level);
+            let got = v0.emulation_required(&params, &KeyImportData::None);
+            assert_eq!(got, want, "emulation_required({:?})={}, want {}", params, got, want);
+        }
+    }
+}
diff --git a/keystore2/src/km_compat/km_compat.cpp b/keystore2/src/km_compat/km_compat.cpp
index bb60047..a6ca179 100644
--- a/keystore2/src/km_compat/km_compat.cpp
+++ b/keystore2/src/km_compat/km_compat.cpp
@@ -1391,14 +1391,33 @@
     }
 }
 
+std::shared_ptr<IKeyMintDevice> getSoftwareKeymintDevice() {
+    static std::mutex mutex;
+    static std::shared_ptr<IKeyMintDevice> swDevice;
+    std::lock_guard<std::mutex> lock(mutex);
+    if (!swDevice) {
+        swDevice.reset(CreateKeyMintDevice(KeyMintSecurityLevel::SOFTWARE));
+    }
+    return swDevice;
+}
+
 std::shared_ptr<KeyMintDevice>
-KeyMintDevice::createKeyMintDevice(KeyMintSecurityLevel securityLevel) {
+KeyMintDevice::getWrappedKeymasterDevice(KeyMintSecurityLevel securityLevel) {
     if (auto dev = getDevice(securityLevel)) {
         return ndk::SharedRefBase::make<KeyMintDevice>(std::move(dev), securityLevel);
     }
     return {};
 }
 
+std::shared_ptr<IKeyMintDevice>
+KeyMintDevice::createKeyMintDevice(KeyMintSecurityLevel securityLevel) {
+    if (securityLevel == KeyMintSecurityLevel::SOFTWARE) {
+        return getSoftwareKeymintDevice();
+    } else {
+        return getWrappedKeymasterDevice(securityLevel);
+    }
+}
+
 std::shared_ptr<SharedSecret> SharedSecret::createSharedSecret(KeyMintSecurityLevel securityLevel) {
     auto device = getDevice(securityLevel);
     if (!device) {
diff --git a/keystore2/src/km_compat/km_compat.h b/keystore2/src/km_compat/km_compat.h
index 70c7b86..c07470d 100644
--- a/keystore2/src/km_compat/km_compat.h
+++ b/keystore2/src/km_compat/km_compat.h
@@ -84,7 +84,9 @@
 
   public:
     explicit KeyMintDevice(::android::sp<Keymaster>, KeyMintSecurityLevel);
-    static std::shared_ptr<KeyMintDevice> createKeyMintDevice(KeyMintSecurityLevel securityLevel);
+    static std::shared_ptr<IKeyMintDevice> createKeyMintDevice(KeyMintSecurityLevel securityLevel);
+    static std::shared_ptr<KeyMintDevice>
+    getWrappedKeymasterDevice(KeyMintSecurityLevel securityLevel);
 
     ScopedAStatus getHardwareInfo(KeyMintHardwareInfo* _aidl_return) override;
     ScopedAStatus addRngEntropy(const std::vector<uint8_t>& in_data) override;
diff --git a/keystore2/src/km_compat/slot_test.cpp b/keystore2/src/km_compat/slot_test.cpp
index 43f3bc6..3539c4d 100644
--- a/keystore2/src/km_compat/slot_test.cpp
+++ b/keystore2/src/km_compat/slot_test.cpp
@@ -73,7 +73,9 @@
 
 TEST(SlotTest, TestSlots) {
     static std::shared_ptr<KeyMintDevice> device =
-        KeyMintDevice::createKeyMintDevice(SecurityLevel::TRUSTED_ENVIRONMENT);
+        KeyMintDevice::getWrappedKeymasterDevice(SecurityLevel::TRUSTED_ENVIRONMENT);
+    ASSERT_NE(device.get(), nullptr);
+
     device->setNumFreeSlots(NUM_SLOTS);
 
     // A begin() that returns a failure should not use a slot.
diff --git a/keystore2/src/legacy_migrator.rs b/keystore2/src/legacy_importer.rs
similarity index 79%
rename from keystore2/src/legacy_migrator.rs
rename to keystore2/src/legacy_importer.rs
index 65f4b0b..3f37b14 100644
--- a/keystore2/src/legacy_migrator.rs
+++ b/keystore2/src/legacy_importer.rs
@@ -38,8 +38,8 @@
 use std::sync::mpsc::channel;
 use std::sync::{Arc, Mutex};
 
-/// Represents LegacyMigrator.
-pub struct LegacyMigrator {
+/// Represents LegacyImporter.
+pub struct LegacyImporter {
     async_task: Arc<AsyncTask>,
     initializer: Mutex<
         Option<
@@ -51,19 +51,19 @@
         >,
     >,
     /// This atomic is used for cheap interior mutability. It is intended to prevent
-    /// expensive calls into the legacy migrator when the legacy database is empty.
+    /// expensive calls into the legacy importer when the legacy database is empty.
     /// When transitioning from READY to EMPTY, spurious calls may occur for a brief period
     /// of time. This is tolerable in favor of the common case.
     state: AtomicU8,
 }
 
 #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
-struct RecentMigration {
+struct RecentImport {
     uid: u32,
     alias: String,
 }
 
-impl RecentMigration {
+impl RecentImport {
     fn new(uid: u32, alias: String) -> Self {
         Self { uid, alias }
     }
@@ -74,15 +74,15 @@
     User(u32),
 }
 
-struct LegacyMigratorState {
-    recently_migrated: HashSet<RecentMigration>,
-    recently_migrated_super_key: HashSet<u32>,
+struct LegacyImporterState {
+    recently_imported: HashSet<RecentImport>,
+    recently_imported_super_key: HashSet<u32>,
     legacy_loader: Arc<LegacyBlobLoader>,
     sec_level_to_km_uuid: HashMap<SecurityLevel, Uuid>,
     db: KeystoreDB,
 }
 
-impl LegacyMigrator {
+impl LegacyImporter {
     const WIFI_NAMESPACE: i64 = 102;
     const AID_WIFI: u32 = 1010;
 
@@ -90,7 +90,7 @@
     const STATE_READY: u8 = 1;
     const STATE_EMPTY: u8 = 2;
 
-    /// Constructs a new LegacyMigrator using the given AsyncTask object as migration
+    /// Constructs a new LegacyImporter using the given AsyncTask object as import
     /// worker.
     pub fn new(async_task: Arc<AsyncTask>) -> Self {
         Self {
@@ -100,7 +100,7 @@
         }
     }
 
-    /// The legacy migrator must be initialized deferred, because keystore starts very early.
+    /// The legacy importer must be initialized deferred, because keystore starts very early.
     /// At this time the data partition may not be mounted. So we cannot open database connections
     /// until we get actual key load requests. This sets the function that the legacy loader
     /// uses to connect to the database.
@@ -125,11 +125,11 @@
         Ok(())
     }
 
-    /// This function is called by the migration requestor to check if it is worth
-    /// making a migration request. It also transitions the state from UNINITIALIZED
+    /// This function is called by the import requestor to check if it is worth
+    /// making an import request. It also transitions the state from UNINITIALIZED
     /// to READY or EMPTY on first use. The deferred initialization is necessary, because
     /// Keystore 2.0 runs early during boot, where data may not yet be mounted.
-    /// Returns Ok(STATE_READY) if a migration request is worth undertaking and
+    /// Returns Ok(STATE_READY) if an import request is worth undertaking and
     /// Ok(STATE_EMPTY) if the database is empty. An error is returned if the loader
     /// was not initialized and cannot be initialized.
     fn check_state(&self) -> Result<u8> {
@@ -157,9 +157,9 @@
                         }
 
                         self.async_task.queue_hi(move |shelf| {
-                            shelf.get_or_put_with(|| LegacyMigratorState {
-                                recently_migrated: Default::default(),
-                                recently_migrated_super_key: Default::default(),
+                            shelf.get_or_put_with(|| LegacyImporterState {
+                                recently_imported: Default::default(),
+                                recently_imported_super_key: Default::default(),
                                 legacy_loader,
                                 sec_level_to_km_uuid,
                                 db,
@@ -189,14 +189,14 @@
                     );
                 }
                 (Self::STATE_READY, _) => return Ok(Self::STATE_READY),
-                (s, _) => panic!("Unknown legacy migrator state. {} ", s),
+                (s, _) => panic!("Unknown legacy importer state. {} ", s),
             }
         }
     }
 
     /// List all aliases for uid in the legacy database.
     pub fn list_uid(&self, domain: Domain, namespace: i64) -> Result<Vec<KeyDescriptor>> {
-        let _wp = wd::watch_millis("LegacyMigrator::list_uid", 500);
+        let _wp = wd::watch_millis("LegacyImporter::list_uid", 500);
 
         let uid = match (domain, namespace) {
             (Domain::APP, namespace) => namespace as u32,
@@ -217,44 +217,44 @@
         )
     }
 
-    /// Sends the given closure to the migrator thread for execution after calling check_state.
+    /// Sends the given closure to the importer thread for execution after calling check_state.
     /// Returns None if the database was empty and the request was not executed.
-    /// Otherwise returns Some with the result produced by the migration request.
+    /// Otherwise returns Some with the result produced by the import request.
     /// The loader state may transition to STATE_EMPTY during the execution of this function.
     fn do_serialized<F, T: Send + 'static>(&self, f: F) -> Option<Result<T>>
     where
-        F: FnOnce(&mut LegacyMigratorState) -> Result<T> + Send + 'static,
+        F: FnOnce(&mut LegacyImporterState) -> Result<T> + Send + 'static,
     {
         // Short circuit if the database is empty or not initialized (error case).
         match self.check_state().context("In do_serialized: Checking state.") {
-            Ok(LegacyMigrator::STATE_EMPTY) => return None,
-            Ok(LegacyMigrator::STATE_READY) => {}
+            Ok(LegacyImporter::STATE_EMPTY) => return None,
+            Ok(LegacyImporter::STATE_READY) => {}
             Err(e) => return Some(Err(e)),
-            Ok(s) => panic!("Unknown legacy migrator state. {} ", s),
+            Ok(s) => panic!("Unknown legacy importer state. {} ", s),
         }
 
         // We have established that there may be a key in the legacy database.
-        // Now we schedule a migration request.
+        // Now we schedule an import request.
         let (sender, receiver) = channel();
         self.async_task.queue_hi(move |shelf| {
-            // Get the migrator state from the shelf.
-            // There may not be a state. This can happen if this migration request was scheduled
+            // Get the importer state from the shelf.
+            // There may not be a state. This can happen if this import request was scheduled
             // before a previous request established that the legacy database was empty
             // and removed the state from the shelf. Since we know now that the database
             // is empty, we can return None here.
-            let (new_state, result) = if let Some(legacy_migrator_state) =
-                shelf.get_downcast_mut::<LegacyMigratorState>()
+            let (new_state, result) = if let Some(legacy_importer_state) =
+                shelf.get_downcast_mut::<LegacyImporterState>()
             {
-                let result = f(legacy_migrator_state);
-                (legacy_migrator_state.check_empty(), Some(result))
+                let result = f(legacy_importer_state);
+                (legacy_importer_state.check_empty(), Some(result))
             } else {
                 (Self::STATE_EMPTY, None)
             };
 
-            // If the migration request determined that the database is now empty, we discard
+            // If the import request determined that the database is now empty, we discard
             // the state from the shelf to free up the resources we won't need any longer.
             if result.is_some() && new_state == Self::STATE_EMPTY {
-                shelf.remove_downcast_ref::<LegacyMigratorState>();
+                shelf.remove_downcast_ref::<LegacyImporterState>();
             }
 
             // Send the result to the requester.
@@ -271,7 +271,7 @@
         };
 
         // We can only transition to EMPTY but never back.
-        // The migrator never creates any legacy blobs.
+        // The importer never creates any legacy blobs.
         if new_state == Self::STATE_EMPTY {
             self.state.store(Self::STATE_EMPTY, Ordering::Relaxed)
         }
@@ -280,10 +280,10 @@
     }
 
     /// Runs the key_accessor function and returns its result. If it returns an error and the
-    /// root cause was KEY_NOT_FOUND, tries to migrate a key with the given parameters from
+    /// root cause was KEY_NOT_FOUND, tries to import a key with the given parameters from
     /// the legacy database to the new database and runs the key_accessor function again if
-    /// the migration request was successful.
-    pub fn with_try_migrate<F, T>(
+    /// the import request was successful.
+    pub fn with_try_import<F, T>(
         &self,
         key: &KeyDescriptor,
         caller_uid: u32,
@@ -292,7 +292,7 @@
     where
         F: Fn() -> Result<T>,
     {
-        let _wp = wd::watch_millis("LegacyMigrator::with_try_migrate", 500);
+        let _wp = wd::watch_millis("LegacyImporter::with_try_import", 500);
 
         // Access the key and return on success.
         match key_accessor() {
@@ -304,7 +304,7 @@
         }
 
         // Filter inputs. We can only load legacy app domain keys and some special rules due
-        // to which we migrate keys transparently to an SELINUX domain.
+        // to which we import keys transparently to an SELINUX domain.
         let uid = match key {
             KeyDescriptor { domain: Domain::APP, alias: Some(_), .. } => caller_uid,
             KeyDescriptor { domain: Domain::SELINUX, nspace, alias: Some(_), .. } => {
@@ -324,11 +324,11 @@
 
         let key_clone = key.clone();
         let result = self
-            .do_serialized(move |migrator_state| migrator_state.check_and_migrate(uid, key_clone));
+            .do_serialized(move |importer_state| importer_state.check_and_import(uid, key_clone));
 
         if let Some(result) = result {
             result?;
-            // After successful migration try again.
+            // After successful import try again.
             key_accessor()
         } else {
             Err(Error::Rc(ResponseCode::KEY_NOT_FOUND)).context("Legacy database is empty.")
@@ -336,8 +336,8 @@
     }
 
     /// Calls key_accessor and returns the result on success. In the case of a KEY_NOT_FOUND error
-    /// this function makes a migration request and on success retries the key_accessor.
-    pub fn with_try_migrate_super_key<F, T>(
+    /// this function makes an import request and on success retries the key_accessor.
+    pub fn with_try_import_super_key<F, T>(
         &self,
         user_id: u32,
         pw: &Password,
@@ -346,31 +346,31 @@
     where
         F: FnMut() -> Result<Option<T>>,
     {
-        let _wp = wd::watch_millis("LegacyMigrator::with_try_migrate_super_key", 500);
+        let _wp = wd::watch_millis("LegacyImporter::with_try_import_super_key", 500);
 
         match key_accessor() {
             Ok(Some(result)) => return Ok(Some(result)),
             Ok(None) => {}
             Err(e) => return Err(e),
         }
-        let pw = pw.try_clone().context("In with_try_migrate_super_key: Cloning password.")?;
-        let result = self.do_serialized(move |migrator_state| {
-            migrator_state.check_and_migrate_super_key(user_id, &pw)
+        let pw = pw.try_clone().context("In with_try_import_super_key: Cloning password.")?;
+        let result = self.do_serialized(move |importer_state| {
+            importer_state.check_and_import_super_key(user_id, &pw)
         });
 
         if let Some(result) = result {
             result?;
-            // After successful migration try again.
+            // After successful import try again.
             key_accessor()
         } else {
             Ok(None)
         }
     }
 
-    /// Deletes all keys belonging to the given namespace, migrating them into the database
+    /// Deletes all keys belonging to the given namespace, importing them into the database
     /// for subsequent garbage collection if necessary.
     pub fn bulk_delete_uid(&self, domain: Domain, nspace: i64) -> Result<()> {
-        let _wp = wd::watch_millis("LegacyMigrator::bulk_delete_uid", 500);
+        let _wp = wd::watch_millis("LegacyImporter::bulk_delete_uid", 500);
 
         let uid = match (domain, nspace) {
             (Domain::APP, nspace) => nspace as u32,
@@ -379,24 +379,24 @@
             _ => return Ok(()),
         };
 
-        let result = self.do_serialized(move |migrator_state| {
-            migrator_state.bulk_delete(BulkDeleteRequest::Uid(uid), false)
+        let result = self.do_serialized(move |importer_state| {
+            importer_state.bulk_delete(BulkDeleteRequest::Uid(uid), false)
         });
 
         result.unwrap_or(Ok(()))
     }
 
-    /// Deletes all keys belonging to the given android user, migrating them into the database
+    /// Deletes all keys belonging to the given android user, importing them into the database
     /// for subsequent garbage collection if necessary.
     pub fn bulk_delete_user(
         &self,
         user_id: u32,
         keep_non_super_encrypted_keys: bool,
     ) -> Result<()> {
-        let _wp = wd::watch_millis("LegacyMigrator::bulk_delete_user", 500);
+        let _wp = wd::watch_millis("LegacyImporter::bulk_delete_user", 500);
 
-        let result = self.do_serialized(move |migrator_state| {
-            migrator_state
+        let result = self.do_serialized(move |importer_state| {
+            importer_state
                 .bulk_delete(BulkDeleteRequest::User(user_id), keep_non_super_encrypted_keys)
         });
 
@@ -406,12 +406,12 @@
     /// Queries the legacy database for the presence of a super key for the given user.
     pub fn has_super_key(&self, user_id: u32) -> Result<bool> {
         let result =
-            self.do_serialized(move |migrator_state| migrator_state.has_super_key(user_id));
+            self.do_serialized(move |importer_state| importer_state.has_super_key(user_id));
         result.unwrap_or(Ok(false))
     }
 }
 
-impl LegacyMigratorState {
+impl LegacyImporterState {
     fn get_km_uuid(&self, is_strongbox: bool) -> Result<Uuid> {
         let sec_level = if is_strongbox {
             SecurityLevel::STRONGBOX
@@ -430,17 +430,17 @@
             .context("In list_uid: Trying to list legacy entries.")
     }
 
-    /// This is a key migration request that must run in the migrator thread. This must
+    /// This is a key import request that must run in the importer thread. This must
     /// be passed to do_serialized.
-    fn check_and_migrate(&mut self, uid: u32, mut key: KeyDescriptor) -> Result<()> {
+    fn check_and_import(&mut self, uid: u32, mut key: KeyDescriptor) -> Result<()> {
         let alias = key.alias.clone().ok_or_else(|| {
-            anyhow::anyhow!(Error::sys()).context(concat!(
-                "In check_and_migrate: Must be Some because ",
-                "our caller must not have called us otherwise."
-            ))
+            anyhow::anyhow!(Error::sys()).context(
+                "In check_and_import: Must be Some because \
+                 our caller must not have called us otherwise.",
+            )
         })?;
 
-        if self.recently_migrated.contains(&RecentMigration::new(uid, alias.clone())) {
+        if self.recently_imported.contains(&RecentImport::new(uid, alias.clone())) {
             return Ok(());
         }
 
@@ -452,7 +452,7 @@
         let (km_blob_params, user_cert, ca_cert) = self
             .legacy_loader
             .load_by_uid_alias(uid, &alias, None)
-            .context("In check_and_migrate: Trying to load legacy blob.")?;
+            .context("In check_and_import: Trying to load legacy blob.")?;
         let result = match km_blob_params {
             Some((km_blob, params)) => {
                 let is_strongbox = km_blob.is_strongbox();
@@ -464,33 +464,33 @@
                         let super_key_id = match self
                             .db
                             .load_super_key(&USER_SUPER_KEY, user_id)
-                            .context("In check_and_migrate: Failed to load super key")?
+                            .context("In check_and_import: Failed to load super key")?
                         {
                             Some((_, entry)) => entry.id(),
                             None => {
                                 // This might be the first time we access the super key,
-                                // and it may not have been migrated. We cannot import
+                                // and it may not have been imported. We cannot import
                                 // the legacy super_key key now, because we need to reencrypt
                                 // it which we cannot do if we are not unlocked, which we are
-                                // not because otherwise the key would have been migrated.
+                                // not because otherwise the key would have been imported.
                                 // We can check though if the key exists. If it does,
                                 // we can return Locked. Otherwise, we can delete the
                                 // key and return NotFound, because the key will never
                                 // be unlocked again.
                                 if self.legacy_loader.has_super_key(user_id) {
                                     return Err(Error::Rc(ResponseCode::LOCKED)).context(concat!(
-                                        "In check_and_migrate: Cannot migrate super key of this ",
+                                        "In check_and_import: Cannot import super key of this ",
                                         "key while user is locked."
                                     ));
                                 } else {
                                     self.legacy_loader.remove_keystore_entry(uid, &alias).context(
                                         concat!(
-                                            "In check_and_migrate: ",
+                                            "In check_and_import: ",
                                             "Trying to remove obsolete key."
                                         ),
                                     )?;
                                     return Err(Error::Rc(ResponseCode::KEY_NOT_FOUND))
-                                        .context("In check_and_migrate: Obsolete key.");
+                                        .context("In check_and_import: Obsolete key.");
                                 }
                             }
                         };
@@ -505,18 +505,18 @@
                     BlobValue::Decrypted(data) => (LegacyBlob::ZVec(data), BlobMetaData::new()),
                     _ => {
                         return Err(Error::Rc(ResponseCode::KEY_NOT_FOUND))
-                            .context("In check_and_migrate: Legacy key has unexpected type.")
+                            .context("In check_and_import: Legacy key has unexpected type.")
                     }
                 };
 
                 let km_uuid = self
                     .get_km_uuid(is_strongbox)
-                    .context("In check_and_migrate: Trying to get KM UUID")?;
+                    .context("In check_and_import: Trying to get KM UUID")?;
                 blob_metadata.add(BlobMetaEntry::KmUuid(km_uuid));
 
                 let mut metadata = KeyMetaData::new();
                 let creation_date = DateTime::now()
-                    .context("In check_and_migrate: Trying to make creation time.")?;
+                    .context("In check_and_import: Trying to make creation time.")?;
                 metadata.add(KeyMetaEntry::CreationDate(creation_date));
 
                 // Store legacy key in the database.
@@ -530,49 +530,49 @@
                         &metadata,
                         &km_uuid,
                     )
-                    .context("In check_and_migrate.")?;
+                    .context("In check_and_import.")?;
                 Ok(())
             }
             None => {
                 if let Some(ca_cert) = ca_cert {
                     self.db
                         .store_new_certificate(&key, KeyType::Client, &ca_cert, &KEYSTORE_UUID)
-                        .context("In check_and_migrate: Failed to insert new certificate.")?;
+                        .context("In check_and_import: Failed to insert new certificate.")?;
                     Ok(())
                 } else {
                     Err(Error::Rc(ResponseCode::KEY_NOT_FOUND))
-                        .context("In check_and_migrate: Legacy key not found.")
+                        .context("In check_and_import: Legacy key not found.")
                 }
             }
         };
 
         match result {
             Ok(()) => {
-                // Add the key to the migrated_keys list.
-                self.recently_migrated.insert(RecentMigration::new(uid, alias.clone()));
+                // Add the key to the imported_keys list.
+                self.recently_imported.insert(RecentImport::new(uid, alias.clone()));
                 // Delete legacy key from the file system
                 self.legacy_loader
                     .remove_keystore_entry(uid, &alias)
-                    .context("In check_and_migrate: Trying to remove migrated key.")?;
+                    .context("In check_and_import: Trying to remove imported key.")?;
                 Ok(())
             }
             Err(e) => Err(e),
         }
     }
 
-    fn check_and_migrate_super_key(&mut self, user_id: u32, pw: &Password) -> Result<()> {
-        if self.recently_migrated_super_key.contains(&user_id) {
+    fn check_and_import_super_key(&mut self, user_id: u32, pw: &Password) -> Result<()> {
+        if self.recently_imported_super_key.contains(&user_id) {
             return Ok(());
         }
 
         if let Some(super_key) = self
             .legacy_loader
             .load_super_key(user_id, pw)
-            .context("In check_and_migrate_super_key: Trying to load legacy super key.")?
+            .context("In check_and_import_super_key: Trying to load legacy super key.")?
         {
             let (blob, blob_metadata) =
                 crate::super_key::SuperKeyManager::encrypt_with_password(&super_key, pw)
-                    .context("In check_and_migrate_super_key: Trying to encrypt super key.")?;
+                    .context("In check_and_import_super_key: Trying to encrypt super key.")?;
 
             self.db
                 .store_super_key(
@@ -583,20 +583,20 @@
                     &KeyMetaData::new(),
                 )
                 .context(concat!(
-                    "In check_and_migrate_super_key: ",
+                    "In check_and_import_super_key: ",
                     "Trying to insert legacy super_key into the database."
                 ))?;
             self.legacy_loader.remove_super_key(user_id);
-            self.recently_migrated_super_key.insert(user_id);
+            self.recently_imported_super_key.insert(user_id);
             Ok(())
         } else {
             Err(Error::Rc(ResponseCode::KEY_NOT_FOUND))
-                .context("In check_and_migrate_super_key: No key found do migrate.")
+                .context("In check_and_import_super_key: No key found do import.")
         }
     }
 
-    /// Key migrator request to be run by do_serialized.
-    /// See LegacyMigrator::bulk_delete_uid and LegacyMigrator::bulk_delete_user.
+    /// Key importer request to be run by do_serialized.
+    /// See LegacyImporter::bulk_delete_uid and LegacyImporter::bulk_delete_user.
     fn bulk_delete(
         &mut self,
         bulk_delete_request: BulkDeleteRequest,
@@ -695,21 +695,21 @@
 
             self.legacy_loader
                 .remove_keystore_entry(uid, &alias)
-                .context("In bulk_delete: Trying to remove migrated key.")?;
+                .context("In bulk_delete: Trying to remove imported key.")?;
         }
         Ok(())
     }
 
     fn has_super_key(&mut self, user_id: u32) -> Result<bool> {
-        Ok(self.recently_migrated_super_key.contains(&user_id)
+        Ok(self.recently_imported_super_key.contains(&user_id)
             || self.legacy_loader.has_super_key(user_id))
     }
 
     fn check_empty(&self) -> u8 {
         if self.legacy_loader.is_empty().unwrap_or(false) {
-            LegacyMigrator::STATE_EMPTY
+            LegacyImporter::STATE_EMPTY
         } else {
-            LegacyMigrator::STATE_READY
+            LegacyImporter::STATE_READY
         }
     }
 }
diff --git a/keystore2/src/lib.rs b/keystore2/src/lib.rs
index 134f707..4a23843 100644
--- a/keystore2/src/lib.rs
+++ b/keystore2/src/lib.rs
@@ -29,7 +29,7 @@
 /// Internal Representation of Key Parameter and convenience functions.
 pub mod key_parameter;
 pub mod legacy_blob;
-pub mod legacy_migrator;
+pub mod legacy_importer;
 pub mod maintenance;
 pub mod metrics;
 pub mod metrics_store;
@@ -45,6 +45,7 @@
 mod attestation_key_utils;
 mod audit_log;
 mod gc;
+mod km_compat;
 mod super_key;
 
 #[cfg(feature = "watchdog")]
diff --git a/keystore2/src/maintenance.rs b/keystore2/src/maintenance.rs
index 9925e42..71f43d6 100644
--- a/keystore2/src/maintenance.rs
+++ b/keystore2/src/maintenance.rs
@@ -19,7 +19,7 @@
 use crate::error::map_or_log_err;
 use crate::error::Error;
 use crate::globals::get_keymint_device;
-use crate::globals::{DB, LEGACY_MIGRATOR, SUPER_KEY};
+use crate::globals::{DB, LEGACY_IMPORTER, SUPER_KEY};
 use crate::permission::{KeyPerm, KeystorePerm};
 use crate::super_key::{SuperKeyManager, UserState};
 use crate::utils::{
@@ -88,7 +88,7 @@
             .with(|db| {
                 skm.reset_or_init_user_and_get_user_state(
                     &mut db.borrow_mut(),
-                    &LEGACY_MIGRATOR,
+                    &LEGACY_IMPORTER,
                     user_id as u32,
                     password.as_ref(),
                 )
@@ -115,7 +115,7 @@
         DB.with(|db| {
             SUPER_KEY.write().unwrap().reset_user(
                 &mut db.borrow_mut(),
-                &LEGACY_MIGRATOR,
+                &LEGACY_IMPORTER,
                 user_id as u32,
                 false,
             )
@@ -130,7 +130,7 @@
         // Permission check. Must return on error. Do not touch the '?'.
         check_keystore_permission(KeystorePerm::ClearUID).context("In clear_namespace.")?;
 
-        LEGACY_MIGRATOR
+        LEGACY_IMPORTER
             .bulk_delete_uid(domain, nspace)
             .context("In clear_namespace: Trying to delete legacy keys.")?;
         DB.with(|db| db.borrow_mut().unbind_keys_for_namespace(domain, nspace))
@@ -148,7 +148,7 @@
             .with(|db| {
                 SUPER_KEY.read().unwrap().get_user_state(
                     &mut db.borrow_mut(),
-                    &LEGACY_MIGRATOR,
+                    &LEGACY_IMPORTER,
                     user_id as u32,
                 )
             })
@@ -235,7 +235,7 @@
             }
             _ => {
                 return Err(Error::Rc(ResponseCode::INVALID_ARGUMENT)).context(
-                    "In migrate_key_namespace:
+                    "In migrate_key_namespace: \
                      Source domain must be one of APP, SELINUX, or KEY_ID.",
                 )
             }
@@ -249,15 +249,15 @@
             }
             _ => {
                 return Err(Error::Rc(ResponseCode::INVALID_ARGUMENT)).context(
-                    "In migrate_key_namespace:
+                    "In migrate_key_namespace: \
                      Destination domain must be one of APP or SELINUX.",
                 )
             }
         };
 
         DB.with(|db| {
-            let (key_id_guard, _) = LEGACY_MIGRATOR
-                .with_try_migrate(source, src_uid, || {
+            let (key_id_guard, _) = LEGACY_IMPORTER
+                .with_try_import(source, src_uid, || {
                     db.borrow_mut().load_key_entry(
                         source,
                         KeyType::Client,
diff --git a/keystore2/src/security_level.rs b/keystore2/src/security_level.rs
index 83f0bee..eefbc20 100644
--- a/keystore2/src/security_level.rs
+++ b/keystore2/src/security_level.rs
@@ -20,7 +20,7 @@
 };
 use crate::database::{CertificateInfo, KeyIdGuard};
 use crate::error::{self, map_km_error, map_or_log_err, Error, ErrorCode};
-use crate::globals::{DB, ENFORCEMENTS, LEGACY_MIGRATOR, SUPER_KEY};
+use crate::globals::{DB, ENFORCEMENTS, LEGACY_IMPORTER, SUPER_KEY};
 use crate::key_parameter::KeyParameter as KsKeyParam;
 use crate::key_parameter::KeyParameterValue as KsKeyParamValue;
 use crate::metrics_store::log_key_creation_event_stats;
@@ -164,7 +164,7 @@
                         .unwrap()
                         .handle_super_encryption_on_key_init(
                             &mut db,
-                            &LEGACY_MIGRATOR,
+                            &LEGACY_IMPORTER,
                             &(key.domain),
                             &key_parameters,
                             flags,
@@ -245,7 +245,7 @@
             _ => {
                 let (key_id_guard, mut key_entry) = DB
                     .with::<_, Result<(KeyIdGuard, KeyEntry)>>(|db| {
-                        LEGACY_MIGRATOR.with_try_migrate(key, caller_uid, || {
+                        LEGACY_IMPORTER.with_try_import(key, caller_uid, || {
                             db.borrow_mut().load_key_entry(
                                 key,
                                 KeyType::Client,
@@ -723,7 +723,7 @@
 
         let (wrapping_key_id_guard, mut wrapping_key_entry) = DB
             .with(|db| {
-                LEGACY_MIGRATOR.with_try_migrate(&key, caller_uid, || {
+                LEGACY_IMPORTER.with_try_import(&key, caller_uid, || {
                     db.borrow_mut().load_key_entry(
                         wrapping_key,
                         KeyType::Client,
diff --git a/keystore2/src/service.rs b/keystore2/src/service.rs
index 2725dc2..46bc8b0 100644
--- a/keystore2/src/service.rs
+++ b/keystore2/src/service.rs
@@ -26,7 +26,7 @@
 };
 use crate::{
     database::Uuid,
-    globals::{create_thread_local_db, DB, LEGACY_BLOB_LOADER, LEGACY_MIGRATOR},
+    globals::{create_thread_local_db, DB, LEGACY_BLOB_LOADER, LEGACY_IMPORTER},
 };
 use crate::{database::KEYSTORE_UUID, permission};
 use crate::{
@@ -81,7 +81,7 @@
         }
 
         let uuid_by_sec_level = result.uuid_by_sec_level.clone();
-        LEGACY_MIGRATOR
+        LEGACY_IMPORTER
             .set_init(move || {
                 (create_thread_local_db(), uuid_by_sec_level, LEGACY_BLOB_LOADER.clone())
             })
@@ -132,7 +132,7 @@
         let caller_uid = ThreadState::get_calling_uid();
         let (key_id_guard, mut key_entry) = DB
             .with(|db| {
-                LEGACY_MIGRATOR.with_try_migrate(key, caller_uid, || {
+                LEGACY_IMPORTER.with_try_import(key, caller_uid, || {
                     db.borrow_mut().load_key_entry(
                         key,
                         KeyType::Client,
@@ -183,7 +183,7 @@
     ) -> Result<()> {
         let caller_uid = ThreadState::get_calling_uid();
         DB.with::<_, Result<()>>(|db| {
-            let entry = match LEGACY_MIGRATOR.with_try_migrate(key, caller_uid, || {
+            let entry = match LEGACY_IMPORTER.with_try_import(key, caller_uid, || {
                 db.borrow_mut().load_key_entry(
                     key,
                     KeyType::Client,
@@ -292,7 +292,7 @@
     fn delete_key(&self, key: &KeyDescriptor) -> Result<()> {
         let caller_uid = ThreadState::get_calling_uid();
         DB.with(|db| {
-            LEGACY_MIGRATOR.with_try_migrate(key, caller_uid, || {
+            LEGACY_IMPORTER.with_try_import(key, caller_uid, || {
                 db.borrow_mut().unbind_key(key, KeyType::Client, caller_uid, |k, av| {
                     check_key_permission(KeyPerm::Delete, k, &av).context("During delete_key.")
                 })
@@ -310,7 +310,7 @@
     ) -> Result<KeyDescriptor> {
         let caller_uid = ThreadState::get_calling_uid();
         DB.with(|db| {
-            LEGACY_MIGRATOR.with_try_migrate(key, caller_uid, || {
+            LEGACY_IMPORTER.with_try_import(key, caller_uid, || {
                 db.borrow_mut().grant(
                     key,
                     caller_uid,
diff --git a/keystore2/src/super_key.rs b/keystore2/src/super_key.rs
index 6862011..2fb4991 100644
--- a/keystore2/src/super_key.rs
+++ b/keystore2/src/super_key.rs
@@ -26,7 +26,7 @@
     error::ResponseCode,
     key_parameter::{KeyParameter, KeyParameterValue},
     legacy_blob::LegacyBlobLoader,
-    legacy_migrator::LegacyMigrator,
+    legacy_importer::LegacyImporter,
     raw_device::KeyMintDevice,
     utils::watchdog as wd,
     utils::AID_KEYSTORE,
@@ -507,7 +507,7 @@
     fn super_key_exists_in_db_for_user(
         &self,
         db: &mut KeystoreDB,
-        legacy_migrator: &LegacyMigrator,
+        legacy_importer: &LegacyImporter,
         user_id: UserId,
     ) -> Result<bool> {
         let key_in_db = db
@@ -517,7 +517,7 @@
         if key_in_db {
             Ok(key_in_db)
         } else {
-            legacy_migrator
+            legacy_importer
                 .has_super_key(user_id)
                 .context("In super_key_exists_in_db_for_user: Trying to query legacy db.")
         }
@@ -529,13 +529,13 @@
     pub fn check_and_unlock_super_key(
         &mut self,
         db: &mut KeystoreDB,
-        legacy_migrator: &LegacyMigrator,
+        legacy_importer: &LegacyImporter,
         user_id: UserId,
         pw: &Password,
     ) -> Result<UserState> {
         let alias = &USER_SUPER_KEY;
-        let result = legacy_migrator
-            .with_try_migrate_super_key(user_id, pw, || db.load_super_key(alias, user_id))
+        let result = legacy_importer
+            .with_try_import_super_key(user_id, pw, || db.load_super_key(alias, user_id))
             .context("In check_and_unlock_super_key. Failed to load super key")?;
 
         match result {
@@ -558,12 +558,12 @@
     pub fn check_and_initialize_super_key(
         &mut self,
         db: &mut KeystoreDB,
-        legacy_migrator: &LegacyMigrator,
+        legacy_importer: &LegacyImporter,
         user_id: UserId,
         pw: Option<&Password>,
     ) -> Result<UserState> {
         let super_key_exists_in_db = self
-            .super_key_exists_in_db_for_user(db, legacy_migrator, user_id)
+            .super_key_exists_in_db_for_user(db, legacy_importer, user_id)
             .context("In check_and_initialize_super_key. Failed to check if super key exists.")?;
         if super_key_exists_in_db {
             Ok(UserState::LskfLocked)
@@ -691,12 +691,12 @@
     fn super_encrypt_on_key_init(
         &self,
         db: &mut KeystoreDB,
-        legacy_migrator: &LegacyMigrator,
+        legacy_importer: &LegacyImporter,
         user_id: UserId,
         key_blob: &[u8],
     ) -> Result<(Vec<u8>, BlobMetaData)> {
         match self
-            .get_user_state(db, legacy_migrator, user_id)
+            .get_user_state(db, legacy_importer, user_id)
             .context("In super_encrypt. Failed to get user state.")?
         {
             UserState::LskfUnlocked(super_key) => {
@@ -737,7 +737,7 @@
     pub fn handle_super_encryption_on_key_init(
         &self,
         db: &mut KeystoreDB,
-        legacy_migrator: &LegacyMigrator,
+        legacy_importer: &LegacyImporter,
         domain: &Domain,
         key_parameters: &[KeyParameter],
         flags: Option<i32>,
@@ -747,7 +747,7 @@
         match Enforcements::super_encryption_required(domain, key_parameters, flags) {
             SuperEncryptionType::None => Ok((key_blob.to_vec(), BlobMetaData::new())),
             SuperEncryptionType::LskfBound => self
-                .super_encrypt_on_key_init(db, legacy_migrator, user_id, key_blob)
+                .super_encrypt_on_key_init(db, legacy_importer, user_id, key_blob)
                 .context(concat!(
                     "In handle_super_encryption_on_key_init. ",
                     "Failed to super encrypt with LskfBound key."
@@ -1086,11 +1086,11 @@
 
     /// Returns the keystore locked state of the given user. It requires the thread local
     /// keystore database and a reference to the legacy migrator because it may need to
-    /// migrate the super key from the legacy blob database to the keystore database.
+    /// import the super key from the legacy blob database to the keystore database.
     pub fn get_user_state(
         &self,
         db: &mut KeystoreDB,
-        legacy_migrator: &LegacyMigrator,
+        legacy_importer: &LegacyImporter,
         user_id: UserId,
     ) -> Result<UserState> {
         match self.get_per_boot_key_by_user_id(user_id) {
@@ -1099,7 +1099,7 @@
                 // Check if a super key exists in the database or legacy database.
                 // If so, return locked user state.
                 if self
-                    .super_key_exists_in_db_for_user(db, legacy_migrator, user_id)
+                    .super_key_exists_in_db_for_user(db, legacy_importer, user_id)
                     .context("In get_user_state.")?
                 {
                     Ok(UserState::LskfLocked)
@@ -1123,7 +1123,7 @@
     pub fn reset_or_init_user_and_get_user_state(
         &mut self,
         db: &mut KeystoreDB,
-        legacy_migrator: &LegacyMigrator,
+        legacy_importer: &LegacyImporter,
         user_id: UserId,
         password: Option<&Password>,
     ) -> Result<UserState> {
@@ -1131,7 +1131,7 @@
             Some(_) if password.is_none() => {
                 // Transitioning to swiping, delete only the super key in database and cache,
                 // and super-encrypted keys in database (and in KM).
-                self.reset_user(db, legacy_migrator, user_id, true).context(
+                self.reset_user(db, legacy_importer, user_id, true).context(
                     "In reset_or_init_user_and_get_user_state: Trying to delete keys from the db.",
                 )?;
                 // Lskf is now removed in Keystore.
@@ -1147,7 +1147,7 @@
                 // If so, return LskfLocked state.
                 // Otherwise, i) if the password is provided, initialize the super key and return
                 // LskfUnlocked state ii) if password is not provided, return Uninitialized state.
-                self.check_and_initialize_super_key(db, legacy_migrator, user_id, password)
+                self.check_and_initialize_super_key(db, legacy_importer, user_id, password)
             }
         }
     }
@@ -1158,7 +1158,7 @@
     pub fn unlock_and_get_user_state(
         &mut self,
         db: &mut KeystoreDB,
-        legacy_migrator: &LegacyMigrator,
+        legacy_importer: &LegacyImporter,
         user_id: UserId,
         password: &Password,
     ) -> Result<UserState> {
@@ -1172,7 +1172,7 @@
                 // If not, return Uninitialized state.
                 // Otherwise, try to unlock the super key and if successful,
                 // return LskfUnlocked.
-                self.check_and_unlock_super_key(db, legacy_migrator, user_id, password)
+                self.check_and_unlock_super_key(db, legacy_importer, user_id, password)
                     .context("In unlock_and_get_user_state. Failed to unlock super key.")
             }
         }
@@ -1184,12 +1184,12 @@
     pub fn reset_user(
         &mut self,
         db: &mut KeystoreDB,
-        legacy_migrator: &LegacyMigrator,
+        legacy_importer: &LegacyImporter,
         user_id: UserId,
         keep_non_super_encrypted_keys: bool,
     ) -> Result<()> {
         // Mark keys created on behalf of the user as unreferenced.
-        legacy_migrator
+        legacy_importer
             .bulk_delete_user(user_id, keep_non_super_encrypted_keys)
             .context("In reset_user: Trying to delete legacy keys.")?;
         db.unbind_keys_for_user(user_id, keep_non_super_encrypted_keys)
diff --git a/keystore2/src/utils.rs b/keystore2/src/utils.rs
index 82e6700..c924bef 100644
--- a/keystore2/src/utils.rs
+++ b/keystore2/src/utils.rs
@@ -20,7 +20,7 @@
 use crate::permission::{KeyPerm, KeyPermSet, KeystorePerm};
 use crate::{
     database::{KeyType, KeystoreDB},
-    globals::LEGACY_MIGRATOR,
+    globals::LEGACY_IMPORTER,
 };
 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
     KeyCharacteristics::KeyCharacteristics, Tag::Tag,
@@ -211,7 +211,7 @@
 ) -> Result<Vec<KeyDescriptor>> {
     let mut result = Vec::new();
     result.append(
-        &mut LEGACY_MIGRATOR
+        &mut LEGACY_IMPORTER
             .list_uid(domain, namespace)
             .context("In list_key_entries: Trying to list legacy keys.")?,
     );