summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShawn Willden <swillden@google.com>2018-01-08 22:00:12 -0700
committerShawn Willden <swillden@google.com>2018-01-17 14:26:08 -0700
commit7efc77216ead495bcfe4504be9040cb8a8b284ca (patch)
tree56135057227c4f245cd8be40ffb9b3a6def8cd46
parentdd7e8a099bdc6310c066d7b99f29faa8d0932c86 (diff)
downloadandroid_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.bp2
-rw-r--r--Makefile6
-rw-r--r--android_keymaster/operation.cpp1
-rw-r--r--contexts/keymaster1_passthrough_context.cpp3
-rw-r--r--contexts/pure_soft_keymaster_context.cpp8
-rw-r--r--contexts/soft_keymaster_context.cpp19
-rw-r--r--contexts/soft_keymaster_device.cpp3
-rw-r--r--include/keymaster/authorization_set.h12
-rw-r--r--include/keymaster/contexts/pure_soft_keymaster_context.h1
-rw-r--r--include/keymaster/contexts/soft_keymaster_context.h1
-rw-r--r--include/keymaster/km_openssl/triple_des_key.h61
-rw-r--r--km_openssl/triple_des_key.cpp64
-rw-r--r--km_openssl/triple_des_operation.cpp71
-rw-r--r--km_openssl/triple_des_operation.h46
-rw-r--r--legacy_support/keymaster1_legacy_support.cpp3
-rw-r--r--legacy_support/keymaster_passthrough_engine.cpp53
-rw-r--r--tests/android_keymaster_test.cpp494
-rw-r--r--tests/android_keymaster_test_utils.cpp21
-rw-r--r--tests/android_keymaster_test_utils.h4
19 files changed, 849 insertions, 24 deletions
diff --git a/Android.bp b/Android.bp
index 7d57709..aaef82d 100644
--- a/Android.bp
+++ b/Android.bp
@@ -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",
],
diff --git a/Makefile b/Makefile
index 141e453..a3f06d9 100644
--- a/Makefile
+++ b/Makefile
@@ -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();