Merge changes I924d6fc8,Iee20a2b1,I4070aade,I55331da0 into main am: ac3f49f34b

Original change: https://android-review.googlesource.com/c/platform/hardware/interfaces/+/3528302

Change-Id: I6dc378a959caf958040b1cad07da8a9003730414
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/security/see/hwcrypto/aidl/vts/functional/Android.bp b/security/see/hwcrypto/aidl/vts/functional/Android.bp
index 2aea077..eb2eba1 100644
--- a/security/see/hwcrypto/aidl/vts/functional/Android.bp
+++ b/security/see/hwcrypto/aidl/vts/functional/Android.bp
@@ -65,3 +65,19 @@
         "vts",
     ],
 }
+
+rust_test {
+    name: "VtsAidlHwCryptoOperationsTests",
+    srcs: ["hwcrypto_operations_tests.rs"],
+    require_root: true,
+    defaults: [
+        "hw_crypto_hal_aidl_rust_defaults",
+    ],
+    rustlibs: [
+        "libhwcryptohal_vts_test",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+}
diff --git a/security/see/hwcrypto/aidl/vts/functional/hwcrypto_operations_tests.rs b/security/see/hwcrypto/aidl/vts/functional/hwcrypto_operations_tests.rs
new file mode 100644
index 0000000..521fb73
--- /dev/null
+++ b/security/see/hwcrypto/aidl/vts/functional/hwcrypto_operations_tests.rs
@@ -0,0 +1,586 @@
+/*
+ * Copyright (C) 2025 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.
+ */
+
+//! HwCryptoOperations tests.
+
+use android_hardware_security_see_hwcrypto::aidl::android::hardware::security::see::hwcrypto::types::{
+    AesKey::AesKey, ExplicitKeyMaterial::ExplicitKeyMaterial, KeyType::KeyType, KeyLifetime::KeyLifetime,
+    KeyUse::KeyUse, OperationData::OperationData, HmacOperationParameters::HmacOperationParameters,
+    SymmetricOperationParameters::SymmetricOperationParameters, SymmetricOperation::SymmetricOperation,
+    HmacKey::HmacKey, CipherModeParameters::CipherModeParameters, AesCipherMode::AesCipherMode,
+    SymmetricCryptoParameters::SymmetricCryptoParameters,
+};
+use android_hardware_security_see_hwcrypto::aidl::android::hardware::security::see::hwcrypto::{
+    KeyPolicy::KeyPolicy,CryptoOperation::CryptoOperation,CryptoOperationSet::CryptoOperationSet,
+    OperationParameters::OperationParameters, PatternParameters::PatternParameters,
+};
+
+#[test]
+fn test_hwcrypto_key_operations_connection() {
+    let hw_crypto_key = hwcryptohal_vts_test::get_hwcryptokey()
+        .expect("Couldn't get back a hwcryptokey binder object");
+    let hw_crypto_operations = hw_crypto_key.getHwCryptoOperations();
+    assert!(hw_crypto_operations.is_ok(), "Couldn't get back a hwcrypto operations binder object");
+}
+
+#[test]
+fn test_hwcrypto_key_operations_simple_aes_test() {
+    let hw_crypto_key = hwcryptohal_vts_test::get_hwcryptokey()
+        .expect("Couldn't get back a hwcryptokey binder object");
+    let hw_crypto_operations = hw_crypto_key
+        .getHwCryptoOperations()
+        .expect("Couldn't get back a hwcryptokey operations binder object");
+    let clear_key = ExplicitKeyMaterial::Aes(AesKey::Aes128([0; 16]));
+    let policy = KeyPolicy {
+        usage: KeyUse::ENCRYPT_DECRYPT,
+        keyLifetime: KeyLifetime::PORTABLE,
+        keyPermissions: Vec::new(),
+        keyManagementKey: false,
+        keyType: KeyType::AES_128_CBC_PKCS7_PADDING,
+    };
+    let key = hw_crypto_key.importClearKey(&clear_key, &policy).expect("couldn't import clear key");
+
+    let nonce = [0u8; 16];
+    let parameters = SymmetricCryptoParameters::Aes(AesCipherMode::Cbc(CipherModeParameters {
+        nonce: nonce.into(),
+    }));
+    let direction = SymmetricOperation::ENCRYPT;
+    let sym_op_params =
+        SymmetricOperationParameters { key: Some(key.clone()), direction, parameters };
+    let op_params = OperationParameters::SymmetricCrypto(sym_op_params);
+    let mut cmd_list = Vec::<CryptoOperation>::new();
+    let data_output = OperationData::DataBuffer(Vec::new());
+    cmd_list.push(CryptoOperation::DataOutput(data_output));
+    cmd_list.push(CryptoOperation::SetOperationParameters(op_params));
+    let input_data = OperationData::DataBuffer("string to be encrypted".as_bytes().to_vec());
+    cmd_list.push(CryptoOperation::DataInput(input_data));
+    let crypto_op_set = CryptoOperationSet { context: None, operations: cmd_list };
+    let mut crypto_sets = Vec::new();
+    crypto_sets.push(crypto_op_set);
+    let mut op_result = hw_crypto_operations
+        .processCommandList(&mut crypto_sets)
+        .expect("couldn't process commands");
+    // Extracting the vector from the command list because of ownership
+    let CryptoOperation::DataOutput(OperationData::DataBuffer(encrypted_data)) =
+        crypto_sets.remove(0).operations.remove(0)
+    else {
+        panic!("not reachable, we created this object above on the test");
+    };
+    let context = op_result.remove(0).context;
+    // Separating the finish call on a different command set to test the returned context
+    let mut cmd_list = Vec::<CryptoOperation>::new();
+    let data_output = OperationData::DataBuffer(encrypted_data);
+    cmd_list.push(CryptoOperation::DataOutput(data_output));
+    cmd_list.push(CryptoOperation::Finish(None));
+    let crypto_op_set = CryptoOperationSet { context, operations: cmd_list };
+    let mut crypto_sets = Vec::new();
+    crypto_sets.push(crypto_op_set);
+    hw_crypto_operations.processCommandList(&mut crypto_sets).expect("couldn't process commands");
+    let CryptoOperation::DataOutput(OperationData::DataBuffer(encrypted_data)) =
+        crypto_sets.remove(0).operations.remove(0)
+    else {
+        panic!("not reachable, we created this object above on the test");
+    };
+
+    // Decrypting
+    let parameters = SymmetricCryptoParameters::Aes(AesCipherMode::Cbc(CipherModeParameters {
+        nonce: nonce.into(),
+    }));
+    let direction = SymmetricOperation::DECRYPT;
+    let sym_op_params = SymmetricOperationParameters { key: Some(key), direction, parameters };
+    let op_params = OperationParameters::SymmetricCrypto(sym_op_params);
+    let mut cmd_list = Vec::<CryptoOperation>::new();
+    let data_output = OperationData::DataBuffer(Vec::new());
+    cmd_list.push(CryptoOperation::DataOutput(data_output));
+    cmd_list.push(CryptoOperation::SetOperationParameters(op_params));
+    cmd_list.push(CryptoOperation::DataInput(OperationData::DataBuffer(encrypted_data)));
+    cmd_list.push(CryptoOperation::Finish(None));
+    let crypto_op_set = CryptoOperationSet { context: None, operations: cmd_list };
+    let mut crypto_sets = Vec::new();
+    crypto_sets.push(crypto_op_set);
+    hw_crypto_operations.processCommandList(&mut crypto_sets).expect("couldn't process commands");
+    // Extracting the vector from the command list because of ownership
+    let CryptoOperation::DataOutput(OperationData::DataBuffer(decrypted_data)) =
+        crypto_sets.remove(0).operations.remove(0)
+    else {
+        panic!("not reachable, we created this object above on the test");
+    };
+    let decrypted_msg =
+        String::from_utf8(decrypted_data).expect("couldn't decode received message");
+    assert_eq!(decrypted_msg, "string to be encrypted", "couldn't retrieve original message");
+}
+
+#[test]
+fn test_hwcrypto_key_operations_simple_hmac_test() {
+    let hw_crypto_key = hwcryptohal_vts_test::get_hwcryptokey()
+        .expect("Couldn't get back a hwcryptokey binder object");
+    let hw_crypto_operations = hw_crypto_key
+        .getHwCryptoOperations()
+        .expect("Couldn't get back a hwcryptokey operations binder object");
+    let clear_key = ExplicitKeyMaterial::Hmac(HmacKey::Sha256([0; 32]));
+    let policy = KeyPolicy {
+        usage: KeyUse::SIGN,
+        keyLifetime: KeyLifetime::PORTABLE,
+        keyPermissions: Vec::new(),
+        keyManagementKey: false,
+        keyType: KeyType::HMAC_SHA256,
+    };
+    let key = hw_crypto_key.importClearKey(&clear_key, &policy).expect("couldn't import clear key");
+
+    let hmac_parameters = HmacOperationParameters { key: Some(key.clone()) };
+    let op_parameters = OperationParameters::Hmac(hmac_parameters);
+    let mut cmd_list = Vec::<CryptoOperation>::new();
+    let data_output = OperationData::DataBuffer(Vec::new());
+    cmd_list.push(CryptoOperation::DataOutput(data_output));
+    cmd_list.push(CryptoOperation::SetOperationParameters(op_parameters));
+    let input_data = OperationData::DataBuffer("text to be mac'ed".as_bytes().to_vec());
+    cmd_list.push(CryptoOperation::DataInput(input_data));
+    cmd_list.push(CryptoOperation::Finish(None));
+    let crypto_op_set = CryptoOperationSet { context: None, operations: cmd_list };
+    let mut crypto_sets = Vec::new();
+    crypto_sets.push(crypto_op_set);
+    hw_crypto_operations.processCommandList(&mut crypto_sets).expect("couldn't process commands");
+    // Extracting the vector from the command list because of ownership
+    let CryptoOperation::DataOutput(OperationData::DataBuffer(mac)) =
+        crypto_sets.remove(0).operations.remove(0)
+    else {
+        panic!("not reachable, we created this object above on the test");
+    };
+
+    //Getting a second mac to compare
+    let hmac_parameters = HmacOperationParameters { key: Some(key) };
+    let op_parameters = OperationParameters::Hmac(hmac_parameters);
+    let mut cmd_list = Vec::<CryptoOperation>::new();
+    let data_output = OperationData::DataBuffer(Vec::new());
+    cmd_list.push(CryptoOperation::DataOutput(data_output));
+    cmd_list.push(CryptoOperation::SetOperationParameters(op_parameters));
+    let input_data = OperationData::DataBuffer("text to be mac'ed".as_bytes().to_vec());
+    cmd_list.push(CryptoOperation::DataInput(input_data));
+    cmd_list.push(CryptoOperation::Finish(None));
+    let crypto_op_set = CryptoOperationSet { context: None, operations: cmd_list };
+    let mut crypto_sets = Vec::new();
+    crypto_sets.push(crypto_op_set);
+    hw_crypto_operations.processCommandList(&mut crypto_sets).expect("couldn't process commands");
+    // Extracting the vector from the command list because of ownership
+    let CryptoOperation::DataOutput(OperationData::DataBuffer(mac2)) =
+        crypto_sets.remove(0).operations.remove(0)
+    else {
+        panic!("not reachable, we created this object above on the test");
+    };
+    assert_eq!(mac, mac2, "got a different mac");
+}
+
+#[test]
+fn test_hwcrypto_key_operations_aes_simple_cbcs_test_non_block_multiple() {
+    let hw_crypto_key = hwcryptohal_vts_test::get_hwcryptokey()
+        .expect("Couldn't get back a hwcryptokey binder object");
+    let hw_crypto_operations = hw_crypto_key
+        .getHwCryptoOperations()
+        .expect("Couldn't get back a hwcryptokey operations binder object");
+
+    let usage = KeyUse::ENCRYPT_DECRYPT;
+    let key_type = KeyType::AES_128_CBC_NO_PADDING;
+    let policy = KeyPolicy {
+        usage,
+        keyLifetime: KeyLifetime::PORTABLE,
+        keyPermissions: Vec::new(),
+        keyType: key_type,
+        keyManagementKey: false,
+    };
+    let clear_key = ExplicitKeyMaterial::Aes(AesKey::Aes128([0; 16]));
+    let key = hw_crypto_key.importClearKey(&clear_key, &policy).expect("couldn't import clear key");
+
+    let nonce = [0u8; 16];
+    let parameters = SymmetricCryptoParameters::Aes(AesCipherMode::Cbc(CipherModeParameters {
+        nonce: nonce.into(),
+    }));
+    let direction = SymmetricOperation::ENCRYPT;
+    let sym_op_params =
+        SymmetricOperationParameters { key: Some(key.clone()), direction, parameters };
+    let op_params = OperationParameters::SymmetricCrypto(sym_op_params);
+    let mut cmd_list = Vec::<CryptoOperation>::new();
+    let data_output = OperationData::DataBuffer(Vec::new());
+    cmd_list.push(CryptoOperation::DataOutput(data_output));
+    cmd_list.push(CryptoOperation::SetOperationParameters(op_params));
+    cmd_list.push(CryptoOperation::SetPattern(PatternParameters {
+        numberBlocksProcess: 1,
+        numberBlocksCopy: 0,
+    }));
+    let input_data =
+        OperationData::DataBuffer("encryption data.0123456789abcdef".as_bytes().to_vec());
+    cmd_list.push(CryptoOperation::DataInput(input_data));
+    let input_data =
+        OperationData::DataBuffer("fedcba98765432100123456789abcdef".as_bytes().to_vec());
+    cmd_list.push(CryptoOperation::DataInput(input_data));
+    let input_data = OperationData::DataBuffer("unencrypted".as_bytes().to_vec());
+    cmd_list.push(CryptoOperation::DataInput(input_data));
+    cmd_list.push(CryptoOperation::Finish(None));
+    let crypto_op_set = CryptoOperationSet { context: None, operations: cmd_list };
+    let mut crypto_sets = Vec::new();
+    crypto_sets.push(crypto_op_set);
+    hw_crypto_operations.processCommandList(&mut crypto_sets).expect("couldn't process commands");
+    let CryptoOperation::DataOutput(OperationData::DataBuffer(encrypted_data)) =
+        crypto_sets.remove(0).operations.remove(0)
+    else {
+        panic!("not reachable, we created this object above on the test");
+    };
+
+    let clear_encrypted_msg =
+        String::from_utf8(encrypted_data[encrypted_data.len() - "unencrypted".len()..].to_vec())
+            .expect("couldn't decode message");
+    assert_eq!(clear_encrypted_msg, "unencrypted");
+
+    // Decrypting
+    let parameters = SymmetricCryptoParameters::Aes(AesCipherMode::Cbc(CipherModeParameters {
+        nonce: nonce.into(),
+    }));
+    let direction = SymmetricOperation::DECRYPT;
+    let sym_op_params =
+        SymmetricOperationParameters { key: Some(key.clone()), direction, parameters };
+    let op_params = OperationParameters::SymmetricCrypto(sym_op_params);
+    let mut cmd_list = Vec::<CryptoOperation>::new();
+    let data_output = OperationData::DataBuffer(Vec::new());
+    cmd_list.push(CryptoOperation::DataOutput(data_output));
+    cmd_list.push(CryptoOperation::SetOperationParameters(op_params));
+    cmd_list.push(CryptoOperation::SetPattern(PatternParameters {
+        numberBlocksProcess: 1,
+        numberBlocksCopy: 0,
+    }));
+    cmd_list.push(CryptoOperation::DataInput(OperationData::DataBuffer(encrypted_data)));
+    cmd_list.push(CryptoOperation::Finish(None));
+    let crypto_op_set = CryptoOperationSet { context: None, operations: cmd_list };
+    let mut crypto_sets = Vec::new();
+    crypto_sets.push(crypto_op_set);
+    hw_crypto_operations.processCommandList(&mut crypto_sets).expect("couldn't process commands");
+    let CryptoOperation::DataOutput(OperationData::DataBuffer(decrypted_data)) =
+        crypto_sets.remove(0).operations.remove(0)
+    else {
+        panic!("not reachable, we created this object above on the test");
+    };
+    let decrypted_msg =
+        String::from_utf8(decrypted_data).expect("couldn't decode received message");
+    assert_eq!(
+        decrypted_msg,
+        "encryption data.0123456789abcdeffedcba9876543210\
+        0123456789abcdefunencrypted",
+        "couldn't retrieve original message"
+    );
+}
+
+#[test]
+fn test_hwcrypto_key_operations_aes_simple_all_encrypted_cbcs_test() {
+    let hw_crypto_key = hwcryptohal_vts_test::get_hwcryptokey()
+        .expect("Couldn't get back a hwcryptokey binder object");
+    let hw_crypto_operations = hw_crypto_key
+        .getHwCryptoOperations()
+        .expect("Couldn't get back a hwcryptokey operations binder object");
+
+    let usage = KeyUse::ENCRYPT_DECRYPT;
+    let key_type = KeyType::AES_128_CBC_NO_PADDING;
+    let policy = KeyPolicy {
+        usage,
+        keyLifetime: KeyLifetime::PORTABLE,
+        keyPermissions: Vec::new(),
+        keyType: key_type,
+        keyManagementKey: false,
+    };
+    let clear_key = ExplicitKeyMaterial::Aes(AesKey::Aes128([0; 16]));
+    let key = hw_crypto_key.importClearKey(&clear_key, &policy).expect("couldn't import clear key");
+
+    let nonce = [0u8; 16];
+    let parameters = SymmetricCryptoParameters::Aes(AesCipherMode::Cbc(CipherModeParameters {
+        nonce: nonce.into(),
+    }));
+    let direction = SymmetricOperation::ENCRYPT;
+    let sym_op_params =
+        SymmetricOperationParameters { key: Some(key.clone()), direction, parameters };
+    let op_params = OperationParameters::SymmetricCrypto(sym_op_params);
+    let mut cmd_list = Vec::<CryptoOperation>::new();
+    let data_output = OperationData::DataBuffer(Vec::new());
+    cmd_list.push(CryptoOperation::DataOutput(data_output));
+    cmd_list.push(CryptoOperation::SetOperationParameters(op_params));
+    cmd_list.push(CryptoOperation::SetPattern(PatternParameters {
+        numberBlocksProcess: 1,
+        numberBlocksCopy: 0,
+    }));
+    let input_data =
+        OperationData::DataBuffer("encryption data.0123456789abcdef".as_bytes().to_vec());
+    cmd_list.push(CryptoOperation::DataInput(input_data));
+    let input_data =
+        OperationData::DataBuffer("fedcba98765432100123456789abcdef".as_bytes().to_vec());
+    cmd_list.push(CryptoOperation::DataInput(input_data));
+    cmd_list.push(CryptoOperation::Finish(None));
+    let crypto_op_set = CryptoOperationSet { context: None, operations: cmd_list };
+    let mut crypto_sets = Vec::new();
+    crypto_sets.push(crypto_op_set);
+    hw_crypto_operations.processCommandList(&mut crypto_sets).expect("couldn't process commands");
+
+    let CryptoOperation::DataOutput(OperationData::DataBuffer(encrypted_data)) =
+        crypto_sets.remove(0).operations.remove(0)
+    else {
+        panic!("not reachable, we created this object above on the test");
+    };
+
+    // Checking that encrypting with patter 0,0 is equivalent to pattern 1,0
+    let parameters = SymmetricCryptoParameters::Aes(AesCipherMode::Cbc(CipherModeParameters {
+        nonce: nonce.into(),
+    }));
+    let direction = SymmetricOperation::ENCRYPT;
+    let sym_op_params =
+        SymmetricOperationParameters { key: Some(key.clone()), direction, parameters };
+    let op_params = OperationParameters::SymmetricCrypto(sym_op_params);
+    let mut cmd_list = Vec::<CryptoOperation>::new();
+    let data_output = OperationData::DataBuffer(Vec::new());
+    cmd_list.push(CryptoOperation::DataOutput(data_output));
+    cmd_list.push(CryptoOperation::SetOperationParameters(op_params));
+    cmd_list.push(CryptoOperation::SetPattern(PatternParameters {
+        numberBlocksProcess: 0,
+        numberBlocksCopy: 0,
+    }));
+    let input_data =
+        OperationData::DataBuffer("encryption data.0123456789abcdef".as_bytes().to_vec());
+    cmd_list.push(CryptoOperation::DataInput(input_data));
+    let input_data =
+        OperationData::DataBuffer("fedcba98765432100123456789abcdef".as_bytes().to_vec());
+    cmd_list.push(CryptoOperation::DataInput(input_data));
+    cmd_list.push(CryptoOperation::Finish(None));
+    let crypto_op_set = CryptoOperationSet { context: None, operations: cmd_list };
+    let mut crypto_sets = Vec::new();
+    crypto_sets.push(crypto_op_set);
+    hw_crypto_operations.processCommandList(&mut crypto_sets).expect("couldn't process commands");
+    let CryptoOperation::DataOutput(OperationData::DataBuffer(encrypted_data1)) =
+        crypto_sets.remove(0).operations.remove(0)
+    else {
+        panic!("not reachable, we created this object above on the test");
+    };
+    assert_eq!(encrypted_data, encrypted_data1, "encrypted data should match");
+
+    // Decrypting
+    let parameters = SymmetricCryptoParameters::Aes(AesCipherMode::Cbc(CipherModeParameters {
+        nonce: nonce.into(),
+    }));
+    let direction = SymmetricOperation::DECRYPT;
+    let sym_op_params =
+        SymmetricOperationParameters { key: Some(key.clone()), direction, parameters };
+    let op_params = OperationParameters::SymmetricCrypto(sym_op_params);
+    let mut cmd_list = Vec::<CryptoOperation>::new();
+    let data_output = OperationData::DataBuffer(Vec::new());
+    cmd_list.push(CryptoOperation::DataOutput(data_output));
+    cmd_list.push(CryptoOperation::SetOperationParameters(op_params));
+    cmd_list.push(CryptoOperation::DataInput(OperationData::DataBuffer(encrypted_data)));
+    cmd_list.push(CryptoOperation::Finish(None));
+    let crypto_op_set = CryptoOperationSet { context: None, operations: cmd_list };
+    let mut crypto_sets = Vec::new();
+    crypto_sets.push(crypto_op_set);
+    hw_crypto_operations.processCommandList(&mut crypto_sets).expect("couldn't process commands");
+
+    let CryptoOperation::DataOutput(OperationData::DataBuffer(decrypted_data)) =
+        crypto_sets.remove(0).operations.remove(0)
+    else {
+        panic!("not reachable, we created this object above on the test");
+    };
+    let decrypted_msg =
+        String::from_utf8(decrypted_data).expect("couldn't decode received message");
+    assert_eq!(
+        decrypted_msg,
+        "encryption data.0123456789abcdeffedcba9876543210\
+        0123456789abcdef",
+        "couldn't retrieve original message"
+    );
+}
+
+#[test]
+fn check_cbcs_wrong_key_types() {
+    let hw_crypto_key = hwcryptohal_vts_test::get_hwcryptokey()
+        .expect("Couldn't get back a hwcryptokey binder object");
+    let hw_crypto_operations = hw_crypto_key
+        .getHwCryptoOperations()
+        .expect("Couldn't get back a hwcryptokey operations binder object");
+
+    let usage = KeyUse::ENCRYPT_DECRYPT;
+    let key_type = KeyType::AES_128_CBC_PKCS7_PADDING;
+    let policy = KeyPolicy {
+        usage,
+        keyLifetime: KeyLifetime::PORTABLE,
+        keyPermissions: Vec::new(),
+        keyType: key_type,
+        keyManagementKey: false,
+    };
+    let clear_key = ExplicitKeyMaterial::Aes(AesKey::Aes128([0; 16]));
+    let key = hw_crypto_key.importClearKey(&clear_key, &policy).expect("couldn't import clear key");
+
+    let nonce = [0u8; 16];
+    let parameters = SymmetricCryptoParameters::Aes(AesCipherMode::Cbc(CipherModeParameters {
+        nonce: nonce.into(),
+    }));
+    let direction = SymmetricOperation::ENCRYPT;
+    let sym_op_params = SymmetricOperationParameters { key: Some(key), direction, parameters };
+    let op_params = OperationParameters::SymmetricCrypto(sym_op_params);
+    let mut cmd_list = Vec::<CryptoOperation>::new();
+    let data_output = OperationData::DataBuffer(Vec::new());
+    cmd_list.push(CryptoOperation::DataOutput(data_output));
+    cmd_list.push(CryptoOperation::SetOperationParameters(op_params));
+    cmd_list.push(CryptoOperation::SetPattern(PatternParameters {
+        numberBlocksProcess: 1,
+        numberBlocksCopy: 9,
+    }));
+    let crypto_op_set = CryptoOperationSet { context: None, operations: cmd_list };
+    let mut crypto_sets = Vec::new();
+    crypto_sets.push(crypto_op_set);
+    let process_result = hw_crypto_operations.processCommandList(&mut crypto_sets);
+    assert!(process_result.is_err(), "Should not be able to use cbcs mode with this key type");
+
+    let policy = KeyPolicy {
+        usage,
+        keyLifetime: KeyLifetime::PORTABLE,
+        keyPermissions: Vec::new(),
+        keyType: KeyType::AES_256_CBC_NO_PADDING,
+        keyManagementKey: false,
+    };
+    let clear_key = ExplicitKeyMaterial::Aes(AesKey::Aes256([0; 32]));
+    let key = hw_crypto_key.importClearKey(&clear_key, &policy).expect("couldn't import clear key");
+    let parameters = SymmetricCryptoParameters::Aes(AesCipherMode::Cbc(CipherModeParameters {
+        nonce: nonce.into(),
+    }));
+    let sym_op_params = SymmetricOperationParameters { key: Some(key), direction, parameters };
+    let op_params = OperationParameters::SymmetricCrypto(sym_op_params);
+    let mut cmd_list = Vec::<CryptoOperation>::new();
+    let data_output = OperationData::DataBuffer(Vec::new());
+    cmd_list.push(CryptoOperation::DataOutput(data_output));
+    cmd_list.push(CryptoOperation::SetOperationParameters(op_params));
+    cmd_list.push(CryptoOperation::SetPattern(PatternParameters {
+        numberBlocksProcess: 1,
+        numberBlocksCopy: 9,
+    }));
+    let crypto_op_set = CryptoOperationSet { context: None, operations: cmd_list };
+    let mut crypto_sets = Vec::new();
+    crypto_sets.push(crypto_op_set);
+    let process_result = hw_crypto_operations.processCommandList(&mut crypto_sets);
+
+    assert!(process_result.is_err(), "Should not be able to use cbcs mode with this key type");
+}
+
+#[test]
+fn aes_simple_cbcs_test() {
+    let hw_crypto_key = hwcryptohal_vts_test::get_hwcryptokey()
+        .expect("Couldn't get back a hwcryptokey binder object");
+    let hw_crypto_operations = hw_crypto_key
+        .getHwCryptoOperations()
+        .expect("Couldn't get back a hwcryptokey operations binder object");
+
+    let usage = KeyUse::ENCRYPT_DECRYPT;
+    let key_type = KeyType::AES_128_CBC_NO_PADDING;
+    let policy = KeyPolicy {
+        usage,
+        keyLifetime: KeyLifetime::PORTABLE,
+        keyPermissions: Vec::new(),
+        keyType: key_type,
+        keyManagementKey: false,
+    };
+    let clear_key = ExplicitKeyMaterial::Aes(AesKey::Aes128([0; 16]));
+    let key = hw_crypto_key.importClearKey(&clear_key, &policy).expect("couldn't import clear key");
+
+    let nonce = [0u8; 16];
+    let parameters = SymmetricCryptoParameters::Aes(AesCipherMode::Cbc(CipherModeParameters {
+        nonce: nonce.into(),
+    }));
+    let direction = SymmetricOperation::ENCRYPT;
+    let sym_op_params =
+        SymmetricOperationParameters { key: Some(key.clone()), direction, parameters };
+    let op_params = OperationParameters::SymmetricCrypto(sym_op_params);
+    let mut cmd_list = Vec::<CryptoOperation>::new();
+    let data_output = OperationData::DataBuffer(Vec::new());
+    cmd_list.push(CryptoOperation::DataOutput(data_output));
+    cmd_list.push(CryptoOperation::SetOperationParameters(op_params));
+    cmd_list.push(CryptoOperation::SetPattern(PatternParameters {
+        numberBlocksProcess: 1,
+        numberBlocksCopy: 9,
+    }));
+    let input_data =
+        OperationData::DataBuffer("encryption data.0123456789abcdef".as_bytes().to_vec());
+    cmd_list.push(CryptoOperation::DataInput(input_data));
+    let input_data =
+        OperationData::DataBuffer("fedcba98765432100123456789abcdef".as_bytes().to_vec());
+    cmd_list.push(CryptoOperation::DataInput(input_data));
+    let input_data =
+        OperationData::DataBuffer("fedcba98765432100123456789abcdef".as_bytes().to_vec());
+    cmd_list.push(CryptoOperation::DataInput(input_data));
+    let input_data =
+        OperationData::DataBuffer("fedcba98765432100123456789abcdef".as_bytes().to_vec());
+    cmd_list.push(CryptoOperation::DataInput(input_data));
+    let input_data = OperationData::DataBuffer(
+        "fedcba98765432100123456789abcdefProtectedSection".as_bytes().to_vec(),
+    );
+    cmd_list.push(CryptoOperation::DataInput(input_data));
+    cmd_list.push(CryptoOperation::Finish(None));
+    let crypto_op_set = CryptoOperationSet { context: None, operations: cmd_list };
+    let mut crypto_sets = Vec::new();
+    crypto_sets.push(crypto_op_set);
+    hw_crypto_operations.processCommandList(&mut crypto_sets).expect("couldn't process commands");
+
+    let CryptoOperation::DataOutput(OperationData::DataBuffer(encrypted_data)) =
+        crypto_sets.remove(0).operations.remove(0)
+    else {
+        panic!("not reachable, we created this object above on the test");
+    };
+    let clear_encrypted_msg =
+        String::from_utf8(encrypted_data[16..encrypted_data.len() - 16].to_vec())
+            .expect("couldn't decode received message");
+    assert_eq!(
+        clear_encrypted_msg,
+        "0123456789abcdeffedcba98765432100123456789abcdeffedcba9876543210\
+        0123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdef",
+        "couldn't retrieve clear portion"
+    );
+
+    // Decrypting
+    let parameters = SymmetricCryptoParameters::Aes(AesCipherMode::Cbc(CipherModeParameters {
+        nonce: nonce.into(),
+    }));
+    let direction = SymmetricOperation::DECRYPT;
+    let sym_op_params =
+        SymmetricOperationParameters { key: Some(key.clone()), direction, parameters };
+    let op_params = OperationParameters::SymmetricCrypto(sym_op_params);
+    let mut cmd_list = Vec::<CryptoOperation>::new();
+    let data_output = OperationData::DataBuffer(Vec::new());
+    cmd_list.push(CryptoOperation::DataOutput(data_output));
+    cmd_list.push(CryptoOperation::SetOperationParameters(op_params));
+    cmd_list.push(CryptoOperation::SetPattern(PatternParameters {
+        numberBlocksProcess: 1,
+        numberBlocksCopy: 9,
+    }));
+    cmd_list.push(CryptoOperation::DataInput(OperationData::DataBuffer(encrypted_data)));
+    cmd_list.push(CryptoOperation::Finish(None));
+    let crypto_op_set = CryptoOperationSet { context: None, operations: cmd_list };
+    let mut crypto_sets = Vec::new();
+    crypto_sets.push(crypto_op_set);
+    hw_crypto_operations.processCommandList(&mut crypto_sets).expect("couldn't process commands");
+
+    let CryptoOperation::DataOutput(OperationData::DataBuffer(decrypted_data)) =
+        crypto_sets.remove(0).operations.remove(0)
+    else {
+        panic!("not reachable, we created this object above on the test");
+    };
+    let decrypted_msg =
+        String::from_utf8(decrypted_data).expect("couldn't decode received message");
+    assert_eq!(
+        decrypted_msg,
+        "encryption data.0123456789abcdeffedcba9876543210\
+        0123456789abcdeffedcba98765432100123456789abcdeffedcba9876543210\
+        0123456789abcdeffedcba98765432100123456789abcdefProtectedSection",
+        "couldn't retrieve original message"
+    );
+}
diff --git a/security/see/hwcrypto/aidl/vts/functional/lib.rs b/security/see/hwcrypto/aidl/vts/functional/lib.rs
index 81ae3fa..465dde7 100644
--- a/security/see/hwcrypto/aidl/vts/functional/lib.rs
+++ b/security/see/hwcrypto/aidl/vts/functional/lib.rs
@@ -17,61 +17,11 @@
 //! VTS test library for HwCrypto functionality.
 //! It provides the base clases necessaries to write HwCrypto VTS tests
 
-#[cfg(target_arch = "x86_64")]
-use anyhow::Context;
 use anyhow::Result;
-#[cfg(target_arch = "x86_64")]
-use binder::{ExceptionCode, FromIBinder, IntoBinderResult, ParcelFileDescriptor};
-#[cfg(target_arch = "x86_64")]
-use rpcbinder::RpcSession;
-#[cfg(target_arch = "x86_64")]
-use vsock::VsockStream;
-#[cfg(target_arch = "x86_64")]
-use std::os::fd::{FromRawFd, IntoRawFd};
-#[cfg(target_arch = "x86_64")]
-use std::fs::File;
-#[cfg(target_arch = "x86_64")]
-use std::io::Read;
-#[cfg(target_arch = "x86_64")]
-use rustutils::system_properties;
-#[cfg(target_arch = "aarch64")]
 use android_hardware_security_see_hwcrypto::aidl::android::hardware::security::see::hwcrypto::IHwCryptoKey::BpHwCryptoKey;
 use android_hardware_security_see_hwcrypto::aidl::android::hardware::security::see::hwcrypto::IHwCryptoKey::IHwCryptoKey;
 
-#[cfg(target_arch = "x86_64")]
-const HWCRYPTO_SERVICE_PORT: u32 = 4;
-
-/// Local function to connect to service
-#[cfg(target_arch = "x86_64")]
-pub fn connect_service<T: FromIBinder + ?Sized>(
-    cid: u32,
-    port: u32,
-) -> Result<binder::Strong<T>, binder::StatusCode> {
-    RpcSession::new().setup_preconnected_client(|| {
-        let mut stream = VsockStream::connect_with_cid_port(cid, port).ok()?;
-        let mut buffer = [0];
-        let _ = stream.read(&mut buffer);
-        // SAFETY: ownership is transferred from stream to f
-        let f = unsafe { File::from_raw_fd(stream.into_raw_fd()) };
-        Some(ParcelFileDescriptor::new(f).into_raw_fd())
-    })
-}
-
-/// Get a HwCryptoKey binder service object using a direct vsock connection
-#[cfg(target_arch = "x86_64")]
-pub fn get_hwcryptokey() -> Result<binder::Strong<dyn IHwCryptoKey>, binder::Status> {
-    let cid = system_properties::read("trusty.test_vm.vm_cid")
-        .context("couldn't get vm cid")
-        .or_binder_exception(ExceptionCode::ILLEGAL_STATE)?
-        .ok_or(ExceptionCode::ILLEGAL_STATE)?
-        .parse::<u32>()
-        .context("couldn't parse vm cid")
-        .or_binder_exception(ExceptionCode::ILLEGAL_ARGUMENT)?;
-    Ok(connect_service(cid, HWCRYPTO_SERVICE_PORT)?)
-}
-
 /// Get a HwCryptoKey binder service object using the service manager
-#[cfg(target_arch = "aarch64")]
 pub fn get_hwcryptokey() -> Result<binder::Strong<dyn IHwCryptoKey>, binder::Status> {
     let interface_name = <BpHwCryptoKey as IHwCryptoKey>::get_descriptor().to_owned() + "/default";
     Ok(binder::get_interface(&interface_name)?)
diff --git a/security/see/hwcrypto/default/hwcryptokeyimpl.h b/security/see/hwcrypto/default/hwcryptokeyimpl.h
index 19be8b4..7d3ade7 100644
--- a/security/see/hwcrypto/default/hwcryptokeyimpl.h
+++ b/security/see/hwcrypto/default/hwcryptokeyimpl.h
@@ -46,30 +46,33 @@
 
     ndk::ScopedAStatus deriveCurrentDicePolicyBoundKey(
             const ndk_hwcrypto::IHwCryptoKey::DiceBoundDerivationKey& derivationKey,
-            ndk_hwcrypto::IHwCryptoKey::DiceCurrentBoundKeyResult* aidl_return);
+            ndk_hwcrypto::IHwCryptoKey::DiceCurrentBoundKeyResult* aidl_return) override;
 
     ndk::ScopedAStatus deriveDicePolicyBoundKey(
             const ndk_hwcrypto::IHwCryptoKey::DiceBoundDerivationKey& derivationKey,
             const ::std::vector<uint8_t>& dicePolicyForKeyVersion,
-            ndk_hwcrypto::IHwCryptoKey::DiceBoundKeyResult* aidl_return);
+            ndk_hwcrypto::IHwCryptoKey::DiceBoundKeyResult* aidl_return) override;
     ndk::ScopedAStatus deriveKey(const ndk_hwcrypto::IHwCryptoKey::DerivedKeyParameters& parameters,
-                                 ndk_hwcrypto::IHwCryptoKey::DerivedKey* aidl_return);
+                                 ndk_hwcrypto::IHwCryptoKey::DerivedKey* aidl_return) override;
 
     ndk::ScopedAStatus getHwCryptoOperations(
-            std::shared_ptr<ndk_hwcrypto::IHwCryptoOperations>* aidl_return);
+            std::shared_ptr<ndk_hwcrypto::IHwCryptoOperations>* aidl_return) override;
 
