hwcryptohal: Adding hwcrypto operations tests

Adding test for hwcrypto operations interface.

Bug: 393162614
Test: atest VtsAidlHwCryptoTests
Change-Id: I4070aade6ed43317610bafd9d68dc951658dfbbb
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"
+    );
+}