diff options
| author | Shawn Willden <swillden@google.com> | 2018-01-08 22:00:12 -0700 |
|---|---|---|
| committer | Shawn Willden <swillden@google.com> | 2018-01-17 14:26:08 -0700 |
| commit | 7efc77216ead495bcfe4504be9040cb8a8b284ca (patch) | |
| tree | 56135057227c4f245cd8be40ffb9b3a6def8cd46 | |
| parent | dd7e8a099bdc6310c066d7b99f29faa8d0932c86 (diff) | |
| download | android_system_keymaster-7efc77216ead495bcfe4504be9040cb8a8b284ca.tar.gz android_system_keymaster-7efc77216ead495bcfe4504be9040cb8a8b284ca.tar.bz2 android_system_keymaster-7efc77216ead495bcfe4504be9040cb8a8b284ca.zip | |
Add Triple DES support
Bug: 31675676
Test: make (will run local unit tests)
Change-Id: I4ed2ebcb087ccf6b9976c8899fc795c09dfad408
| -rw-r--r-- | Android.bp | 2 | ||||
| -rw-r--r-- | Makefile | 6 | ||||
| -rw-r--r-- | android_keymaster/operation.cpp | 1 | ||||
| -rw-r--r-- | contexts/keymaster1_passthrough_context.cpp | 3 | ||||
| -rw-r--r-- | contexts/pure_soft_keymaster_context.cpp | 8 | ||||
| -rw-r--r-- | contexts/soft_keymaster_context.cpp | 19 | ||||
| -rw-r--r-- | contexts/soft_keymaster_device.cpp | 3 | ||||
| -rw-r--r-- | include/keymaster/authorization_set.h | 12 | ||||
| -rw-r--r-- | include/keymaster/contexts/pure_soft_keymaster_context.h | 1 | ||||
| -rw-r--r-- | include/keymaster/contexts/soft_keymaster_context.h | 1 | ||||
| -rw-r--r-- | include/keymaster/km_openssl/triple_des_key.h | 61 | ||||
| -rw-r--r-- | km_openssl/triple_des_key.cpp | 64 | ||||
| -rw-r--r-- | km_openssl/triple_des_operation.cpp | 71 | ||||
| -rw-r--r-- | km_openssl/triple_des_operation.h | 46 | ||||
| -rw-r--r-- | legacy_support/keymaster1_legacy_support.cpp | 3 | ||||
| -rw-r--r-- | legacy_support/keymaster_passthrough_engine.cpp | 53 | ||||
| -rw-r--r-- | tests/android_keymaster_test.cpp | 494 | ||||
| -rw-r--r-- | tests/android_keymaster_test_utils.cpp | 21 | ||||
| -rw-r--r-- | tests/android_keymaster_test_utils.h | 4 |
19 files changed, 849 insertions, 24 deletions
@@ -100,6 +100,8 @@ cc_library_shared { "km_openssl/rsa_operation.cpp", "km_openssl/software_random_source.cpp", "km_openssl/symmetric_key.cpp", + "km_openssl/triple_des_key.cpp", + "km_openssl/triple_des_operation.cpp", "km_openssl/wrapped_key.cpp", ], @@ -63,6 +63,8 @@ LDLIBS=-L$(BASE)/../boringssl/build/crypto -lcrypto -lpthread -lstdc++ -lgcov CPPSRCS=\ km_openssl/aes_key.cpp \ km_openssl/aes_operation.cpp \ + km_openssl/triple_des_key.cpp \ + km_openssl/triple_des_operation.cpp \ android_keymaster/android_keymaster.cpp \ android_keymaster/android_keymaster_messages.cpp \ tests/android_keymaster_messages_test.cpp \ @@ -353,6 +355,8 @@ tests/android_keymaster_test: tests/android_keymaster_test.o \ key_blob_utils/ocb_utils.o \ key_blob_utils/software_keyblobs.o \ km_openssl/aes_key.o \ + km_openssl/aes_key.o \ + km_openssl/aes_operation.o \ km_openssl/aes_operation.o \ km_openssl/asymmetric_key.o \ km_openssl/asymmetric_key_factory.o \ @@ -373,6 +377,8 @@ tests/android_keymaster_test: tests/android_keymaster_test.o \ km_openssl/soft_keymaster_enforcement.o \ km_openssl/software_random_source.o \ km_openssl/symmetric_key.o \ + km_openssl/triple_des_key.o \ + km_openssl/triple_des_operation.o \ km_openssl/wrapped_key.o \ legacy_support/ec_keymaster0_key.o \ legacy_support/ec_keymaster1_key.o \ diff --git a/android_keymaster/operation.cpp b/android_keymaster/operation.cpp index 65cdfd5..0edc70f 100644 --- a/android_keymaster/operation.cpp +++ b/android_keymaster/operation.cpp @@ -52,6 +52,7 @@ inline bool is_public_key_algorithm(keymaster_algorithm_t algorithm) { switch (algorithm) { case KM_ALGORITHM_HMAC: case KM_ALGORITHM_AES: + case KM_ALGORITHM_TRIPLE_DES: return false; case KM_ALGORITHM_RSA: case KM_ALGORITHM_EC: diff --git a/contexts/keymaster1_passthrough_context.cpp b/contexts/keymaster1_passthrough_context.cpp index 3f3c371..dab8f37 100644 --- a/contexts/keymaster1_passthrough_context.cpp +++ b/contexts/keymaster1_passthrough_context.cpp @@ -72,6 +72,9 @@ KeyFactory* Keymaster1PassthroughContext::GetKeyFactory(keymaster_algorithm_t al result.reset(new Keymaster1ArbitrationFactory<HmacKeyFactory>(pt_engine_.get(), KM_ALGORITHM_HMAC, device_, this, this)); break; + case KM_ALGORITHM_TRIPLE_DES: + // Not supported by KM1. + return nullptr; } } return result.get(); diff --git a/contexts/pure_soft_keymaster_context.cpp b/contexts/pure_soft_keymaster_context.cpp index 71622a9..b4d1fb7 100644 --- a/contexts/pure_soft_keymaster_context.cpp +++ b/contexts/pure_soft_keymaster_context.cpp @@ -39,6 +39,7 @@ #include <keymaster/km_openssl/openssl_utils.h> #include <keymaster/km_openssl/rsa_key_factory.h> #include <keymaster/km_openssl/soft_keymaster_enforcement.h> +#include <keymaster/km_openssl/triple_des_key.h> #include <keymaster/logger.h> #include <keymaster/operation.h> #include <keymaster/wrapped_key.h> @@ -51,8 +52,9 @@ namespace keymaster { PureSoftKeymasterContext::PureSoftKeymasterContext() : rsa_factory_(new RsaKeyFactory(this)), ec_factory_(new EcKeyFactory(this)), - aes_factory_(new AesKeyFactory(this, this)), hmac_factory_(new HmacKeyFactory(this, this)), - os_version_(0), os_patchlevel_(0), + aes_factory_(new AesKeyFactory(this, this)), + tdes_factory_(new TripleDesKeyFactory(this, this)), + hmac_factory_(new HmacKeyFactory(this, this)), os_version_(0), os_patchlevel_(0), soft_keymaster_enforcement_(64, 64) {} PureSoftKeymasterContext::~PureSoftKeymasterContext() {} @@ -77,6 +79,8 @@ KeyFactory* PureSoftKeymasterContext::GetKeyFactory(keymaster_algorithm_t algori return ec_factory_.get(); case KM_ALGORITHM_AES: return aes_factory_.get(); + case KM_ALGORITHM_TRIPLE_DES: + return tdes_factory_.get(); case KM_ALGORITHM_HMAC: return hmac_factory_.get(); default: diff --git a/contexts/soft_keymaster_context.cpp b/contexts/soft_keymaster_context.cpp index dc9dcd5..7c28bdc 100644 --- a/contexts/soft_keymaster_context.cpp +++ b/contexts/soft_keymaster_context.cpp @@ -25,16 +25,17 @@ #include <keymaster/key_blob_utils/integrity_assured_key_blob.h> #include <keymaster/key_blob_utils/ocb_utils.h> #include <keymaster/key_blob_utils/software_keyblobs.h> -#include <keymaster/legacy_support/ec_keymaster0_key.h> -#include <keymaster/legacy_support/ec_keymaster1_key.h> -#include <keymaster/legacy_support/keymaster0_engine.h> -#include <keymaster/legacy_support/rsa_keymaster0_key.h> -#include <keymaster/legacy_support/rsa_keymaster1_key.h> #include <keymaster/km_openssl/aes_key.h> #include <keymaster/km_openssl/asymmetric_key.h> #include <keymaster/km_openssl/attestation_utils.h> #include <keymaster/km_openssl/hmac_key.h> #include <keymaster/km_openssl/openssl_err.h> +#include <keymaster/km_openssl/triple_des_key.h> +#include <keymaster/legacy_support/ec_keymaster0_key.h> +#include <keymaster/legacy_support/ec_keymaster1_key.h> +#include <keymaster/legacy_support/keymaster0_engine.h> +#include <keymaster/legacy_support/rsa_keymaster0_key.h> +#include <keymaster/legacy_support/rsa_keymaster1_key.h> #include <keymaster/logger.h> #include "soft_attestation_cert.h" @@ -53,8 +54,10 @@ KeymasterBlob string2Blob(const std::string& str) { SoftKeymasterContext::SoftKeymasterContext(const std::string& root_of_trust) : rsa_factory_(new RsaKeyFactory(this)), ec_factory_(new EcKeyFactory(this)), - aes_factory_(new AesKeyFactory(this, this)), hmac_factory_(new HmacKeyFactory(this, this)), - km1_dev_(nullptr), root_of_trust_(string2Blob(root_of_trust)), os_version_(0), os_patchlevel_(0) {} + aes_factory_(new AesKeyFactory(this, this)), + tdes_factory_(new TripleDesKeyFactory(this, this)), + hmac_factory_(new HmacKeyFactory(this, this)), km1_dev_(nullptr), + root_of_trust_(string2Blob(root_of_trust)), os_version_(0), os_patchlevel_(0) {} SoftKeymasterContext::~SoftKeymasterContext() {} @@ -111,6 +114,8 @@ KeyFactory* SoftKeymasterContext::GetKeyFactory(keymaster_algorithm_t algorithm) return ec_factory_.get(); case KM_ALGORITHM_AES: return aes_factory_.get(); + case KM_ALGORITHM_TRIPLE_DES: + return tdes_factory_.get(); case KM_ALGORITHM_HMAC: return hmac_factory_.get(); default: diff --git a/contexts/soft_keymaster_device.cpp b/contexts/soft_keymaster_device.cpp index 6864151..c3c7af5 100644 --- a/contexts/soft_keymaster_device.cpp +++ b/contexts/soft_keymaster_device.cpp @@ -694,7 +694,8 @@ bool SoftKeymasterDevice::RequiresSoftwareDigesting(keymaster_algorithm_t algori switch (algorithm) { case KM_ALGORITHM_AES: - LOG_D("Not performing software digesting for AES keys", algorithm); + case KM_ALGORITHM_TRIPLE_DES: + LOG_D("Not performing software digesting for algorithm %d", algorithm); return false; case KM_ALGORITHM_HMAC: case KM_ALGORITHM_RSA: diff --git a/include/keymaster/authorization_set.h b/include/keymaster/authorization_set.h index df7e244..d018db9 100644 --- a/include/keymaster/authorization_set.h +++ b/include/keymaster/authorization_set.h @@ -515,12 +515,14 @@ class AuthorizationSetBuilder { AuthorizationSetBuilder& RsaKey(uint32_t key_size, uint64_t public_exponent); AuthorizationSetBuilder& EcdsaKey(uint32_t key_size); AuthorizationSetBuilder& AesKey(uint32_t key_size); + AuthorizationSetBuilder& TripleDesKey(uint32_t key_size); AuthorizationSetBuilder& HmacKey(uint32_t key_size); AuthorizationSetBuilder& RsaSigningKey(uint32_t key_size, uint64_t public_exponent); AuthorizationSetBuilder& RsaEncryptionKey(uint32_t key_size, uint64_t public_exponent); AuthorizationSetBuilder& EcdsaSigningKey(uint32_t key_size); AuthorizationSetBuilder& AesEncryptionKey(uint32_t key_size); + AuthorizationSetBuilder& TripleDesEncryptionKey(uint32_t key_size); AuthorizationSetBuilder& SigningKey(); AuthorizationSetBuilder& EncryptionKey(); @@ -570,6 +572,11 @@ inline AuthorizationSetBuilder& AuthorizationSetBuilder::AesKey(uint32_t key_siz return Authorization(TAG_KEY_SIZE, key_size); } +inline AuthorizationSetBuilder& AuthorizationSetBuilder::TripleDesKey(uint32_t key_size) { + Authorization(TAG_ALGORITHM, KM_ALGORITHM_TRIPLE_DES); + return Authorization(TAG_KEY_SIZE, key_size); +} + inline AuthorizationSetBuilder& AuthorizationSetBuilder::HmacKey(uint32_t key_size) { Authorization(TAG_ALGORITHM, KM_ALGORITHM_HMAC); Authorization(TAG_KEY_SIZE, key_size); @@ -598,6 +605,11 @@ inline AuthorizationSetBuilder& AuthorizationSetBuilder::AesEncryptionKey(uint32 return EncryptionKey(); } +inline AuthorizationSetBuilder& AuthorizationSetBuilder::TripleDesEncryptionKey(uint32_t key_size) { + TripleDesKey(key_size); + return EncryptionKey(); +} + inline AuthorizationSetBuilder& AuthorizationSetBuilder::SigningKey() { Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN); return Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY); diff --git a/include/keymaster/contexts/pure_soft_keymaster_context.h b/include/keymaster/contexts/pure_soft_keymaster_context.h index a68a3d5..3a1156d 100644 --- a/include/keymaster/contexts/pure_soft_keymaster_context.h +++ b/include/keymaster/contexts/pure_soft_keymaster_context.h @@ -94,6 +94,7 @@ class PureSoftKeymasterContext: public KeymasterContext, std::unique_ptr<KeyFactory> rsa_factory_; std::unique_ptr<KeyFactory> ec_factory_; std::unique_ptr<KeyFactory> aes_factory_; + std::unique_ptr<KeyFactory> tdes_factory_; std::unique_ptr<KeyFactory> hmac_factory_; uint32_t os_version_; uint32_t os_patchlevel_; diff --git a/include/keymaster/contexts/soft_keymaster_context.h b/include/keymaster/contexts/soft_keymaster_context.h index 5164803..588e3db 100644 --- a/include/keymaster/contexts/soft_keymaster_context.h +++ b/include/keymaster/contexts/soft_keymaster_context.h @@ -120,6 +120,7 @@ class SoftKeymasterContext: public KeymasterContext, SoftwareKeyBlobMaker, Softw std::unique_ptr<KeyFactory> rsa_factory_; std::unique_ptr<KeyFactory> ec_factory_; std::unique_ptr<KeyFactory> aes_factory_; + std::unique_ptr<KeyFactory> tdes_factory_; std::unique_ptr<KeyFactory> hmac_factory_; keymaster1_device* km1_dev_; const KeymasterBlob root_of_trust_; diff --git a/include/keymaster/km_openssl/triple_des_key.h b/include/keymaster/km_openssl/triple_des_key.h new file mode 100644 index 0000000..0a6810d --- /dev/null +++ b/include/keymaster/km_openssl/triple_des_key.h @@ -0,0 +1,61 @@ +/* + * Copyright 2018 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. + */ + +#ifndef SYSTEM_KEYMASTER_TRIPLE_DES_KEY_H_ +#define SYSTEM_KEYMASTER_TRIPLE_DES_KEY_H_ + +#include <openssl/des.h> + +#include "symmetric_key.h" + +namespace keymaster { + +class TripleDesKeyFactory : public SymmetricKeyFactory { + public: + explicit TripleDesKeyFactory(const SoftwareKeyBlobMaker* blob_maker, + const RandomSource* random_source) + : SymmetricKeyFactory(blob_maker, random_source) {} + + keymaster_algorithm_t registry_key() const { return KM_ALGORITHM_TRIPLE_DES; } + + keymaster_error_t LoadKey(KeymasterKeyBlob&& key_material, + const AuthorizationSet& additional_params, + AuthorizationSet&& hw_enforced, AuthorizationSet&& sw_enforced, + UniquePtr<Key>* key) const override; + + OperationFactory* GetOperationFactory(keymaster_purpose_t purpose) const override; + + private: + bool key_size_supported(size_t key_size_bits) const override { + return key_size_bits == 112 || key_size_bits == 168; + } + size_t key_size_bytes(size_t key_size_bits) const override { return key_size_bits / 7; } + size_t key_size_bits(size_t key_size_bytes) const override { return key_size_bytes * 7; } + + keymaster_error_t validate_algorithm_specific_new_key_params( + const AuthorizationSet& key_description) const override; +}; + +class TripleDesKey : public SymmetricKey { + public: + TripleDesKey(KeymasterKeyBlob&& key_material, AuthorizationSet&& hw_enforced, + AuthorizationSet&& sw_enforced, const KeyFactory* key_factory) + : SymmetricKey(move(key_material), move(hw_enforced), move(sw_enforced), key_factory) {} +}; + +} // namespace keymaster + +#endif // SYSTEM_KEYMASTER_TRIPLE_DES_KEY_H_ diff --git a/km_openssl/triple_des_key.cpp b/km_openssl/triple_des_key.cpp new file mode 100644 index 0000000..d515d96 --- /dev/null +++ b/km_openssl/triple_des_key.cpp @@ -0,0 +1,64 @@ +/* + * Copyright 2018 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. + */ + +#include <keymaster/km_openssl/triple_des_key.h> + +#include <assert.h> + +#include <keymaster/new> + +#include <openssl/err.h> +#include <openssl/rand.h> + +#include "triple_des_operation.h" + +namespace keymaster { + +static TripleDesOperationFactory encrypt_factory(KM_PURPOSE_ENCRYPT); +static TripleDesOperationFactory decrypt_factory(KM_PURPOSE_DECRYPT); + +OperationFactory* TripleDesKeyFactory::GetOperationFactory(keymaster_purpose_t purpose) const { + switch (purpose) { + case KM_PURPOSE_ENCRYPT: + return &encrypt_factory; + case KM_PURPOSE_DECRYPT: + return &decrypt_factory; + default: + return nullptr; + } +} + +keymaster_error_t TripleDesKeyFactory::LoadKey(KeymasterKeyBlob&& key_material, + const AuthorizationSet& /* additional_params */, + AuthorizationSet&& hw_enforced, + AuthorizationSet&& sw_enforced, + UniquePtr<Key>* key) const { + if (!key) return KM_ERROR_OUTPUT_PARAMETER_NULL; + + keymaster_error_t error = KM_ERROR_OK; + key->reset(new (std::nothrow) + TripleDesKey(move(key_material), move(hw_enforced), move(sw_enforced), this)); + if (!key->get()) error = KM_ERROR_MEMORY_ALLOCATION_FAILED; + return error; +} + +keymaster_error_t TripleDesKeyFactory::validate_algorithm_specific_new_key_params( + const AuthorizationSet& key_description) const { + if (key_description.Contains(TAG_MIN_MAC_LENGTH)) return KM_ERROR_INVALID_TAG; + return KM_ERROR_OK; +} + +} // namespace keymaster diff --git a/km_openssl/triple_des_operation.cpp b/km_openssl/triple_des_operation.cpp new file mode 100644 index 0000000..b521bf5 --- /dev/null +++ b/km_openssl/triple_des_operation.cpp @@ -0,0 +1,71 @@ +/* + * Copyright 2014 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. + */ + +#include "triple_des_operation.h" + +namespace keymaster { + +static const keymaster_block_mode_t supported_block_modes[] = {KM_MODE_ECB, KM_MODE_CBC}; + +const keymaster_block_mode_t* +TripleDesEvpCipherDescription::SupportedBlockModes(size_t* block_mode_count) const { + *block_mode_count = array_length(supported_block_modes); + return supported_block_modes; +} + +const EVP_CIPHER* +TripleDesEvpCipherDescription::GetCipherInstance(size_t key_size, keymaster_block_mode_t block_mode, + keymaster_error_t* error) const { + *error = KM_ERROR_OK; + + switch (block_mode) { + case KM_MODE_ECB: + switch (key_size) { + case 16: + return EVP_des_ede(); // Note: OpenSSL 1.1.0 renamed this to EVP_des_ede_ecb + case 24: + return EVP_des_ede3(); // Note: OpenSSL 1.1.0 renamed this to EVP_des_ede3_ecb + default: + *error = KM_ERROR_UNSUPPORTED_KEY_SIZE; + break; + } + + case KM_MODE_CBC: + switch (key_size) { + case 16: + return EVP_des_ede_cbc(); + case 24: + return EVP_des_ede3_cbc(); + default: + *error = KM_ERROR_UNSUPPORTED_KEY_SIZE; + break; + } + + default: + *error = KM_ERROR_UNSUPPORTED_BLOCK_MODE; + break; + } + + assert(*error != KM_ERROR_OK); + return nullptr; +} + +static TripleDesEvpCipherDescription description; +const EvpCipherDescription& TripleDesOperationFactory::GetCipherDescription() const { + return description; +} + +} // namespace keymaster diff --git a/km_openssl/triple_des_operation.h b/km_openssl/triple_des_operation.h new file mode 100644 index 0000000..cc69bc7 --- /dev/null +++ b/km_openssl/triple_des_operation.h @@ -0,0 +1,46 @@ +/* + * Copyright 2018 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. + */ + +#ifndef SYSTEM_KEYMASTER_TRIPLE_DES_OPERATION_H_ +#define SYSTEM_KEYMASTER_TRIPLE_DES_OPERATION_H_ + +#include <openssl/des.h> + +#include "block_cipher_operation.h" + +namespace keymaster { + +class TripleDesEvpCipherDescription : public EvpCipherDescription { + public: + keymaster_algorithm_t algorithm() const override { return KM_ALGORITHM_TRIPLE_DES; } + + const keymaster_block_mode_t* SupportedBlockModes(size_t* block_mode_count) const override; + + const EVP_CIPHER* GetCipherInstance(size_t key_size, keymaster_block_mode_t block_mode, + keymaster_error_t* error) const override; + + size_t block_size_bytes() const override { return 8 /* DES_BLOCK_SIZE */; } +}; + +class TripleDesOperationFactory : public BlockCipherOperationFactory { + public: + TripleDesOperationFactory(keymaster_purpose_t purpose) : BlockCipherOperationFactory(purpose) {} + const EvpCipherDescription& GetCipherDescription() const override; +}; + +} // namespace keymaster + +#endif // SYSTEM_KEYMASTER_TRIPLE_DES_OPERATION_H_ diff --git a/legacy_support/keymaster1_legacy_support.cpp b/legacy_support/keymaster1_legacy_support.cpp index 18f5385..3026452 100644 --- a/legacy_support/keymaster1_legacy_support.cpp +++ b/legacy_support/keymaster1_legacy_support.cpp @@ -140,7 +140,8 @@ bool requiresSoftwareDigesting(keymaster_algorithm_t algorithm, keymaster_purpos const Keymaster1LegacySupport::DigestMap& digest_map) { switch (algorithm) { case KM_ALGORITHM_AES: - LOG(WARNING) << "Not performing software digesting for AES keys"; + case KM_ALGORITHM_TRIPLE_DES: + LOG(WARNING) << "Not performing software digesting for symmetric cipher keys"; return false; case KM_ALGORITHM_HMAC: case KM_ALGORITHM_RSA: diff --git a/legacy_support/keymaster_passthrough_engine.cpp b/legacy_support/keymaster_passthrough_engine.cpp index 6af238e..7aa8908 100644 --- a/legacy_support/keymaster_passthrough_engine.cpp +++ b/legacy_support/keymaster_passthrough_engine.cpp @@ -14,9 +14,9 @@ ** See the License for the specific language governing permissions and ** limitations under the License. */ +#include "keymaster_passthrough_operation.h" #include <keymaster/legacy_support/keymaster_passthrough_engine.h> #include <keymaster/legacy_support/keymaster_passthrough_key.h> -#include "keymaster_passthrough_operation.h" #include <hardware/keymaster1.h> #include <hardware/keymaster2.h> @@ -38,25 +38,41 @@ namespace keymaster { template <typename KeymasterDeviceType> class TKeymasterPassthroughEngine : public KeymasterPassthroughEngine { using opfactory_t = KeymasterPassthroughOperationFactory<KeymasterDeviceType>; + public: /** * The engine takes ownership of the device, and will close it during destruction. */ explicit TKeymasterPassthroughEngine(const KeymasterDeviceType* km_device) : km_device_(km_device) { - rsa_encrypt_op_factory_.reset(new opfactory_t(KM_ALGORITHM_RSA, KM_PURPOSE_ENCRYPT, km_device_)); - rsa_decrypt_op_factory_.reset(new opfactory_t(KM_ALGORITHM_RSA, KM_PURPOSE_DECRYPT, km_device_)); + rsa_encrypt_op_factory_.reset( + new opfactory_t(KM_ALGORITHM_RSA, KM_PURPOSE_ENCRYPT, km_device_)); + rsa_decrypt_op_factory_.reset( + new opfactory_t(KM_ALGORITHM_RSA, KM_PURPOSE_DECRYPT, km_device_)); rsa_sign_op_factory_.reset(new opfactory_t(KM_ALGORITHM_RSA, KM_PURPOSE_SIGN, km_device_)); - rsa_verify_op_factory_.reset(new opfactory_t(KM_ALGORITHM_RSA, KM_PURPOSE_VERIFY, km_device_)); - ec_encrypt_op_factory_.reset(new opfactory_t(KM_ALGORITHM_EC, KM_PURPOSE_ENCRYPT, km_device_)); - ec_decrypt_op_factory_.reset(new opfactory_t(KM_ALGORITHM_EC, KM_PURPOSE_DECRYPT, km_device_)); + rsa_verify_op_factory_.reset( + new opfactory_t(KM_ALGORITHM_RSA, KM_PURPOSE_VERIFY, km_device_)); + ec_encrypt_op_factory_.reset( + new opfactory_t(KM_ALGORITHM_EC, KM_PURPOSE_ENCRYPT, km_device_)); + ec_decrypt_op_factory_.reset( + new opfactory_t(KM_ALGORITHM_EC, KM_PURPOSE_DECRYPT, km_device_)); ec_sign_op_factory_.reset(new opfactory_t(KM_ALGORITHM_EC, KM_PURPOSE_SIGN, km_device_)); - ec_verify_op_factory_.reset(new opfactory_t(KM_ALGORITHM_EC, KM_PURPOSE_VERIFY, km_device_)); - ec_derive_op_factory_.reset(new opfactory_t(KM_ALGORITHM_EC, KM_PURPOSE_DERIVE_KEY, km_device_)); - aes_encrypt_op_factory_.reset(new opfactory_t(KM_ALGORITHM_AES, KM_PURPOSE_ENCRYPT, km_device_)); - aes_decrypt_op_factory_.reset(new opfactory_t(KM_ALGORITHM_AES, KM_PURPOSE_DECRYPT, km_device_)); - hmac_sign_op_factory_.reset(new opfactory_t(KM_ALGORITHM_HMAC, KM_PURPOSE_SIGN, km_device_)); - hmac_verify_op_factory_.reset(new opfactory_t(KM_ALGORITHM_HMAC, KM_PURPOSE_VERIFY, km_device_)); + ec_verify_op_factory_.reset( + new opfactory_t(KM_ALGORITHM_EC, KM_PURPOSE_VERIFY, km_device_)); + ec_derive_op_factory_.reset( + new opfactory_t(KM_ALGORITHM_EC, KM_PURPOSE_DERIVE_KEY, km_device_)); + aes_encrypt_op_factory_.reset( + new opfactory_t(KM_ALGORITHM_AES, KM_PURPOSE_ENCRYPT, km_device_)); + aes_decrypt_op_factory_.reset( + new opfactory_t(KM_ALGORITHM_AES, KM_PURPOSE_DECRYPT, km_device_)); + triple_des_encrypt_op_factory_.reset( + new opfactory_t(KM_ALGORITHM_TRIPLE_DES, KM_PURPOSE_ENCRYPT, km_device_)); + triple_des_decrypt_op_factory_.reset( + new opfactory_t(KM_ALGORITHM_TRIPLE_DES, KM_PURPOSE_DECRYPT, km_device_)); + hmac_sign_op_factory_.reset( + new opfactory_t(KM_ALGORITHM_HMAC, KM_PURPOSE_SIGN, km_device_)); + hmac_verify_op_factory_.reset( + new opfactory_t(KM_ALGORITHM_HMAC, KM_PURPOSE_VERIFY, km_device_)); } virtual ~TKeymasterPassthroughEngine() { // QUIRK: we only take ownership if this is a KM2 device. @@ -138,8 +154,17 @@ class TKeymasterPassthroughEngine : public KeymasterPassthroughEngine { default: return nullptr; } + case KM_ALGORITHM_TRIPLE_DES: + switch (purpose) { + case KM_PURPOSE_ENCRYPT: + return triple_des_encrypt_op_factory_.get(); + case KM_PURPOSE_DECRYPT: + return triple_des_decrypt_op_factory_.get(); + default: + return nullptr; + } case KM_ALGORITHM_HMAC: - switch(purpose) { + switch (purpose) { case KM_PURPOSE_SIGN: return hmac_sign_op_factory_.get(); case KM_PURPOSE_VERIFY: @@ -168,6 +193,8 @@ class TKeymasterPassthroughEngine : public KeymasterPassthroughEngine { std::unique_ptr<opfactory_t> ec_derive_op_factory_; std::unique_ptr<opfactory_t> aes_encrypt_op_factory_; std::unique_ptr<opfactory_t> aes_decrypt_op_factory_; + std::unique_ptr<opfactory_t> triple_des_encrypt_op_factory_; + std::unique_ptr<opfactory_t> triple_des_decrypt_op_factory_; std::unique_ptr<opfactory_t> hmac_sign_op_factory_; std::unique_ptr<opfactory_t> hmac_verify_op_factory_; }; diff --git a/tests/android_keymaster_test.cpp b/tests/android_keymaster_test.cpp index ccfb874..7e523f3 100644 --- a/tests/android_keymaster_test.cpp +++ b/tests/android_keymaster_test.cpp @@ -3376,6 +3376,500 @@ TEST_P(EncryptionOperationsTest, AesGcmCorruptTag) { EXPECT_EQ(0, GetParam()->keymaster0_calls()); } +TEST_P(EncryptionOperationsTest, TripleDesEcbRoundTripSuccess) { + auto auths = AuthorizationSetBuilder() + .TripleDesEncryptionKey(112) + .Authorization(TAG_BLOCK_MODE, KM_MODE_ECB) + .Padding(KM_PAD_NONE); + + ASSERT_EQ(KM_ERROR_OK, GenerateKey(auths)); + // Two-block message. + string message = "1234567890123456"; + string ciphertext1 = EncryptMessage(message, KM_MODE_ECB, KM_PAD_NONE); + EXPECT_EQ(message.size(), ciphertext1.size()); + + string ciphertext2 = EncryptMessage(string(message), KM_MODE_ECB, KM_PAD_NONE); + EXPECT_EQ(message.size(), ciphertext2.size()); + + // ECB is deterministic. + EXPECT_EQ(ciphertext1, ciphertext2); + + string plaintext = DecryptMessage(ciphertext1, KM_MODE_ECB, KM_PAD_NONE); + EXPECT_EQ(message, plaintext); +} + +TEST_P(EncryptionOperationsTest, TripleDesEcbNotAuthorized) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .TripleDesEncryptionKey(112) + .Authorization(TAG_BLOCK_MODE, KM_MODE_CBC) + .Padding(KM_PAD_NONE))); + // Two-block message. + string message = "1234567890123456"; + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_ECB); + begin_params.push_back(TAG_PADDING, KM_PAD_NONE); + EXPECT_EQ(KM_ERROR_INCOMPATIBLE_BLOCK_MODE, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params)); +} + +TEST_P(EncryptionOperationsTest, TripleDesEcbNoPaddingWrongInputSize) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .TripleDesEncryptionKey(112) + .Authorization(TAG_BLOCK_MODE, KM_MODE_ECB) + .Padding(KM_PAD_NONE))); + // Message is slightly shorter than two blocks. + string message = "123456789012345"; + + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_ECB); + begin_params.push_back(TAG_PADDING, KM_PAD_NONE); + EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params)); + string ciphertext; + EXPECT_EQ(KM_ERROR_INVALID_INPUT_LENGTH, FinishOperation(message, "", &ciphertext)); +} + +TEST_P(EncryptionOperationsTest, TripleDesEcbPkcs7Padding) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .TripleDesEncryptionKey(112) + .Authorization(TAG_BLOCK_MODE, KM_MODE_ECB) + .Authorization(TAG_PADDING, KM_PAD_PKCS7))); + + // Try various message lengths; all should work. + for (size_t i = 0; i < 32; ++i) { + string message(i, 'a'); + string ciphertext = EncryptMessage(message, KM_MODE_ECB, KM_PAD_PKCS7); + EXPECT_EQ(i + 8 - (i % 8), ciphertext.size()); + string plaintext = DecryptMessage(ciphertext, KM_MODE_ECB, KM_PAD_PKCS7); + EXPECT_EQ(message, plaintext); + } +} + +TEST_P(EncryptionOperationsTest, TripleDesEcbNoPaddingKeyWithPkcs7Padding) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .TripleDesEncryptionKey(112) + .Authorization(TAG_BLOCK_MODE, KM_MODE_ECB) + .Authorization(TAG_PADDING, KM_PAD_NONE))); + + // Try various message lengths; all should fail. + for (size_t i = 0; i < 32; ++i) { + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_ECB); + begin_params.push_back(TAG_PADDING, KM_PAD_PKCS7); + EXPECT_EQ(KM_ERROR_INCOMPATIBLE_PADDING_MODE, + BeginOperation(KM_PURPOSE_ENCRYPT, begin_params)); + } +} + +TEST_P(EncryptionOperationsTest, TripleDesEcbPkcs7PaddingCorrupted) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .TripleDesEncryptionKey(112) + .Authorization(TAG_BLOCK_MODE, KM_MODE_ECB) + .Authorization(TAG_PADDING, KM_PAD_PKCS7))); + + string message = "a"; + string ciphertext = EncryptMessage(message, KM_MODE_ECB, KM_PAD_PKCS7); + EXPECT_EQ(8U, ciphertext.size()); + EXPECT_NE(ciphertext, message); + ++ciphertext[ciphertext.size() / 2]; + + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_ECB); + begin_params.push_back(TAG_PADDING, KM_PAD_PKCS7); + EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params)); + string plaintext; + size_t input_consumed; + EXPECT_EQ(KM_ERROR_OK, UpdateOperation(ciphertext, &plaintext, &input_consumed)); + EXPECT_EQ(ciphertext.size(), input_consumed); + EXPECT_EQ(KM_ERROR_INVALID_ARGUMENT, FinishOperation(&plaintext)); +} + +struct TripleDesTestVector { + const char* name; + const keymaster_purpose_t purpose; + const keymaster_block_mode_t block_mode; + const keymaster_padding_t padding_mode; + const char* key; + const char* iv; + const char* input; + const char* output; +}; + +// These test vectors are from NIST CAVP, plus a few custom variants to test padding, since all of +// the NIST vectors are multiples of the block size. +static const TripleDesTestVector kTripleDesTestVectors[] = { + { + "TECBMMT2 Encrypt 0", KM_PURPOSE_ENCRYPT, KM_MODE_ECB, KM_PAD_NONE, + "ad192fd064b5579e7a4fb3c8f794f22a", // key + "", // IV + "13bad542f3652d67", // input + "908e543cf2cb254f", // output + }, + { + "TECBMMT2 Encrypt 0 PKCS7", KM_PURPOSE_ENCRYPT, KM_MODE_ECB, KM_PAD_PKCS7, + "ad192fd064b5579e7a4fb3c8f794f22a", // key + "", // IV + "13bad542f3652d6700", // input + "908e543cf2cb254fc40165289a89008c", // output + }, + { + "TECBMMT2 Encrypt 0 PKCS7 decrypted", KM_PURPOSE_DECRYPT, KM_MODE_ECB, KM_PAD_PKCS7, + "ad192fd064b5579e7a4fb3c8f794f22a", // key + "", // IV + "908e543cf2cb254fc40165289a89008c", // input + "13bad542f3652d6700", // output + }, + { + "TECBMMT2 Encrypt 1", KM_PURPOSE_ENCRYPT, KM_MODE_ECB, KM_PAD_NONE, + "259df16e7af804fe83b90e9bf7c7e557", // key + "", // IV + "a4619c433bbd6787c07c81728f9ac9fa", // input + "9e06de155c483c6bcfd834dbc8bd5830", // output + }, + { + "TECBMMT2 Decrypt 0", KM_PURPOSE_DECRYPT, KM_MODE_ECB, KM_PAD_NONE, + "b32ff42092024adf2076b9d3d9f19e6d", // key + "", // IV + "2f3f2a49bba807a5", // input + "2249973fa135fb52", // output + }, + { + "TECBMMT2 Decrypt 1", KM_PURPOSE_DECRYPT, KM_MODE_ECB, KM_PAD_NONE, + "023dfbe6621aa17cc219eae9cdecd923", // key + "", // IV + "54045dc71d8d565b227ec19f06fef912", // input + "9b071622181e6412de6066429401410d", // output + }, + { + "TECBMMT3 Encrypt 0", KM_PURPOSE_ENCRYPT, KM_MODE_ECB, KM_PAD_NONE, + "a2b5bc67da13dc92cd9d344aa238544a0e1fa79ef76810cd", // key + "", // IV + "329d86bdf1bc5af4", // input + "d946c2756d78633f", // output + }, + { + "TECBMMT3 Encrypt 1", KM_PURPOSE_ENCRYPT, KM_MODE_ECB, KM_PAD_NONE, + "49e692290d2a5e46bace79b9648a4c5d491004c262dc9d49", // key + "", // IV + "6b1540781b01ce1997adae102dbf3c5b", // input + "4d0dc182d6e481ac4a3dc6ab6976ccae", // output + }, + { + "TECBMMT3 Decrypt 0", KM_PURPOSE_DECRYPT, KM_MODE_ECB, KM_PAD_NONE, + "52daec2ac7dc1958377392682f37860b2cc1ea2304bab0e9", // key + "", // IV + "6daad94ce08acfe7", // input + "660e7d32dcc90e79", // output + }, + { + "TECBMMT3 Decrypt 1", KM_PURPOSE_DECRYPT, KM_MODE_ECB, KM_PAD_NONE, + "7f8fe3d3f4a48394fb682c2919926d6ddfce8932529229ce", // key + "", // IV + "e9653a0a1f05d31b9acd12d73aa9879d", // input + "9b2ae9d998efe62f1b592e7e1df8ff38", // output + }, + { + "TCBCMMT2 Encrypt 0", KM_PURPOSE_ENCRYPT, KM_MODE_CBC, KM_PAD_NONE, + "34a41a8c293176c1b30732ecfe38ae8a", // key + "f55b4855228bd0b4", // IV + "7dd880d2a9ab411c", // input + "c91892948b6cadb4", // output + }, + { + "TCBCMMT2 Encrypt 1", KM_PURPOSE_ENCRYPT, KM_MODE_CBC, KM_PAD_NONE, + "70a88fa1dfb9942fa77f40157ffef2ad", // key + "ece08ce2fdc6ce80", // IV + "bc225304d5a3a5c9918fc5006cbc40cc", // input + "27f67dc87af7ddb4b68f63fa7c2d454a", // output + }, + { + "TCBCMMT2 Decrypt 0", KM_PURPOSE_DECRYPT, KM_MODE_CBC, KM_PAD_NONE, + "4ff47fda89209bda8c85f7fe80192007", // key + "d5bc4891dabe48b9", // IV + "7e154b28c353adef", // input + "712b961ea9a1d0af", // output + }, + { + "TCBCMMT2 Decrypt 1", KM_PURPOSE_DECRYPT, KM_MODE_CBC, KM_PAD_NONE, + "464092cdbf736d38fb1fe6a12a94ae0e", // key + "5423455f00023b01", // IV + "3f6050b74ed64416bc23d53b0469ed7a", // input + "9cbe7d1b5cdd1864c3095ba810575960", // output + }, + { + "TCBCMMT3 Encrypt 0", KM_PURPOSE_ENCRYPT, KM_MODE_CBC, KM_PAD_NONE, + "b5cb1504802326c73df186e3e352a20de643b0d63ee30e37", // key + "43f791134c5647ba", // IV + "dcc153cef81d6f24", // input + "92538bd8af18d3ba", // output + }, + { + "TCBCMMT3 Encrypt 1", KM_PURPOSE_ENCRYPT, KM_MODE_CBC, KM_PAD_NONE, + "a49d7564199e97cb529d2c9d97bf2f98d35edf57ba1f7358", // key + "c2e999cb6249023c", // IV + "c689aee38a301bb316da75db36f110b5", // input + "e9afaba5ec75ea1bbe65506655bb4ecb", // output + }, + { + "TCBCMMT3 Encrypt 1 PKCS7 variant", KM_PURPOSE_ENCRYPT, KM_MODE_CBC, KM_PAD_PKCS7, + "a49d7564199e97cb529d2c9d97bf2f98d35edf57ba1f7358", // key + "c2e999cb6249023c", // IV + "c689aee38a301bb316da75db36f110b500", // input + "e9afaba5ec75ea1bbe65506655bb4ecb825aa27ec0656156", // output + }, + { + "TCBCMMT3 Encrypt 1 PKCS7 decrypted", KM_PURPOSE_DECRYPT, KM_MODE_CBC, KM_PAD_PKCS7, + "a49d7564199e97cb529d2c9d97bf2f98d35edf57ba1f7358", // key + "c2e999cb6249023c", // IV + "e9afaba5ec75ea1bbe65506655bb4ecb825aa27ec0656156", // input + "c689aee38a301bb316da75db36f110b500", // output + }, + { + "TCBCMMT3 Decrypt 0", KM_PURPOSE_DECRYPT, KM_MODE_CBC, KM_PAD_NONE, + "5eb6040d46082c7aa7d06dfd08dfeac8c18364c1548c3ba1", // key + "41746c7e442d3681", // IV + "c53a7b0ec40600fe", // input + "d4f00eb455de1034", // output + }, + { + "TCBCMMT3 Decrypt 1", KM_PURPOSE_DECRYPT, KM_MODE_CBC, KM_PAD_NONE, + "5b1cce7c0dc1ec49130dfb4af45785ab9179e567f2c7d549", // key + "3982bc02c3727d45", // IV + "6006f10adef52991fcc777a1238bbb65", // input + "edae09288e9e3bc05746d872b48e3b29", // output + }, +}; + +TEST_P(EncryptionOperationsTest, TripleDesTestVector) { + for (auto& test : array_range(kTripleDesTestVectors)) { + SCOPED_TRACE(test.name); + CheckTripleDesTestVector(test.purpose, test.block_mode, test.padding_mode, + hex2str(test.key), hex2str(test.iv), hex2str(test.input), + hex2str(test.output)); + } +} + +TEST_P(EncryptionOperationsTest, TripleDesCbcRoundTripSuccess) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .TripleDesEncryptionKey(112) + .Authorization(TAG_BLOCK_MODE, KM_MODE_CBC) + .Padding(KM_PAD_NONE))); + // Two-block message. + string message = "1234567890123456"; + string iv1; + string ciphertext1 = EncryptMessage(message, KM_MODE_CBC, KM_PAD_NONE, &iv1); + EXPECT_EQ(message.size(), ciphertext1.size()); + + string iv2; + string ciphertext2 = EncryptMessage(message, KM_MODE_CBC, KM_PAD_NONE, &iv2); + EXPECT_EQ(message.size(), ciphertext2.size()); + + // IVs should be random, so ciphertexts should differ. + EXPECT_NE(iv1, iv2); + EXPECT_NE(ciphertext1, ciphertext2); + + string plaintext = DecryptMessage(ciphertext1, KM_MODE_CBC, KM_PAD_NONE, iv1); + EXPECT_EQ(message, plaintext); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +TEST_P(EncryptionOperationsTest, TripleDesCallerIv) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .TripleDesEncryptionKey(112) + .Authorization(TAG_BLOCK_MODE, KM_MODE_CBC) + .Authorization(TAG_CALLER_NONCE) + .Padding(KM_PAD_NONE))); + string message = "1234567890123456"; + string iv1; + // Don't specify IV, should get a random one. + string ciphertext1 = EncryptMessage(message, KM_MODE_CBC, KM_PAD_NONE, &iv1); + EXPECT_EQ(message.size(), ciphertext1.size()); + EXPECT_EQ(8U, iv1.size()); + + string plaintext = DecryptMessage(ciphertext1, KM_MODE_CBC, KM_PAD_NONE, iv1); + EXPECT_EQ(message, plaintext); + + // Now specify an IV, should also work. + AuthorizationSet input_params(client_params()); + AuthorizationSet update_params; + AuthorizationSet output_params; + input_params.push_back(TAG_NONCE, "abcdefgh", 8); + input_params.push_back(TAG_BLOCK_MODE, KM_MODE_CBC); + input_params.push_back(TAG_PADDING, KM_PAD_NONE); + string ciphertext2 = + ProcessMessage(KM_PURPOSE_ENCRYPT, message, input_params, update_params, &output_params); + + // Decrypt with correct IV. + plaintext = ProcessMessage(KM_PURPOSE_DECRYPT, ciphertext2, input_params, update_params, + &output_params); + EXPECT_EQ(message, plaintext); + + // Now try with wrong IV. + input_params.Reinitialize(client_params()); + input_params.push_back(TAG_BLOCK_MODE, KM_MODE_CBC); + input_params.push_back(TAG_PADDING, KM_PAD_NONE); + input_params.push_back(TAG_NONCE, "aaaaaaaa", 8); + plaintext = ProcessMessage(KM_PURPOSE_DECRYPT, ciphertext2, input_params, update_params, + &output_params); + EXPECT_NE(message, plaintext); +} + +TEST_P(EncryptionOperationsTest, TripleDesCallerNonceProhibited) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .TripleDesEncryptionKey(112) + .Authorization(TAG_BLOCK_MODE, KM_MODE_CBC) + .Padding(KM_PAD_NONE))); + + string message = "12345678901234567890123456789012"; + string iv1; + // Don't specify nonce, should get a random one. + string ciphertext1 = EncryptMessage(message, KM_MODE_CBC, KM_PAD_NONE, &iv1); + EXPECT_EQ(message.size(), ciphertext1.size()); + EXPECT_EQ(8U, iv1.size()); + + string plaintext = DecryptMessage(ciphertext1, KM_MODE_CBC, KM_PAD_NONE, iv1); + EXPECT_EQ(message, plaintext); + + // Now specify a nonce, should fail. + AuthorizationSet input_params(client_params()); + AuthorizationSet update_params; + AuthorizationSet output_params; + input_params.push_back(TAG_NONCE, "abcdefgh", 8); + input_params.push_back(TAG_BLOCK_MODE, KM_MODE_CBC); + input_params.push_back(TAG_PADDING, KM_PAD_NONE); + + EXPECT_EQ(KM_ERROR_CALLER_NONCE_PROHIBITED, + BeginOperation(KM_PURPOSE_ENCRYPT, input_params, &output_params)); +} + +TEST_P(EncryptionOperationsTest, TripleDesCbcNotAuthorized) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .TripleDesEncryptionKey(112) + .Authorization(TAG_BLOCK_MODE, KM_MODE_ECB) + .Padding(KM_PAD_NONE))); + // Two-block message. + string message = "1234567890123456"; + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_CBC); + begin_params.push_back(TAG_PADDING, KM_PAD_NONE); + EXPECT_EQ(KM_ERROR_INCOMPATIBLE_BLOCK_MODE, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params)); +} + +TEST_P(EncryptionOperationsTest, TripleDesCbcNoPaddingWrongInputSize) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .TripleDesEncryptionKey(112) + .Authorization(TAG_BLOCK_MODE, KM_MODE_CBC) + .Padding(KM_PAD_NONE))); + // Message is slightly shorter than two blocks. + string message = "123456789012345"; + + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_CBC); + begin_params.push_back(TAG_PADDING, KM_PAD_NONE); + AuthorizationSet output_params; + EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params, &output_params)); + string ciphertext; + EXPECT_EQ(KM_ERROR_INVALID_INPUT_LENGTH, FinishOperation(message, "", &ciphertext)); +} + +TEST_P(EncryptionOperationsTest, TripleDesCbcPkcs7Padding) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .TripleDesEncryptionKey(112) + .Authorization(TAG_BLOCK_MODE, KM_MODE_CBC) + .Authorization(TAG_PADDING, KM_PAD_PKCS7))); + + // Try various message lengths; all should work. + for (size_t i = 0; i < 32; ++i) { + string message(i, 'a'); + string iv; + string ciphertext = EncryptMessage(message, KM_MODE_CBC, KM_PAD_PKCS7, &iv); + EXPECT_EQ(i + 8 - (i % 8), ciphertext.size()); + string plaintext = DecryptMessage(ciphertext, KM_MODE_CBC, KM_PAD_PKCS7, iv); + EXPECT_EQ(message, plaintext); + } +} + +TEST_P(EncryptionOperationsTest, TripleDesCbcNoPaddingKeyWithPkcs7Padding) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .TripleDesEncryptionKey(112) + .Authorization(TAG_BLOCK_MODE, KM_MODE_CBC) + .Authorization(TAG_PADDING, KM_PAD_NONE))); + + // Try various message lengths; all should fail. + for (size_t i = 0; i < 32; ++i) { + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_CBC); + begin_params.push_back(TAG_PADDING, KM_PAD_PKCS7); + EXPECT_EQ(KM_ERROR_INCOMPATIBLE_PADDING_MODE, + BeginOperation(KM_PURPOSE_ENCRYPT, begin_params)); + } +} + +TEST_P(EncryptionOperationsTest, TripleDesCbcPkcs7PaddingCorrupted) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .TripleDesEncryptionKey(112) + .Authorization(TAG_BLOCK_MODE, KM_MODE_CBC) + .Authorization(TAG_PADDING, KM_PAD_PKCS7))); + + string message = "a"; + string iv; + string ciphertext = EncryptMessage(message, KM_MODE_CBC, KM_PAD_PKCS7, &iv); + EXPECT_EQ(8U, ciphertext.size()); + EXPECT_NE(ciphertext, message); + ++ciphertext[ciphertext.size() / 2]; + + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_CBC); + begin_params.push_back(TAG_PADDING, KM_PAD_PKCS7); + begin_params.push_back(TAG_NONCE, iv.data(), iv.size()); + EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params)); + string plaintext; + size_t input_consumed; + EXPECT_EQ(KM_ERROR_OK, UpdateOperation(ciphertext, &plaintext, &input_consumed)); + EXPECT_EQ(ciphertext.size(), input_consumed); + EXPECT_EQ(KM_ERROR_INVALID_ARGUMENT, FinishOperation(&plaintext)); +} + +TEST_P(EncryptionOperationsTest, TripleDesCbcIncrementalNoPadding) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .TripleDesEncryptionKey(112) + .Authorization(TAG_BLOCK_MODE, KM_MODE_CBC) + .Padding(KM_PAD_NONE))); + + int increment = 7; + string message(240, 'a'); + AuthorizationSet input_params(client_params()); + input_params.push_back(TAG_BLOCK_MODE, KM_MODE_CBC); + input_params.push_back(TAG_PADDING, KM_PAD_NONE); + AuthorizationSet output_params; + EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, input_params, &output_params)); + + string ciphertext; + size_t input_consumed; + for (size_t i = 0; i < message.size(); i += increment) + EXPECT_EQ(KM_ERROR_OK, + UpdateOperation(message.substr(i, increment), &ciphertext, &input_consumed)); + EXPECT_EQ(KM_ERROR_OK, FinishOperation(&ciphertext)); + EXPECT_EQ(message.size(), ciphertext.size()); + + // Move TAG_NONCE into input_params + input_params.Reinitialize(output_params); + input_params.push_back(client_params()); + input_params.push_back(TAG_BLOCK_MODE, KM_MODE_CBC); + input_params.push_back(TAG_PADDING, KM_PAD_NONE); + output_params.Clear(); + + EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, input_params, &output_params)); + string plaintext; + for (size_t i = 0; i < ciphertext.size(); i += increment) + EXPECT_EQ(KM_ERROR_OK, + UpdateOperation(ciphertext.substr(i, increment), &plaintext, &input_consumed)); + EXPECT_EQ(KM_ERROR_OK, FinishOperation(&plaintext)); + EXPECT_EQ(ciphertext.size(), plaintext.size()); + EXPECT_EQ(message, plaintext); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + typedef Keymaster2Test MaxOperationsTest; INSTANTIATE_TEST_CASE_P(AndroidKeymasterTest, MaxOperationsTest, test_params); diff --git a/tests/android_keymaster_test_utils.cpp b/tests/android_keymaster_test_utils.cpp index 6c84613..917e95e 100644 --- a/tests/android_keymaster_test_utils.cpp +++ b/tests/android_keymaster_test_utils.cpp @@ -656,6 +656,27 @@ void Keymaster2Test::CheckAesCtrTestVector(const string& key, const string& nonc EXPECT_EQ(expected_ciphertext, ciphertext); } +void Keymaster2Test::CheckTripleDesTestVector(keymaster_purpose_t purpose, + keymaster_block_mode_t block_mode, + keymaster_padding_t padding_mode, const string& key, + const string& iv, const string& input, + const string& expected_output) { + auto authset = AuthorizationSetBuilder() + .TripleDesEncryptionKey(key.size() * 7) + .Authorization(TAG_BLOCK_MODE, block_mode) + .Padding(padding_mode); + if (iv.size()) authset.Authorization(TAG_CALLER_NONCE); + + ASSERT_EQ(KM_ERROR_OK, ImportKey(authset, KM_KEY_FORMAT_RAW, key)); + + AuthorizationSet begin_params(client_params()), update_params, output_params; + if (iv.size()) begin_params.push_back(TAG_NONCE, iv.data(), iv.size()); + begin_params.push_back(TAG_BLOCK_MODE, block_mode); + begin_params.push_back(TAG_PADDING, padding_mode); + string output = ProcessMessage(purpose, input, begin_params, update_params, &output_params); + EXPECT_EQ(expected_output, output); +} + AuthorizationSet Keymaster2Test::hw_enforced() { return AuthorizationSet(characteristics_.hw_enforced); } diff --git a/tests/android_keymaster_test_utils.h b/tests/android_keymaster_test_utils.h index 381902d..c6a1641 100644 --- a/tests/android_keymaster_test_utils.h +++ b/tests/android_keymaster_test_utils.h @@ -292,6 +292,10 @@ class Keymaster2Test : public testing::TestWithParam<InstanceCreatorPtr> { const std::string& expected_ciphertext); void CheckAesCtrTestVector(const std::string& key, const std::string& nonce, const std::string& message, const std::string& expected_ciphertext); + void CheckTripleDesTestVector(keymaster_purpose_t purpose, keymaster_block_mode_t mode, + keymaster_padding_t padding, const std::string& key, + const std::string& iv, const std::string& message, + const std::string& expected_ciphertext); AuthorizationSet UserAuthParams(); AuthorizationSet ClientParams(); |