-    ndk::ScopedAStatus importClearKey(const ndk_hwcrypto::types::ExplicitKeyMaterial& keyMaterial,
-                                      const ndk_hwcrypto::KeyPolicy& newKeyPolicy,
-                                      std::shared_ptr<ndk_hwcrypto::IOpaqueKey>* aidl_return);
+    ndk::ScopedAStatus importClearKey(
+            const ndk_hwcrypto::types::ExplicitKeyMaterial& keyMaterial,
+            const ndk_hwcrypto::KeyPolicy& newKeyPolicy,
+            std::shared_ptr<ndk_hwcrypto::IOpaqueKey>* aidl_return) override;
 
-    ndk::ScopedAStatus getCurrentDicePolicy(std::vector<uint8_t>* aidl_return);
+    ndk::ScopedAStatus getCurrentDicePolicy(std::vector<uint8_t>* aidl_return) override;
 
-    ndk::ScopedAStatus keyTokenImport(const ndk_hwcrypto::types::OpaqueKeyToken& requestedKey,
-                                      const ::std::vector<uint8_t>& sealingDicePolicy,
-                                      std::shared_ptr<ndk_hwcrypto::IOpaqueKey>* aidl_return);
+    ndk::ScopedAStatus keyTokenImport(
+            const ndk_hwcrypto::types::OpaqueKeyToken& requestedKey,
+            const ::std::vector<uint8_t>& sealingDicePolicy,
+            std::shared_ptr<ndk_hwcrypto::IOpaqueKey>* aidl_return) override;
 
-    ndk::ScopedAStatus getKeyslotData(ndk_hwcrypto::IHwCryptoKey::KeySlot slotId,
-                                      std::shared_ptr<ndk_hwcrypto::IOpaqueKey>* aidl_return);
+    ndk::ScopedAStatus getKeyslotData(
+            ndk_hwcrypto::IHwCryptoKey::KeySlot slotId,
+            std::shared_ptr<ndk_hwcrypto::IOpaqueKey>* aidl_return) override;
 };
 
 template <typename LHP, typename RHP>
@@ -79,9 +82,10 @@
     policy.keyLifetime = static_cast<decltype(policy.keyLifetime)>(policyToConvert.keyLifetime);
     policy.keyType = static_cast<decltype(policy.keyType)>(policyToConvert.keyType);
     policy.keyManagementKey = policyToConvert.keyManagementKey;
+    policy.keyPermissions.reserve(policyToConvert.keyPermissions.size());
     for (auto permission : policyToConvert.keyPermissions) {
         policy.keyPermissions.push_back(
-                std::move(reinterpret_cast<decltype(policy.keyPermissions[0])>(permission)));
+                std::move(static_cast<decltype(policy.keyPermissions)::value_type>(permission)));
     }
     return policy;
 }
diff --git a/security/see/hwcrypto/default/hwcryptolib.cpp b/security/see/hwcrypto/default/hwcryptolib.cpp
index b168707..5babc23 100644
--- a/security/see/hwcrypto/default/hwcryptolib.cpp
+++ b/security/see/hwcrypto/default/hwcryptolib.cpp
@@ -115,11 +115,14 @@
 class HwCryptoOperationContextNdk : public ndk_hwcrypto::BnCryptoOperationContext {
   private:
     sp<cpp_hwcrypto::ICryptoOperationContext> mContext;
+    std::weak_ptr<ndk_hwcrypto::ICryptoOperationContext> self;
 
   public:
     HwCryptoOperationContextNdk(sp<cpp_hwcrypto::ICryptoOperationContext> operations)
         : mContext(std::move(operations)) {}
 
+    ~HwCryptoOperationContextNdk() { contextMapping.erase(self); }
+
     static std::shared_ptr<HwCryptoOperationContextNdk> Create(
             sp<cpp_hwcrypto::ICryptoOperationContext> operations) {
         if (operations == nullptr) {
@@ -132,18 +135,18 @@
             LOG(ERROR) << "failed to allocate HwCryptoOperationContext";
             return nullptr;
         }
+        contextNdk->self = contextNdk;
         return contextNdk;
     }
 };
 
-// TODO: Check refactoring opportunities like returning a Result<cpp_hwcrypto::types::OperationData>
-//       once we add the code that uses this function.
-Result<void> setOperationData(const ndk_hwcrypto::types::OperationData& ndkOperationData,
-                              cpp_hwcrypto::types::OperationData* cppOperationData) {
+std::optional<cpp_hwcrypto::types::OperationData> convertOperationData(
+        const ndk_hwcrypto::types::OperationData& ndkOperationData) {
+    cpp_hwcrypto::types::OperationData cppOperationData = cpp_hwcrypto::types::OperationData();
     cpp_hwcrypto::types::MemoryBufferReference cppMemBuffRef;
     switch (ndkOperationData.getTag()) {
         case ndk_hwcrypto::types::OperationData::dataBuffer:
-            cppOperationData->set<cpp_hwcrypto::types::OperationData::dataBuffer>(
+            cppOperationData.set<cpp_hwcrypto::types::OperationData::dataBuffer>(
                     ndkOperationData.get<ndk_hwcrypto::types::OperationData::dataBuffer>());
             break;
         case ndk_hwcrypto::types::OperationData::memoryBufferReference:
@@ -155,14 +158,223 @@
                     ndkOperationData
                             .get<ndk_hwcrypto::types::OperationData::memoryBufferReference>()
                             .sizeBytes;
-            cppOperationData->set<cpp_hwcrypto::types::OperationData::memoryBufferReference>(
+            cppOperationData.set<cpp_hwcrypto::types::OperationData::memoryBufferReference>(
                     std::move(cppMemBuffRef));
             break;
         default:
-            // This shouldn't happen with the current definitions
-            return ErrnoError() << "received unknown operation data type";
+            LOG(ERROR) << "received unknown operation data type";
+            return std::nullopt;
     }
-    return {};
+    return cppOperationData;
+}
+
+std::optional<cpp_hwcrypto::PatternParameters> convertPatternParameters(
+        const ndk_hwcrypto::PatternParameters& ndkpatternParameters) {
+    int64_t numberBlocksProcess = ndkpatternParameters.numberBlocksProcess;
+    int64_t numberBlocksCopy = ndkpatternParameters.numberBlocksCopy;
+    if ((numberBlocksProcess < 0) || (numberBlocksCopy < 0)) {
+        LOG(ERROR) << "received invalid pattern parameters";
+        return std::nullopt;
+    }
+    cpp_hwcrypto::PatternParameters patternParameters = cpp_hwcrypto::PatternParameters();
+    patternParameters.numberBlocksProcess = numberBlocksProcess;
+    patternParameters.numberBlocksCopy = numberBlocksCopy;
+    return patternParameters;
+}
+
+std::optional<cpp_hwcrypto::types::SymmetricOperation> convertSymmetricOperation(
+        const ndk_hwcrypto::types::SymmetricOperation& ndkSymmetricOperation) {
+    cpp_hwcrypto::types::SymmetricOperation symmetricOperation =
+            cpp_hwcrypto::types::SymmetricOperation();
+    switch (ndkSymmetricOperation) {
+        case ndk_hwcrypto::types::SymmetricOperation::ENCRYPT:
+            symmetricOperation = cpp_hwcrypto::types::SymmetricOperation::ENCRYPT;
+            break;
+        case ndk_hwcrypto::types::SymmetricOperation::DECRYPT:
+            symmetricOperation = cpp_hwcrypto::types::SymmetricOperation::DECRYPT;
+            break;
+        default:
+            LOG(ERROR) << "invalid symmetric operation type";
+            return std::nullopt;
+    }
+    return symmetricOperation;
+}
+
+cpp_hwcrypto::types::CipherModeParameters convertSymmetricModeParameters(
+        const ndk_hwcrypto::types::CipherModeParameters& ndkcipherModeParameters) {
+    cpp_hwcrypto::types::CipherModeParameters cipherModeParameters =
+            cpp_hwcrypto::types::CipherModeParameters();
+    cipherModeParameters.nonce = ndkcipherModeParameters.nonce;
+    return cipherModeParameters;
+}
+
+cpp_hwcrypto::types::AesGcmMode::AesGcmModeParameters convertSymmetricModeParameters(
+        const ndk_hwcrypto::types::AesGcmMode::AesGcmModeParameters& ndkgcmModeParameters) {
+    cpp_hwcrypto::types::AesGcmMode::AesGcmModeParameters gcmModeParameters =
+            cpp_hwcrypto::types::AesGcmMode::AesGcmModeParameters();
+    gcmModeParameters.nonce = ndkgcmModeParameters.nonce;
+    return gcmModeParameters;
+}
+
+std::optional<cpp_hwcrypto::OperationParameters> convertOperationParameters(
+        const ndk_hwcrypto::OperationParameters& ndkOperationParameters) {
+    cpp_hwcrypto::OperationParameters operationParameters = cpp_hwcrypto::OperationParameters();
+    sp<cpp_hwcrypto::IOpaqueKey> opaqueKey;
+    cpp_hwcrypto::types::HmacOperationParameters hmacParameters =
+            cpp_hwcrypto::types::HmacOperationParameters();
+    std::optional<cpp_hwcrypto::types::SymmetricOperation> cppSymmetricOperation;
+    cpp_hwcrypto::types::CipherModeParameters cipherModeParameters;
+    cpp_hwcrypto::types::AesCipherMode cppAesCipherMode = cpp_hwcrypto::types::AesCipherMode();
+    cpp_hwcrypto::types::SymmetricOperationParameters cppSymmetricOperationParameters =
+            cpp_hwcrypto::types::SymmetricOperationParameters();
+    cpp_hwcrypto::types::SymmetricAuthOperationParameters cppSymmetricAuthOperationParameters =
+            cpp_hwcrypto::types::SymmetricAuthOperationParameters();
+    cpp_hwcrypto::types::AesGcmMode::AesGcmModeParameters cppAesGcmModeParameters =
+            cpp_hwcrypto::types::AesGcmMode::AesGcmModeParameters();
+    cpp_hwcrypto::types::AesGcmMode cppAesGcmMode = cpp_hwcrypto::types::AesGcmMode();
+    switch (ndkOperationParameters.getTag()) {
+        case ndk_hwcrypto::OperationParameters::symmetricAuthCrypto:
+            opaqueKey = retrieveCppBinder<cpp_hwcrypto::IOpaqueKey, ndk_hwcrypto::IOpaqueKey,
+                                          keyMapping>(
+                    ndkOperationParameters
+                            .get<ndk_hwcrypto::OperationParameters::symmetricAuthCrypto>()
+                            .key);
+            if (!opaqueKey) {
+                LOG(ERROR) << "couldn't get aes key";
+                return std::nullopt;
+            }
+            cppSymmetricAuthOperationParameters.key = std::move(opaqueKey);
+            cppSymmetricOperation = convertSymmetricOperation(
+                    ndkOperationParameters
+                            .get<ndk_hwcrypto::OperationParameters::symmetricAuthCrypto>()
+                            .direction);
+            if (!cppSymmetricOperation.has_value()) {
+                LOG(ERROR) << "couldn't get aes direction";
+                return std::nullopt;
+            }
+            cppSymmetricAuthOperationParameters.direction =
+                    std::move(cppSymmetricOperation.value());
+            switch (ndkOperationParameters
+                            .get<ndk_hwcrypto::OperationParameters::symmetricAuthCrypto>()
+                            .parameters.getTag()) {
+                case ndk_hwcrypto::types::SymmetricAuthCryptoParameters::aes:
+                    switch (ndkOperationParameters
+                                    .get<ndk_hwcrypto::OperationParameters::symmetricAuthCrypto>()
+                                    .parameters
+                                    .get<ndk_hwcrypto::types::SymmetricAuthCryptoParameters::aes>()
+                                    .getTag()) {
+                        case ndk_hwcrypto::types::AesGcmMode::gcmTag16:
+                            cppAesGcmModeParameters = convertSymmetricModeParameters(
+                                    ndkOperationParameters
+                                            .get<ndk_hwcrypto::OperationParameters::
+                                                         symmetricAuthCrypto>()
+                                            .parameters
+                                            .get<ndk_hwcrypto::types::
+                                                         SymmetricAuthCryptoParameters::aes>()
+                                            .get<ndk_hwcrypto::types::AesGcmMode::gcmTag16>());
+                            cppAesGcmMode.set<cpp_hwcrypto::types::AesGcmMode::gcmTag16>(
+                                    std::move(cppAesGcmModeParameters));
+                            cppSymmetricAuthOperationParameters.parameters
+                                    .set<cpp_hwcrypto::types::SymmetricAuthCryptoParameters::aes>(
+                                            std::move(cppAesGcmMode));
+                            break;
+                        default:
+                            LOG(ERROR) << "received invalid aes gcm parameters";
+                            return std::nullopt;
+                    }
+                    break;
+                default:
+                    LOG(ERROR) << "received invalid symmetric auth crypto parameters";
+                    return std::nullopt;
+            }
+            operationParameters.set<cpp_hwcrypto::OperationParameters::symmetricAuthCrypto>(
+                    std::move(cppSymmetricAuthOperationParameters));
+            break;
+        case ndk_hwcrypto::OperationParameters::symmetricCrypto:
+            opaqueKey = retrieveCppBinder<cpp_hwcrypto::IOpaqueKey, ndk_hwcrypto::IOpaqueKey,
+                                          keyMapping>(
+                    ndkOperationParameters.get<ndk_hwcrypto::OperationParameters::symmetricCrypto>()
+                            .key);
+            if (!opaqueKey) {
+                LOG(ERROR) << "couldn't get aes key";
+                return std::nullopt;
+            }
+            cppSymmetricOperationParameters.key = std::move(opaqueKey);
+            cppSymmetricOperation = convertSymmetricOperation(
+                    ndkOperationParameters.get<ndk_hwcrypto::OperationParameters::symmetricCrypto>()
+                            .direction);
+            if (!cppSymmetricOperation.has_value()) {
+                LOG(ERROR) << "couldn't get aes direction";
+                return std::nullopt;
+            }
+            cppSymmetricOperationParameters.direction = std::move(cppSymmetricOperation.value());
+            switch (ndkOperationParameters.get<ndk_hwcrypto::OperationParameters::symmetricCrypto>()
+                            .parameters.getTag()) {
+                case ndk_hwcrypto::types::SymmetricCryptoParameters::aes:
+                    switch (ndkOperationParameters
+                                    .get<ndk_hwcrypto::OperationParameters::symmetricCrypto>()
+                                    .parameters
+                                    .get<ndk_hwcrypto::types::SymmetricCryptoParameters::aes>()
+                                    .getTag()) {
+                        case ndk_hwcrypto::types::AesCipherMode::cbc:
+                            cipherModeParameters = convertSymmetricModeParameters(
+                                    ndkOperationParameters
+                                            .get<ndk_hwcrypto::OperationParameters::
+                                                         symmetricCrypto>()
+                                            .parameters
+                                            .get<ndk_hwcrypto::types::SymmetricCryptoParameters::
+                                                         aes>()
+                                            .get<ndk_hwcrypto::types::AesCipherMode::cbc>());
+                            cppAesCipherMode.set<cpp_hwcrypto::types::AesCipherMode::cbc>(
+                                    std::move(cipherModeParameters));
+                            cppSymmetricOperationParameters.parameters
+                                    .set<cpp_hwcrypto::types::SymmetricCryptoParameters::aes>(
+                                            std::move(cppAesCipherMode));
+                            break;
+                        case ndk_hwcrypto::types::AesCipherMode::ctr:
+                            cipherModeParameters = convertSymmetricModeParameters(
+                                    ndkOperationParameters
+                                            .get<ndk_hwcrypto::OperationParameters::
+                                                         symmetricCrypto>()
+                                            .parameters
+                                            .get<ndk_hwcrypto::types::SymmetricCryptoParameters::
+                                                         aes>()
+                                            .get<ndk_hwcrypto::types::AesCipherMode::ctr>());
+                            cppAesCipherMode.set<cpp_hwcrypto::types::AesCipherMode::ctr>(
+                                    std::move(cipherModeParameters));
+                            cppSymmetricOperationParameters.parameters
+                                    .set<cpp_hwcrypto::types::SymmetricCryptoParameters::aes>(
+                                            std::move(cppAesCipherMode));
+                            break;
+                        default:
+                            LOG(ERROR) << "received invalid aes parameters";
+                            return std::nullopt;
+                    }
+                    break;
+                default:
+                    LOG(ERROR) << "received invalid symmetric crypto parameters";
+                    return std::nullopt;
+            }
+            operationParameters.set<cpp_hwcrypto::OperationParameters::symmetricCrypto>(
+                    std::move(cppSymmetricOperationParameters));
+            break;
+        case ndk_hwcrypto::OperationParameters::hmac:
+            opaqueKey = retrieveCppBinder<cpp_hwcrypto::IOpaqueKey, ndk_hwcrypto::IOpaqueKey,
+                                          keyMapping>(
+                    ndkOperationParameters.get<ndk_hwcrypto::OperationParameters::hmac>().key);
+            if (!opaqueKey) {
+                LOG(ERROR) << "couldn't get hmac key";
+                return std::nullopt;
+            }
+            hmacParameters.key = opaqueKey;
+            operationParameters.set<cpp_hwcrypto::OperationParameters::hmac>(
+                    std::move(hmacParameters));
+            break;
+        default:
+            LOG(ERROR) << "received invalid operation parameters";
+            return std::nullopt;
+    }
+    return operationParameters;
 }
 
 class HwCryptoOperationsNdk : public ndk_hwcrypto::BnHwCryptoOperations {
@@ -189,19 +401,208 @@
     }
 
     ndk::ScopedAStatus processCommandList(
-            std::vector<ndk_hwcrypto::CryptoOperationSet>* /*operationSets*/,
-            std::vector<ndk_hwcrypto::CryptoOperationResult>* /*aidl_return*/) {
-        return ndk::ScopedAStatus::ok();
+            std::vector<ndk_hwcrypto::CryptoOperationSet>* operationSets,
+            std::vector<ndk_hwcrypto::CryptoOperationResult>* aidl_return) {
+        Status status = Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
+        if (operationSets == nullptr) {
+            LOG(ERROR) << "received a null operation set";
+            return convertStatus(status);
+        }
+        if (aidl_return == nullptr) {
+            LOG(ERROR) << "received a null CryptoOperationResult set";
+            return convertStatus(status);
+        }
+        std::vector<cpp_hwcrypto::CryptoOperationResult> binderResult;
+        std::vector<cpp_hwcrypto::CryptoOperationSet> cppOperationSets;
+        for (ndk_hwcrypto::CryptoOperationSet& operationSet : *operationSets) {
+            cpp_hwcrypto::CryptoOperationSet cppSingleOperation =
+                    cpp_hwcrypto::CryptoOperationSet();
+            cppSingleOperation.context =
+                    retrieveCppBinder<cpp_hwcrypto::ICryptoOperationContext,
+                                      ndk_hwcrypto::ICryptoOperationContext, contextMapping>(
+                            operationSet.context);
+            for (ndk_hwcrypto::CryptoOperation& operation : operationSet.operations) {
+                cpp_hwcrypto::CryptoOperation cppOperation;
+                cpp_hwcrypto::types::Void voidObj;
+                std::optional<cpp_hwcrypto::types::OperationData> cppOperationData;
+                std::optional<cpp_hwcrypto::PatternParameters> cppPatternParameters;
+                std::optional<cpp_hwcrypto::OperationParameters> cppOperationParameters;
+                switch (operation.getTag()) {
+                    case ndk_hwcrypto::CryptoOperation::setMemoryBuffer:
+                        // TODO: finish this case
+                        exit(1);
+                        break;
+                    case ndk_hwcrypto::CryptoOperation::setOperationParameters:
+                        cppOperationParameters = convertOperationParameters(
+                                operation.get<
+                                        ndk_hwcrypto::CryptoOperation::setOperationParameters>());
+                        if (cppOperationParameters.has_value()) {
+                            cppOperation.set<cpp_hwcrypto::CryptoOperation::setOperationParameters>(
+                                    std::move(cppOperationParameters.value()));
+                        } else {
+                            LOG(ERROR) << "couldn't convert operation parameters";
+                            return convertStatus(status);
+                        }
+                        break;
+                    case ndk_hwcrypto::CryptoOperation::setPattern:
+                        cppPatternParameters = convertPatternParameters(
+                                operation.get<ndk_hwcrypto::CryptoOperation::setPattern>());
+                        if (cppPatternParameters.has_value()) {
+                            cppOperation.set<cpp_hwcrypto::CryptoOperation::setPattern>(
+                                    std::move(cppPatternParameters.value()));
+                        } else {
+                            LOG(ERROR) << "couldn't convert pattern parameters";
+                            return convertStatus(status);
+                        }
+                        break;
+                    case ndk_hwcrypto::CryptoOperation::copyData:
+                        cppOperationData = convertOperationData(
+                                operation.get<ndk_hwcrypto::CryptoOperation::copyData>());
+                        if (cppOperationData.has_value()) {
+                            cppOperation.set<cpp_hwcrypto::CryptoOperation::copyData>(
+                                    std::move(cppOperationData.value()));
+                        } else {
+                            LOG(ERROR) << "couldn't convert CryptoOperation::copyData";
+                            return convertStatus(status);
+                        }
+                        break;
+                    case ndk_hwcrypto::CryptoOperation::aadInput:
+                        cppOperationData = convertOperationData(
+                                operation.get<ndk_hwcrypto::CryptoOperation::aadInput>());
+                        if (cppOperationData.has_value()) {
+                            cppOperation.set<cpp_hwcrypto::CryptoOperation::aadInput>(
+                                    std::move(cppOperationData.value()));
+                        } else {
+                            LOG(ERROR) << "couldn't convert CryptoOperation::aadInput";
+                            return convertStatus(status);
+                        }
+                        break;
+                    case ndk_hwcrypto::CryptoOperation::dataInput:
+                        cppOperationData = convertOperationData(
+                                operation.get<ndk_hwcrypto::CryptoOperation::dataInput>());
+                        if (cppOperationData.has_value()) {
+                            cppOperation.set<cpp_hwcrypto::CryptoOperation::dataInput>(
+                                    std::move(cppOperationData.value()));
+                        } else {
+                            LOG(ERROR) << "couldn't convert CryptoOperation::dataInput";
+                            return convertStatus(status);
+                        }
+                        break;
+                    case ndk_hwcrypto::CryptoOperation::dataOutput:
+                        cppOperationData = convertOperationData(
+                                operation.get<ndk_hwcrypto::CryptoOperation::dataOutput>());
+                        if (cppOperationData.has_value()) {
+                            cppOperation.set<cpp_hwcrypto::CryptoOperation::dataOutput>(
+                                    std::move(cppOperationData.value()));
+                        } else {
+                            LOG(ERROR) << "couldn't convert CryptoOperation::dataOutput";
+                            return convertStatus(status);
+                        }
+                        break;
+                    case ndk_hwcrypto::CryptoOperation::destroyContext:
+                        cppOperation.set<cpp_hwcrypto::CryptoOperation::destroyContext>(
+                                std::move(voidObj));
+                        break;
+                    case ndk_hwcrypto::CryptoOperation::finish:
+                        cppOperation.set<cpp_hwcrypto::CryptoOperation::finish>(std::move(voidObj));
+                        break;
+                    default:
+                        // This shouldn't happen
+                        LOG(ERROR) << "received unknown crypto operation";
+                        return convertStatus(status);
+                }
+                cppSingleOperation.operations.push_back(std::move(cppOperation));
+            }
+            cppOperationSets.push_back(std::move(cppSingleOperation));
+        }
+        status = mHwCryptoOperations->processCommandList(&cppOperationSets, &binderResult);
+        if (status.isOk()) {
+            *aidl_return = std::vector<ndk_hwcrypto::CryptoOperationResult>();
+            for (cpp_hwcrypto::CryptoOperationResult& result : binderResult) {
+                ndk_hwcrypto::CryptoOperationResult ndkResult =
+                        ndk_hwcrypto::CryptoOperationResult();
+                if (result.context != nullptr) {
+                    insertBinderMapping<cpp_hwcrypto::ICryptoOperationContext,
+                                        ndk_hwcrypto::ICryptoOperationContext,
+                                        HwCryptoOperationContextNdk, contextMapping>(
+                            result.context, &ndkResult.context);
+                } else {
+                    ndkResult.context = nullptr;
+                }
+                aidl_return->push_back(std::move(ndkResult));
+            }
+        } else {
+            // No reason to copy back the data output vectors if this failed
+            LOG(ERROR) << "couldn't process command list";
+            return convertStatus(status);
+        }
+        // We need to copy the vectors from the cpp operations back to the ndk one
+        if (cppOperationSets.size() != operationSets->size()) {
+            LOG(ERROR) << "ndk and cpp operation sets had a different number of elements";
+            return convertStatus(Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT));
+        }
+        for (unsigned setIdx = 0; setIdx < cppOperationSets.size(); ++setIdx) {
+            if (cppOperationSets[setIdx].operations.size() !=
+                (*operationSets)[setIdx].operations.size()) {
+                LOG(ERROR) << "ndk and cpp operations on set " << setIdx
+                           << " had a different number of elements";
+                return convertStatus(Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT));
+            }
+            for (unsigned operationIdx = 0;
+                 operationIdx < cppOperationSets[setIdx].operations.size(); ++operationIdx) {
+                if (cppOperationSets[setIdx].operations[operationIdx].getTag() ==
+                    cpp_hwcrypto::CryptoOperation::dataOutput) {
+                    if ((*operationSets)[setIdx].operations[operationIdx].getTag() !=
+                        ndk_hwcrypto::CryptoOperation::dataOutput) {
+                        LOG(ERROR)
+                                << "ndk and cpp operations on set " << setIdx << " and operation "
+                                << operationIdx << " had a different operation type";
+                        return convertStatus(
+                                Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT));
+                    }
+                    if (cppOperationSets[setIdx]
+                                .operations[operationIdx]
+                                .get<cpp_hwcrypto::CryptoOperation::dataOutput>()
+                                .getTag() == cpp_hwcrypto::types::OperationData::dataBuffer) {
+                        // This is the only case on which we need to move the data backto the
+                        // original array
+                        if ((*operationSets)[setIdx]
+                                    .operations[operationIdx]
+                                    .get<ndk_hwcrypto::CryptoOperation::dataOutput>()
+                                    .getTag() != ndk_hwcrypto::types::OperationData::dataBuffer) {
+                            LOG(ERROR) << "ndk and cpp operations on set " << setIdx
+                                       << " and operation " << operationIdx
+                                       << " had a different operation data output type";
+                            return convertStatus(
+                                    Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT));
+                        }
+                        (*operationSets)[setIdx]
+                                .operations[operationIdx]
+                                .get<ndk_hwcrypto::CryptoOperation::dataOutput>()
+                                .set<ndk_hwcrypto::types::OperationData::dataBuffer>(
+                                        cppOperationSets[setIdx]
+                                                .operations[operationIdx]
+                                                .get<cpp_hwcrypto::CryptoOperation::dataOutput>()
+                                                .get<cpp_hwcrypto::types::OperationData::
+                                                             dataBuffer>());
+                    }
+                }
+            }
+        }
+        return convertStatus(status);
     }
 };
 
 class OpaqueKeyNdk : public ndk_hwcrypto::BnOpaqueKey {
   private:
     sp<cpp_hwcrypto::IOpaqueKey> mOpaqueKey;
+    std::weak_ptr<ndk_hwcrypto::IOpaqueKey> self;
 
   public:
     OpaqueKeyNdk(sp<cpp_hwcrypto::IOpaqueKey> opaqueKey) : mOpaqueKey(std::move(opaqueKey)) {}
 
+    ~OpaqueKeyNdk() { keyMapping.erase(self); }
+
     static std::shared_ptr<OpaqueKeyNdk> Create(sp<cpp_hwcrypto::IOpaqueKey> opaqueKey) {
         if (opaqueKey == nullptr) {
             return nullptr;
@@ -213,6 +614,7 @@
             LOG(ERROR) << "failed to allocate HwCryptoKey";
             return nullptr;
         }
+        opaqueKeyNdk->self = opaqueKeyNdk;
         return opaqueKeyNdk;
     }