Add AAD support to AES OCB.
Also add OCB test vectors.
Change-Id: I33074bfea142aab334916c4567f92a6645fcab9f
diff --git a/aead_mode_operation.cpp b/aead_mode_operation.cpp
index 05ed6e9..bf6f33a 100644
--- a/aead_mode_operation.cpp
+++ b/aead_mode_operation.cpp
@@ -19,6 +19,7 @@
#include <openssl/aes.h>
#include <openssl/rand.h>
+#include <keymaster/authorization_set.h>
#include <keymaster/logger.h>
#include "aead_mode_operation.h"
@@ -26,16 +27,18 @@
namespace keymaster {
-keymaster_error_t AeadModeOperation::Begin(const AuthorizationSet& /* input_params */,
- AuthorizationSet* /* output_params */) {
+keymaster_error_t AeadModeOperation::Begin(const AuthorizationSet& input_params,
+ AuthorizationSet* output_params) {
keymaster_error_t error = Initialize(key_, key_size_, nonce_length_, tag_length_);
- if (error == KM_ERROR_OK) {
- buffer_end_ = 0;
- buffer_.reset(new uint8_t[processing_unit_]);
- if (!buffer_.get())
- error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
- }
- return error;
+ if (error != KM_ERROR_OK)
+ return error;
+
+ buffer_end_ = 0;
+ buffer_.reset(new uint8_t[processing_unit_]);
+ if (!buffer_.get())
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+ return HandleNonce(input_params, output_params);
}
inline size_t min(size_t a, size_t b) {
@@ -44,7 +47,7 @@
return b;
}
-keymaster_error_t AeadModeOperation::Update(const AuthorizationSet& /* additional_params */,
+keymaster_error_t AeadModeOperation::Update(const AuthorizationSet& additional_params,
const Buffer& input, Buffer* output,
size_t* input_consumed) {
// Make an effort to reserve enough output space. The output buffer will be extended if needed,
@@ -55,39 +58,32 @@
keymaster_error_t error = KM_ERROR_OK;
*input_consumed = 0;
+ keymaster_blob_t associated_data = {0, 0};
+ additional_params.GetTagValue(TAG_ASSOCIATED_DATA, &associated_data);
+
const uint8_t* plaintext = input.peek_read();
const uint8_t* plaintext_end = plaintext + input.available_read();
while (plaintext < plaintext_end && error == KM_ERROR_OK) {
if (buffered_data_length() == processing_unit_) {
- assert(nonce_handled_);
- if (!nonce_handled_)
- return KM_ERROR_UNKNOWN_ERROR;
- error = ProcessChunk(output);
+ error = ProcessChunk(associated_data, output);
ClearBuffer();
IncrementNonce();
}
plaintext = AppendToBuffer(plaintext, plaintext_end - plaintext);
*input_consumed = plaintext - input.peek_read();
- if (!nonce_handled_)
- error = HandleNonce(output);
}
return error;
}
-keymaster_error_t AeadModeOperation::Finish(const AuthorizationSet& /* additional_params */,
+keymaster_error_t AeadModeOperation::Finish(const AuthorizationSet& additional_params,
const Buffer& /* signature */, Buffer* output) {
- keymaster_error_t error = KM_ERROR_OK;
- if (!nonce_handled_)
- error = HandleNonce(output);
- if (error != KM_ERROR_OK)
- return error;
- return ProcessChunk(output);
+ keymaster_blob_t associated_data = {0, 0};
+ additional_params.GetTagValue(TAG_ASSOCIATED_DATA, &associated_data);
+ return ProcessChunk(associated_data, output);
}
-keymaster_error_t AeadModeOperation::ProcessChunk(Buffer* output) {
- if (!nonce_handled_)
- return KM_ERROR_INVALID_INPUT_LENGTH;
-
+keymaster_error_t AeadModeOperation::ProcessChunk(const keymaster_blob_t& additional_data,
+ Buffer* output) {
keymaster_error_t error = KM_ERROR_OK;
if (purpose() == KM_PURPOSE_DECRYPT) {
if (buffered_data_length() < tag_length_)
@@ -97,14 +93,14 @@
if (!output->reserve(output->available_read() + buffered_data_length()))
error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
else
- error = DecryptChunk(nonce_, nonce_length_, tag_, tag_length_, additional_data_,
+ error = DecryptChunk(nonce_, nonce_length_, tag_, tag_length_, additional_data,
buffer_.get(), buffered_data_length(), output);
} else {
if (!output->reserve(output->available_read() + buffered_data_length() + tag_length_))
error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
else
- error = EncryptChunk(nonce_, nonce_length_, tag_length_, additional_data_,
- buffer_.get(), buffered_data_length(), output);
+ error = EncryptChunk(nonce_, nonce_length_, tag_length_, additional_data, buffer_.get(),
+ buffered_data_length(), output);
}
return error;
}
@@ -129,33 +125,61 @@
}
}
-keymaster_error_t AeadModeOperation::HandleNonce(Buffer* output) {
+keymaster_error_t AeadModeOperation::HandleNonce(const AuthorizationSet& input_params,
+ AuthorizationSet* output_params) {
+ if (!output_params)
+ return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
switch (purpose()) {
- case KM_PURPOSE_ENCRYPT:
- if (!RAND_bytes(nonce_, nonce_length_)) {
- LOG_S("Failed to generate %d-byte nonce", nonce_length_);
- return TranslateLastOpenSslError();
+ case KM_PURPOSE_ENCRYPT: {
+ keymaster_error_t error;
+ if (caller_nonce_)
+ error = ExtractNonce(input_params);
+ else {
+ if (input_params.find(TAG_NONCE) != -1)
+ /* TODO(swillden): Create and return a better error code */
+ return KM_ERROR_INVALID_ARGUMENT;
+ error = GenerateNonce();
}
- if (!output->reserve(nonce_length_))
+
+ if (error != KM_ERROR_OK)
+ return error;
+
+ output_params->push_back(TAG_NONCE, nonce_, nonce_length_);
+ if (output_params->is_valid() != AuthorizationSet::OK)
return KM_ERROR_MEMORY_ALLOCATION_FAILED;
- output->write(nonce_, nonce_length_);
- nonce_handled_ = true;
break;
+ }
case KM_PURPOSE_DECRYPT:
- if (buffered_data_length() >= nonce_length_) {
- memcpy(nonce_, buffer_.get(), nonce_length_);
- memmove(buffer_.get(), buffer_.get() + nonce_length_,
- buffered_data_length() - nonce_length_);
- buffer_end_ -= nonce_length_;
- nonce_handled_ = true;
- }
- break;
+ return ExtractNonce(input_params);
+
default:
return KM_ERROR_UNSUPPORTED_PURPOSE;
}
return KM_ERROR_OK;
}
+keymaster_error_t AeadModeOperation::GenerateNonce() {
+ if (RAND_bytes(nonce_, nonce_length_))
+ return KM_ERROR_OK;
+ LOG_S("Failed to generate %d-byte nonce", nonce_length_);
+ return TranslateLastOpenSslError();
+}
+
+keymaster_error_t AeadModeOperation::ExtractNonce(const AuthorizationSet& input_params) {
+ keymaster_blob_t nonce_blob;
+ if (!input_params.GetTagValue(TAG_NONCE, &nonce_blob))
+ /* TODO(swillden): Add a better error return code for this case. */
+ return KM_ERROR_INVALID_ARGUMENT;
+
+ if (nonce_blob.data_length != nonce_length_)
+ /* TODO(swillden): Add a better error return code for this case. */
+ return KM_ERROR_INVALID_ARGUMENT;
+
+ memcpy(nonce_, nonce_blob.data, nonce_length_);
+ return KM_ERROR_OK;
+}
+
void AeadModeOperation::IncrementNonce() {
for (int i = nonce_length_ - 1; i > 0; --i)
if (++nonce_[i])
diff --git a/aead_mode_operation.h b/aead_mode_operation.h
index e89da20..e7eecb7 100644
--- a/aead_mode_operation.h
+++ b/aead_mode_operation.h
@@ -30,22 +30,19 @@
AeadModeOperation(keymaster_purpose_t purpose, const uint8_t* key, size_t key_size,
size_t chunk_length, size_t tag_length, size_t nonce_length,
- keymaster_blob_t additional_data)
+ bool caller_nonce)
: Operation(purpose), key_size_(key_size), tag_length_(tag_length),
nonce_length_(nonce_length),
processing_unit_(purpose == KM_PURPOSE_DECRYPT ? chunk_length + tag_length
: chunk_length),
- additional_data_(additional_data), nonce_handled_(false) {
-
+ caller_nonce_(caller_nonce) {
assert(key_size <= MAX_KEY_LENGTH);
memcpy(key_, key, key_size);
}
~AeadModeOperation() {
// Wipe sensitive buffers.
memset_s(buffer_.get(), 0, processing_unit_);
- memset_s(const_cast<uint8_t*>(additional_data_.data), 0, additional_data_.data_length);
memset_s(key_, 0, MAX_KEY_LENGTH);
- delete[] additional_data_.data;
}
virtual keymaster_error_t Begin(const AuthorizationSet& input_params,
@@ -79,25 +76,26 @@
size_t chunk_size, Buffer* output) = 0;
size_t EstimateOutputSize(const Buffer& input, Buffer* output);
- keymaster_error_t ProcessChunk(Buffer* output);
+ keymaster_error_t ProcessChunk(const keymaster_blob_t& associated_data, Buffer* output);
size_t buffer_free_space() const { return processing_unit_ - buffer_end_; }
const uint8_t* AppendToBuffer(const uint8_t* data, size_t data_length);
- void ExtractNonceFromBuffer();
void ExtractTagFromBuffer();
void ClearBuffer() { buffer_end_ = 0; }
- keymaster_error_t HandleNonce(Buffer* output);
+ keymaster_error_t HandleNonce(const AuthorizationSet& input_params,
+ AuthorizationSet* output_params);
+ keymaster_error_t ExtractNonce(const AuthorizationSet& input_params);
+ keymaster_error_t GenerateNonce();
void IncrementNonce();
const size_t key_size_;
const size_t tag_length_;
const size_t nonce_length_;
const size_t processing_unit_;
- const keymaster_blob_t additional_data_;
+ const bool caller_nonce_;
UniquePtr<uint8_t[]> buffer_;
size_t buffer_end_;
- bool nonce_handled_;
uint8_t __attribute__((aligned(16))) key_[MAX_KEY_LENGTH];
uint8_t __attribute__((aligned(16))) tag_[MAX_TAG_LENGTH];
uint8_t __attribute__((aligned(16))) nonce_[MAX_NONCE_LENGTH];
diff --git a/aes_operation.cpp b/aes_operation.cpp
index ceebf34..701e55f 100644
--- a/aes_operation.cpp
+++ b/aes_operation.cpp
@@ -117,11 +117,10 @@
if (*error != KM_ERROR_OK)
return NULL;
- keymaster_blob_t additional_data = {0, 0};
- key.authorizations().GetTagValue(TAG_ASSOCIATED_DATA, &additional_data);
+ bool caller_nonce = key.authorizations().GetTagValue(TAG_CALLER_NONCE);
Operation* op = new AesOcbOperation(purpose(), key.key_data(), key.key_data_size(),
- chunk_length, tag_length, additional_data);
+ chunk_length, tag_length, caller_nonce);
if (!op)
*error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
return op;
diff --git a/aes_operation.h b/aes_operation.h
index aaa53a4..c097989 100644
--- a/aes_operation.h
+++ b/aes_operation.h
@@ -30,9 +30,9 @@
static const size_t NONCE_LENGTH = 12;
AesOcbOperation(keymaster_purpose_t purpose, const uint8_t* key, size_t key_size,
- size_t chunk_length, size_t tag_length, keymaster_blob_t additional_data)
+ size_t chunk_length, size_t tag_length, bool caller_nonce)
: AeadModeOperation(purpose, key, key_size, chunk_length, tag_length, NONCE_LENGTH,
- additional_data) {}
+ caller_nonce) {}
virtual keymaster_error_t Abort() {
/* All cleanup is in the dtor */
@@ -67,7 +67,7 @@
virtual keymaster_error_t Update(const AuthorizationSet& additional_params, const Buffer& input,
Buffer* output, size_t* input_consumed);
virtual keymaster_error_t Finish(const AuthorizationSet& additional_params,
- const Buffer& /* signature */, Buffer* output);
+ const Buffer& signature, Buffer* output);
virtual keymaster_error_t Abort();
virtual int evp_encrypt_mode() = 0;
diff --git a/authorization_set.cpp b/authorization_set.cpp
index 01e66a5..124baba 100644
--- a/authorization_set.cpp
+++ b/authorization_set.cpp
@@ -487,4 +487,13 @@
return true;
}
+bool AuthorizationSet::GetTagValueBool(keymaster_tag_t tag) const {
+ int pos = find(tag);
+ if (pos == -1) {
+ return false;
+ }
+ assert(elems_[pos].boolean);
+ return elems_[pos].boolean;
+}
+
} // namespace keymaster
diff --git a/google_keymaster_test.cpp b/google_keymaster_test.cpp
index e2a2102..06479a7 100644
--- a/google_keymaster_test.cpp
+++ b/google_keymaster_test.cpp
@@ -81,6 +81,11 @@
return *this;
}
+ template <keymaster_tag_t Tag> ParamBuilder& Option(TypedTag<KM_BOOL, Tag> tag) {
+ set.push_back(tag);
+ return *this;
+ }
+
ParamBuilder& RsaKey(uint32_t key_size = 0, uint64_t public_exponent = 0) {
Option(TAG_ALGORITHM, KM_ALGORITHM_RSA);
if (key_size != 0)
@@ -164,12 +169,24 @@
AuthorizationSet set;
};
+inline string make_string(const uint8_t* data, size_t length) {
+ return string(reinterpret_cast<const char*>(data), length);
+}
+
+template <size_t N> string make_string(const uint8_t(&a)[N]) {
+ return make_string(a, N);
+}
+
+static string make_string(const uint8_t(&)[0]) {
+ return string();
+}
+
StdoutLogger logger;
const uint64_t OP_HANDLE_SENTINEL = 0xFFFFFFFFFFFFFFFF;
class KeymasterTest : public testing::Test {
protected:
- KeymasterTest() : out_params_(NULL), op_handle_(OP_HANDLE_SENTINEL), characteristics_(NULL) {
+ KeymasterTest() : op_handle_(OP_HANDLE_SENTINEL), characteristics_(NULL) {
blob_.key_material = NULL;
RAND_seed("foobar", 6);
blob_.key_material = 0;
@@ -223,9 +240,35 @@
}
keymaster_error_t BeginOperation(keymaster_purpose_t purpose) {
- return device()->begin(device(), purpose, &blob_, client_params_,
- array_length(client_params_), &out_params_, &out_params_count_,
- &op_handle_);
+ keymaster_key_param_t* out_params = NULL;
+ size_t out_params_count = 0;
+ keymaster_error_t error =
+ device()->begin(device(), purpose, &blob_, client_params_, array_length(client_params_),
+ &out_params, &out_params_count, &op_handle_);
+ EXPECT_EQ(0, out_params_count);
+ EXPECT_TRUE(out_params == NULL);
+ return error;
+ }
+
+ keymaster_error_t BeginOperation(keymaster_purpose_t purpose, const AuthorizationSet& input_set,
+ AuthorizationSet* output_set = NULL) {
+ AuthorizationSet additional_params(client_params_, array_length(client_params_));
+ additional_params.push_back(input_set);
+
+ keymaster_key_param_t* out_params;
+ size_t out_params_count;
+ keymaster_error_t error =
+ device()->begin(device(), purpose, &blob_, additional_params.data(),
+ additional_params.size(), &out_params, &out_params_count, &op_handle_);
+ if (output_set) {
+ output_set->Reinitialize(out_params, out_params_count);
+ } else {
+ EXPECT_EQ(0, out_params_count);
+ EXPECT_TRUE(out_params == NULL);
+ }
+ keymaster_free_param_values(out_params, out_params_count);
+ free(out_params);
+ return error;
}
keymaster_error_t UpdateOperation(const string& message, string* output,
@@ -233,8 +276,24 @@
uint8_t* out_tmp = NULL;
size_t out_length;
EXPECT_NE(op_handle_, OP_HANDLE_SENTINEL);
+ keymaster_error_t error =
+ device()->update(device(), op_handle_, NULL /* params */, 0 /* params_count */,
+ reinterpret_cast<const uint8_t*>(message.c_str()), message.length(),
+ input_consumed, &out_tmp, &out_length);
+ if (out_tmp)
+ output->append(reinterpret_cast<char*>(out_tmp), out_length);
+ free(out_tmp);
+ return error;
+ }
+
+ keymaster_error_t UpdateOperation(const AuthorizationSet& additional_params,
+ const string& message, string* output,
+ size_t* input_consumed) {
+ uint8_t* out_tmp = NULL;
+ size_t out_length;
+ EXPECT_NE(op_handle_, OP_HANDLE_SENTINEL);
keymaster_error_t error = device()->update(
- device(), op_handle_, NULL /* additional_params */, 0 /* additional_params_count */,
+ device(), op_handle_, additional_params.data(), additional_params.size(),
reinterpret_cast<const uint8_t*>(message.c_str()), message.length(), input_consumed,
&out_tmp, &out_length);
if (out_tmp)
@@ -246,10 +305,16 @@
keymaster_error_t FinishOperation(string* output) { return FinishOperation("", output); }
keymaster_error_t FinishOperation(const string& signature, string* output) {
+ AuthorizationSet additional_params;
+ return FinishOperation(additional_params, signature, output);
+ }
+
+ keymaster_error_t FinishOperation(const AuthorizationSet& additional_params,
+ const string& signature, string* output) {
uint8_t* out_tmp = NULL;
size_t out_length;
keymaster_error_t error = device()->finish(
- device(), op_handle_, NULL /* additional_params */, 0 /* additional_params_count */,
+ device(), op_handle_, additional_params.data(), additional_params.size(),
reinterpret_cast<const uint8_t*>(signature.c_str()), signature.length(), &out_tmp,
&out_length);
if (out_tmp)
@@ -271,7 +336,8 @@
keymaster_error_t AbortOperation() { return device()->abort(device(), op_handle_); }
string ProcessMessage(keymaster_purpose_t purpose, const string& message) {
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(purpose));
+ AuthorizationSet input_params;
+ EXPECT_EQ(KM_ERROR_OK, BeginOperation(purpose, input_params, NULL /* output_params */));
string result;
size_t input_consumed;
@@ -282,8 +348,23 @@
}
string ProcessMessage(keymaster_purpose_t purpose, const string& message,
+ const AuthorizationSet& begin_params,
+ const AuthorizationSet& update_params,
+ AuthorizationSet* output_params = NULL) {
+ EXPECT_EQ(KM_ERROR_OK, BeginOperation(purpose, begin_params, output_params));
+
+ string result;
+ size_t input_consumed;
+ EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, message, &result, &input_consumed));
+ EXPECT_EQ(message.size(), input_consumed);
+ EXPECT_EQ(KM_ERROR_OK, FinishOperation(update_params, "", &result));
+ return result;
+ }
+
+ string ProcessMessage(keymaster_purpose_t purpose, const string& message,
const string& signature) {
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(purpose));
+ AuthorizationSet input_params;
+ EXPECT_EQ(KM_ERROR_OK, BeginOperation(purpose, input_params, NULL /* output_params */));
string result;
size_t input_consumed;
@@ -304,9 +385,33 @@
ProcessMessage(KM_PURPOSE_VERIFY, message, signature);
}
- string EncryptMessage(const string& message) {
+ string EncryptMessage(const string& message, string* generated_nonce = NULL) {
+ AuthorizationSet update_params;
+ return EncryptMessage(update_params, message, generated_nonce);
+ }
+
+ string EncryptMessage(const AuthorizationSet& update_params, const string& message,
+ string* generated_nonce = NULL) {
SCOPED_TRACE("EncryptMessage");
- return ProcessMessage(KM_PURPOSE_ENCRYPT, message);
+ AuthorizationSet begin_params, output_params;
+ string ciphertext = ProcessMessage(KM_PURPOSE_ENCRYPT, message, begin_params, update_params,
+ &output_params);
+ if (generated_nonce) {
+ keymaster_blob_t nonce_blob;
+ EXPECT_TRUE(output_params.GetTagValue(TAG_NONCE, &nonce_blob));
+ *generated_nonce = make_string(nonce_blob.data, nonce_blob.data_length);
+ } else {
+ EXPECT_EQ(-1, output_params.find(TAG_NONCE));
+ }
+ return ciphertext;
+ }
+
+ string EncryptMessageWithParams(const string& message, const AuthorizationSet& begin_params,
+ const AuthorizationSet& update_params,
+ AuthorizationSet* output_params) {
+ SCOPED_TRACE("EncryptMessageWithParams");
+ return ProcessMessage(KM_PURPOSE_ENCRYPT, message, begin_params, update_params,
+ output_params);
}
string DecryptMessage(const string& ciphertext) {
@@ -314,6 +419,20 @@
return ProcessMessage(KM_PURPOSE_DECRYPT, ciphertext);
}
+ string DecryptMessage(const string& ciphertext, const string& nonce) {
+ SCOPED_TRACE("DecryptMessage");
+ AuthorizationSet update_params;
+ return DecryptMessage(update_params, ciphertext, nonce);
+ }
+
+ string DecryptMessage(const AuthorizationSet& update_params, const string& ciphertext,
+ const string& nonce) {
+ SCOPED_TRACE("DecryptMessage");
+ AuthorizationSet begin_params;
+ begin_params.push_back(TAG_NONCE, nonce.data(), nonce.size());
+ return ProcessMessage(KM_PURPOSE_DECRYPT, ciphertext, begin_params, update_params);
+ }
+
keymaster_error_t GetCharacteristics() {
FreeCharacteristics();
return device()->get_key_characteristics(device(), &blob_, &client_id_, NULL /* app_data */,
@@ -358,6 +477,24 @@
EXPECT_EQ(expected_mac, signature) << "Test vector didn't match for digest " << digest;
}
+ void CheckAesOcbTestVector(const string& key, const string& nonce,
+ const string& associated_data, const string& message,
+ const string& expected_ciphertext) {
+ ASSERT_EQ(KM_ERROR_OK, ImportKey(ParamBuilder()
+ .AesEncryptionKey(key.size() * 8)
+ .OcbMode(4096 /* chunk length */, 16 /* tag length */)
+ .Option(TAG_CALLER_NONCE),
+ KM_KEY_FORMAT_RAW, key));
+
+ AuthorizationSet begin_params, update_params, output_params;
+ begin_params.push_back(TAG_NONCE, nonce.data(), nonce.size());
+ update_params.push_back(TAG_ASSOCIATED_DATA, associated_data.data(),
+ associated_data.size());
+ string ciphertext =
+ EncryptMessageWithParams(message, begin_params, update_params, &output_params);
+ EXPECT_EQ(expected_ciphertext, ciphertext);
+ }
+
AuthorizationSet hw_enforced() {
EXPECT_TRUE(characteristics_ != NULL);
return AuthorizationSet(characteristics_->hw_enforced);
@@ -392,8 +529,6 @@
keymaster_key_param_t client_params_[1] = {
Authorization(TAG_APPLICATION_ID, client_id_.data, client_id_.data_length)};
- keymaster_key_param_t* out_params_;
- size_t out_params_count_;
uint64_t op_handle_;
keymaster_key_blob_t blob_;
@@ -739,6 +874,7 @@
TEST_F(SigningOperationsTest, RsaAbort) {
ASSERT_EQ(KM_ERROR_OK, GenerateKey(ParamBuilder().RsaSigningKey(256)));
+ AuthorizationSet input_params, output_params;
ASSERT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_SIGN));
EXPECT_EQ(KM_ERROR_OK, AbortOperation());
// Another abort should fail
@@ -814,10 +950,6 @@
ASSERT_EQ(64, signature.size());
}
-template <size_t N> string make_string(const uint8_t(&a)[N]) {
- return string(reinterpret_cast<const char*>(a), N);
-}
-
TEST_F(SigningOperationsTest, HmacRfc4231TestCase1) {
uint8_t key_data[] = {
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
@@ -1477,8 +1609,9 @@
EXPECT_TRUE(contains(sw_enforced(), KM_TAG_CREATION_DATETIME));
string message = "Hello World!";
- string ciphertext = EncryptMessage(message);
- string plaintext = DecryptMessage(ciphertext);
+ string nonce;
+ string ciphertext = EncryptMessage(message, &nonce);
+ string plaintext = DecryptMessage(ciphertext, nonce);
EXPECT_EQ(message, plaintext);
}
@@ -1620,35 +1753,47 @@
TEST_F(EncryptionOperationsTest, AesOcbSuccess) {
ASSERT_EQ(KM_ERROR_OK, GenerateKey(ParamBuilder().AesEncryptionKey(128).OcbMode(4096, 16)));
string message = "Hello World!";
- string ciphertext1 = EncryptMessage(string(message));
- EXPECT_EQ(12 /* nonce */ + message.size() + 16 /* tag */, ciphertext1.size());
+ string nonce1;
+ string ciphertext1 = EncryptMessage(message, &nonce1);
+ EXPECT_EQ(12, nonce1.size());
+ EXPECT_EQ(message.size() + 16 /* tag */, ciphertext1.size());
- string ciphertext2 = EncryptMessage(string(message));
- EXPECT_EQ(12 /* nonce */ + message.size() + 16 /* tag */, ciphertext2.size());
+ string nonce2;
+ string ciphertext2 = EncryptMessage(message, &nonce2);
+ EXPECT_EQ(12, nonce2.size());
+ EXPECT_EQ(message.size() + 16 /* tag */, ciphertext2.size());
- // OCB uses a random nonce, so every output should be different
+ // Nonces should be random
+ EXPECT_NE(nonce1, nonce2);
+
+ // Therefore ciphertexts are different
EXPECT_NE(ciphertext1, ciphertext2);
}
TEST_F(EncryptionOperationsTest, AesOcbRoundTripSuccess) {
ASSERT_EQ(KM_ERROR_OK, GenerateKey(ParamBuilder().AesEncryptionKey(128).OcbMode(4096, 16)));
string message = "Hello World!";
- string ciphertext = EncryptMessage(message);
- EXPECT_EQ(12 /* nonce */ + message.length() + 16 /* tag */, ciphertext.size());
+ string nonce;
+ string ciphertext = EncryptMessage(message, &nonce);
+ EXPECT_EQ(12, nonce.size());
+ EXPECT_EQ(message.length() + 16 /* tag */, ciphertext.size());
- string plaintext = DecryptMessage(ciphertext);
+ string plaintext = DecryptMessage(ciphertext, nonce);
EXPECT_EQ(message, plaintext);
}
TEST_F(EncryptionOperationsTest, AesOcbRoundTripCorrupted) {
ASSERT_EQ(KM_ERROR_OK, GenerateKey(ParamBuilder().AesEncryptionKey(128).OcbMode(4096, 16)));
string message = "Hello World!";
- string ciphertext = EncryptMessage(string(message));
- EXPECT_EQ(12 /* nonce */ + message.size() + 16 /* tag */, ciphertext.size());
+ string nonce;
+ string ciphertext = EncryptMessage(message, &nonce);
+ EXPECT_EQ(message.size() + 16 /* tag */, ciphertext.size());
ciphertext[ciphertext.size() / 2]++;
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT));
+ AuthorizationSet input_set, output_set;
+ input_set.push_back(TAG_NONCE, nonce.data(), nonce.size());
+ EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, input_set, &output_set));
string result;
size_t input_consumed;
@@ -1660,7 +1805,9 @@
TEST_F(EncryptionOperationsTest, AesDecryptGarbage) {
ASSERT_EQ(KM_ERROR_OK, GenerateKey(ParamBuilder().AesEncryptionKey(128).OcbMode(4096, 16)));
string ciphertext(128, 'a');
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT));
+ AuthorizationSet input_params;
+ input_params.push_back(TAG_NONCE, "aaaaaaaaaaaa", 12);
+ EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, input_params));
string result;
size_t input_consumed;
@@ -1669,39 +1816,41 @@
EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED, FinishOperation(&result));
}
-TEST_F(EncryptionOperationsTest, AesDecryptTooShort) {
+TEST_F(EncryptionOperationsTest, AesDecryptTooShortNonce) {
ASSERT_EQ(KM_ERROR_OK, GenerateKey(ParamBuilder().AesEncryptionKey(128).OcbMode(4096, 16)));
- // Try decrypting garbage ciphertext that is too short to be valid (< nonce + tag).
- string ciphertext(12 + 15, 'a');
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT));
-
- string result;
- size_t input_consumed;
- EXPECT_EQ(KM_ERROR_OK, UpdateOperation(ciphertext, &result, &input_consumed));
- EXPECT_EQ(ciphertext.length(), input_consumed);
- EXPECT_EQ(KM_ERROR_INVALID_INPUT_LENGTH, FinishOperation(&result));
+ // Try decrypting garbage ciphertext with too-short nonce
+ string ciphertext(15, 'a');
+ AuthorizationSet input_params;
+ input_params.push_back(TAG_NONCE, "aaaaaaaaaaa", 11);
+ EXPECT_EQ(KM_ERROR_INVALID_ARGUMENT, BeginOperation(KM_PURPOSE_DECRYPT, input_params));
}
TEST_F(EncryptionOperationsTest, AesOcbRoundTripEmptySuccess) {
ASSERT_EQ(KM_ERROR_OK, GenerateKey(ParamBuilder().AesEncryptionKey(128).OcbMode(4096, 16)));
string message = "";
- string ciphertext = EncryptMessage(string(message));
- EXPECT_EQ(12 /* nonce */ + message.size() + 16 /* tag */, ciphertext.size());
+ string nonce;
+ string ciphertext = EncryptMessage(message, &nonce);
+ EXPECT_EQ(12, nonce.size());
+ EXPECT_EQ(message.size() + 16 /* tag */, ciphertext.size());
- string plaintext = DecryptMessage(ciphertext);
+ string plaintext = DecryptMessage(ciphertext, nonce);
EXPECT_EQ(message, plaintext);
}
TEST_F(EncryptionOperationsTest, AesOcbRoundTripEmptyCorrupted) {
ASSERT_EQ(KM_ERROR_OK, GenerateKey(ParamBuilder().AesEncryptionKey(128).OcbMode(4096, 16)));
string message = "";
- string ciphertext = EncryptMessage(string(message));
- EXPECT_EQ(12 /* nonce */ + message.size() + 16 /* tag */, ciphertext.size());
+ string nonce;
+ string ciphertext = EncryptMessage(message, &nonce);
+ EXPECT_EQ(12, nonce.size());
+ EXPECT_EQ(message.size() + 16 /* tag */, ciphertext.size());
ciphertext[ciphertext.size() / 2]++;
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT));
+ AuthorizationSet input_set;
+ input_set.push_back(TAG_NONCE, nonce.data(), nonce.size());
+ EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, input_set));
string result;
size_t input_consumed;
@@ -1713,10 +1862,11 @@
TEST_F(EncryptionOperationsTest, AesOcbFullChunk) {
ASSERT_EQ(KM_ERROR_OK, GenerateKey(ParamBuilder().AesEncryptionKey(128).OcbMode(4096, 16)));
string message(4096, 'a');
- string ciphertext = EncryptMessage(message);
- EXPECT_EQ(12 /* nonce */ + message.length() + 16 /* tag */, ciphertext.size());
+ string nonce;
+ string ciphertext = EncryptMessage(message, &nonce);
+ EXPECT_EQ(message.length() + 16 /* tag */, ciphertext.size());
- string plaintext = DecryptMessage(ciphertext);
+ string plaintext = DecryptMessage(ciphertext, nonce);
EXPECT_EQ(message, plaintext);
}
@@ -1725,15 +1875,16 @@
ASSERT_EQ(KM_ERROR_OK,
GenerateKey(ParamBuilder().AesEncryptionKey(128).OcbMode(chunk_length, 16)));
string message(128, 'a');
- string ciphertext = EncryptMessage(message);
+ string nonce;
+ string ciphertext = EncryptMessage(message, &nonce);
int expected_tag_count = (message.length() + chunk_length - 1) / chunk_length;
- EXPECT_EQ(12 /* nonce */ + message.length() + 16 * expected_tag_count, ciphertext.size())
+ EXPECT_EQ(message.length() + 16 * expected_tag_count, ciphertext.size())
<< "Unexpected ciphertext size for chunk length " << chunk_length
<< " expected tag count was " << expected_tag_count
<< " but actual tag count was probably "
<< (ciphertext.size() - message.length() - 12) / 16;
- string plaintext = DecryptMessage(ciphertext);
+ string plaintext = DecryptMessage(ciphertext, nonce);
EXPECT_EQ(message, plaintext);
}
}
@@ -1742,7 +1893,10 @@
ASSERT_EQ(KM_ERROR_OK, GenerateKey(ParamBuilder().AesEncryptionKey(128).OcbMode(4096, 16)));
string message = "Hello";
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT));
+ AuthorizationSet input_set, output_set;
+ EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, input_set, &output_set));
+ EXPECT_EQ(1, output_set.size());
+ EXPECT_EQ(0, output_set.find(TAG_NONCE));
string result;
size_t input_consumed;
@@ -1771,6 +1925,303 @@
EXPECT_EQ(KM_ERROR_INVALID_ARGUMENT, BeginOperation(KM_PURPOSE_ENCRYPT));
}
+uint8_t rfc_7523_test_key_data[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+};
+string rfc_7523_test_key = make_string(rfc_7523_test_key_data);
+
+TEST_F(EncryptionOperationsTest, AesOcbRfc7253TestVector1) {
+ uint8_t nonce[] = {
+ 0xBB, 0xAA, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00,
+ };
+ uint8_t expected_ciphertext[] = {
+ 0x78, 0x54, 0x07, 0xBF, 0xFF, 0xC8, 0xAD, 0x9E,
+ 0xDC, 0xC5, 0x52, 0x0A, 0xC9, 0x11, 0x1E, 0xE6,
+ };
+ CheckAesOcbTestVector(rfc_7523_test_key, make_string(nonce), "" /* associated_data */,
+ "" /* plaintext */, make_string(expected_ciphertext));
+}
+
+TEST_F(EncryptionOperationsTest, AesOcbRfc7253TestVector2) {
+ uint8_t nonce[] = {
+ 0xBB, 0xAA, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x01,
+ };
+ uint8_t associated_data[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ };
+ uint8_t plaintext[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ };
+ uint8_t expected_ciphertext[] = {
+ 0x68, 0x20, 0xB3, 0x65, 0x7B, 0x6F, 0x61, 0x5A, 0x57, 0x25, 0xBD, 0xA0,
+ 0xD3, 0xB4, 0xEB, 0x3A, 0x25, 0x7C, 0x9A, 0xF1, 0xF8, 0xF0, 0x30, 0x09,
+ };
+ CheckAesOcbTestVector(rfc_7523_test_key, make_string(nonce), make_string(associated_data),
+ make_string(plaintext), make_string(expected_ciphertext));
+}
+
+TEST_F(EncryptionOperationsTest, AesOcbRfc7253TestVector3) {
+ uint8_t nonce[] = {
+ 0xBB, 0xAA, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x02,
+ };
+ uint8_t associated_data[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ };
+ uint8_t expected_ciphertext[] = {
+ 0x81, 0x01, 0x7F, 0x82, 0x03, 0xF0, 0x81, 0x27,
+ 0x71, 0x52, 0xFA, 0xDE, 0x69, 0x4A, 0x0A, 0x00,
+ };
+ CheckAesOcbTestVector(rfc_7523_test_key, make_string(nonce), make_string(associated_data),
+ "" /* plaintext */, make_string(expected_ciphertext));
+}
+
+TEST_F(EncryptionOperationsTest, AesOcbRfc7253TestVector4) {
+ uint8_t nonce[] = {
+ 0xBB, 0xAA, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x03,
+ };
+ uint8_t plaintext[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ };
+ uint8_t expected_ciphertext[] = {
+ 0x45, 0xDD, 0x69, 0xF8, 0xF5, 0xAA, 0xE7, 0x24, 0x14, 0x05, 0x4C, 0xD1,
+ 0xF3, 0x5D, 0x82, 0x76, 0x0B, 0x2C, 0xD0, 0x0D, 0x2F, 0x99, 0xBF, 0xA9,
+ };
+ CheckAesOcbTestVector(rfc_7523_test_key, make_string(nonce), "" /* associated_data */,
+ make_string(plaintext), make_string(expected_ciphertext));
+}
+
+TEST_F(EncryptionOperationsTest, AesOcbRfc7253TestVector5) {
+ uint8_t nonce[] = {
+ 0xBB, 0xAA, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x04,
+ };
+ uint8_t associated_data[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ };
+ uint8_t plaintext[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ };
+ uint8_t expected_ciphertext[] = {
+ 0x57, 0x1D, 0x53, 0x5B, 0x60, 0xB2, 0x77, 0x18, 0x8B, 0xE5, 0x14,
+ 0x71, 0x70, 0xA9, 0xA2, 0x2C, 0x3A, 0xD7, 0xA4, 0xFF, 0x38, 0x35,
+ 0xB8, 0xC5, 0x70, 0x1C, 0x1C, 0xCE, 0xC8, 0xFC, 0x33, 0x58,
+ };
+ CheckAesOcbTestVector(rfc_7523_test_key, make_string(nonce), make_string(associated_data),
+ make_string(plaintext), make_string(expected_ciphertext));
+}
+
+TEST_F(EncryptionOperationsTest, AesOcbRfc7253TestVector6) {
+ uint8_t nonce[] = {
+ 0xBB, 0xAA, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x05,
+ };
+ uint8_t associated_data[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ };
+ uint8_t expected_ciphertext[] = {
+ 0x8C, 0xF7, 0x61, 0xB6, 0x90, 0x2E, 0xF7, 0x64,
+ 0x46, 0x2A, 0xD8, 0x64, 0x98, 0xCA, 0x6B, 0x97,
+ };
+ CheckAesOcbTestVector(rfc_7523_test_key, make_string(nonce), make_string(associated_data),
+ "" /* plaintext */, make_string(expected_ciphertext));
+}
+
+TEST_F(EncryptionOperationsTest, AesOcbRfc7253TestVector7) {
+ uint8_t nonce[] = {
+ 0xBB, 0xAA, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x06,
+ };
+ uint8_t plaintext[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ };
+ uint8_t expected_ciphertext[] = {
+ 0x5C, 0xE8, 0x8E, 0xC2, 0xE0, 0x69, 0x27, 0x06, 0xA9, 0x15, 0xC0,
+ 0x0A, 0xEB, 0x8B, 0x23, 0x96, 0xF4, 0x0E, 0x1C, 0x74, 0x3F, 0x52,
+ 0x43, 0x6B, 0xDF, 0x06, 0xD8, 0xFA, 0x1E, 0xCA, 0x34, 0x3D,
+ };
+ CheckAesOcbTestVector(rfc_7523_test_key, make_string(nonce), "" /* associated_data */,
+ make_string(plaintext), make_string(expected_ciphertext));
+}
+
+TEST_F(EncryptionOperationsTest, AesOcbRfc7253TestVector8) {
+ uint8_t nonce[] = {
+ 0xBB, 0xAA, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x07,
+ };
+ uint8_t associated_data[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
+ 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ };
+ uint8_t plaintext[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
+ 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ };
+ uint8_t expected_ciphertext[] = {
+ 0x1C, 0xA2, 0x20, 0x73, 0x08, 0xC8, 0x7C, 0x01, 0x07, 0x56, 0x10, 0x4D, 0x88, 0x40,
+ 0xCE, 0x19, 0x52, 0xF0, 0x96, 0x73, 0xA4, 0x48, 0xA1, 0x22, 0xC9, 0x2C, 0x62, 0x24,
+ 0x10, 0x51, 0xF5, 0x73, 0x56, 0xD7, 0xF3, 0xC9, 0x0B, 0xB0, 0xE0, 0x7F,
+ };
+ CheckAesOcbTestVector(rfc_7523_test_key, make_string(nonce), make_string(associated_data),
+ make_string(plaintext), make_string(expected_ciphertext));
+}
+
+TEST_F(EncryptionOperationsTest, AesOcbRfc7253TestVector9) {
+ uint8_t nonce[] = {
+ 0xBB, 0xAA, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x08,
+ };
+ uint8_t associated_data[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
+ 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ };
+ uint8_t expected_ciphertext[] = {
+ 0x6D, 0xC2, 0x25, 0xA0, 0x71, 0xFC, 0x1B, 0x9F,
+ 0x7C, 0x69, 0xF9, 0x3B, 0x0F, 0x1E, 0x10, 0xDE,
+ };
+ CheckAesOcbTestVector(rfc_7523_test_key, make_string(nonce), make_string(associated_data),
+ "" /* plaintext */, make_string(expected_ciphertext));
+}
+
+TEST_F(EncryptionOperationsTest, AesOcbRfc7253TestVector10) {
+ uint8_t nonce[] = {
+ 0xBB, 0xAA, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x09,
+ };
+ uint8_t plaintext[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
+ 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ };
+ uint8_t expected_ciphertext[] = {
+ 0x22, 0x1B, 0xD0, 0xDE, 0x7F, 0xA6, 0xFE, 0x99, 0x3E, 0xCC, 0xD7, 0x69, 0x46, 0x0A,
+ 0x0A, 0xF2, 0xD6, 0xCD, 0xED, 0x0C, 0x39, 0x5B, 0x1C, 0x3C, 0xE7, 0x25, 0xF3, 0x24,
+ 0x94, 0xB9, 0xF9, 0x14, 0xD8, 0x5C, 0x0B, 0x1E, 0xB3, 0x83, 0x57, 0xFF,
+ };
+ CheckAesOcbTestVector(rfc_7523_test_key, make_string(nonce), "" /* associated_data */,
+ make_string(plaintext), make_string(expected_ciphertext));
+}
+
+TEST_F(EncryptionOperationsTest, AesOcbRfc7253TestVector11) {
+ uint8_t nonce[] = {
+ 0xBB, 0xAA, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x0A,
+ };
+ uint8_t associated_data[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
+ 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
+ 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
+ };
+ uint8_t plaintext[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
+ 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
+ 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
+ };
+ uint8_t expected_ciphertext[] = {
+ 0xBD, 0x6F, 0x6C, 0x49, 0x62, 0x01, 0xC6, 0x92, 0x96, 0xC1, 0x1E, 0xFD,
+ 0x13, 0x8A, 0x46, 0x7A, 0xBD, 0x3C, 0x70, 0x79, 0x24, 0xB9, 0x64, 0xDE,
+ 0xAF, 0xFC, 0x40, 0x31, 0x9A, 0xF5, 0xA4, 0x85, 0x40, 0xFB, 0xBA, 0x18,
+ 0x6C, 0x55, 0x53, 0xC6, 0x8A, 0xD9, 0xF5, 0x92, 0xA7, 0x9A, 0x42, 0x40,
+ };
+ CheckAesOcbTestVector(rfc_7523_test_key, make_string(nonce), make_string(associated_data),
+ make_string(plaintext), make_string(expected_ciphertext));
+}
+
+TEST_F(EncryptionOperationsTest, AesOcbRfc7253TestVector12) {
+ uint8_t nonce[] = {
+ 0xBB, 0xAA, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x0B,
+ };
+ uint8_t associated_data[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
+ 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
+ 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
+ };
+ uint8_t plaintext[] = {};
+ uint8_t expected_ciphertext[] = {
+ 0xFE, 0x80, 0x69, 0x0B, 0xEE, 0x8A, 0x48, 0x5D,
+ 0x11, 0xF3, 0x29, 0x65, 0xBC, 0x9D, 0x2A, 0x32,
+ };
+ CheckAesOcbTestVector(rfc_7523_test_key, make_string(nonce), make_string(associated_data),
+ "" /* plaintext */, make_string(expected_ciphertext));
+}
+
+TEST_F(EncryptionOperationsTest, AesOcbRfc7253TestVector13) {
+ uint8_t nonce[] = {
+ 0xBB, 0xAA, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x0C,
+ };
+ uint8_t associated_data[] = {};
+ uint8_t plaintext[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
+ 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
+ 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
+ };
+ uint8_t expected_ciphertext[] = {
+ 0x29, 0x42, 0xBF, 0xC7, 0x73, 0xBD, 0xA2, 0x3C, 0xAB, 0xC6, 0xAC, 0xFD,
+ 0x9B, 0xFD, 0x58, 0x35, 0xBD, 0x30, 0x0F, 0x09, 0x73, 0x79, 0x2E, 0xF4,
+ 0x60, 0x40, 0xC5, 0x3F, 0x14, 0x32, 0xBC, 0xDF, 0xB5, 0xE1, 0xDD, 0xE3,
+ 0xBC, 0x18, 0xA5, 0xF8, 0x40, 0xB5, 0x2E, 0x65, 0x34, 0x44, 0xD5, 0xDF,
+ };
+ CheckAesOcbTestVector(rfc_7523_test_key, make_string(nonce), "" /* associated_data */,
+ make_string(plaintext), make_string(expected_ciphertext));
+}
+
+TEST_F(EncryptionOperationsTest, AesOcbRfc7253TestVector14) {
+ uint8_t nonce[] = {
+ 0xBB, 0xAA, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x0D,
+ };
+ uint8_t associated_data[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
+ 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B,
+ 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ };
+ uint8_t plaintext[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
+ 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B,
+ 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ };
+ uint8_t expected_ciphertext[] = {
+ 0xD5, 0xCA, 0x91, 0x74, 0x84, 0x10, 0xC1, 0x75, 0x1F, 0xF8, 0xA2, 0xF6, 0x18, 0x25,
+ 0x5B, 0x68, 0xA0, 0xA1, 0x2E, 0x09, 0x3F, 0xF4, 0x54, 0x60, 0x6E, 0x59, 0xF9, 0xC1,
+ 0xD0, 0xDD, 0xC5, 0x4B, 0x65, 0xE8, 0x62, 0x8E, 0x56, 0x8B, 0xAD, 0x7A, 0xED, 0x07,
+ 0xBA, 0x06, 0xA4, 0xA6, 0x94, 0x83, 0xA7, 0x03, 0x54, 0x90, 0xC5, 0x76, 0x9E, 0x60,
+ };
+ CheckAesOcbTestVector(rfc_7523_test_key, make_string(nonce), make_string(associated_data),
+ make_string(plaintext), make_string(expected_ciphertext));
+}
+
+TEST_F(EncryptionOperationsTest, AesOcbRfc7253TestVector15) {
+ uint8_t nonce[] = {
+ 0xBB, 0xAA, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x0E,
+ };
+ uint8_t associated_data[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
+ 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B,
+ 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ };
+ uint8_t plaintext[] = {};
+ uint8_t expected_ciphertext[] = {
+ 0xC5, 0xCD, 0x9D, 0x18, 0x50, 0xC1, 0x41, 0xE3,
+ 0x58, 0x64, 0x99, 0x94, 0xEE, 0x70, 0x1B, 0x68,
+ };
+ CheckAesOcbTestVector(rfc_7523_test_key, make_string(nonce), make_string(associated_data),
+ "" /* plaintext */, make_string(expected_ciphertext));
+}
+
+TEST_F(EncryptionOperationsTest, AesOcbRfc7253TestVector16) {
+ uint8_t nonce[] = {
+ 0xBB, 0xAA, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x0F,
+ };
+ uint8_t associated_data[] = {};
+ uint8_t plaintext[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
+ 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B,
+ 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ };
+ uint8_t expected_ciphertext[] = {
+ 0x44, 0x12, 0x92, 0x34, 0x93, 0xC5, 0x7D, 0x5D, 0xE0, 0xD7, 0x00, 0xF7, 0x53, 0xCC,
+ 0xE0, 0xD1, 0xD2, 0xD9, 0x50, 0x60, 0x12, 0x2E, 0x9F, 0x15, 0xA5, 0xDD, 0xBF, 0xC5,
+ 0x78, 0x7E, 0x50, 0xB5, 0xCC, 0x55, 0xEE, 0x50, 0x7B, 0xCB, 0x08, 0x4E, 0x47, 0x9A,
+ 0xD3, 0x63, 0xAC, 0x36, 0x6B, 0x95, 0xA9, 0x8C, 0xA5, 0xF3, 0x00, 0x0B, 0x14, 0x79,
+ };
+ CheckAesOcbTestVector(rfc_7523_test_key, make_string(nonce), "" /* associated_data */,
+ make_string(plaintext), make_string(expected_ciphertext));
+}
+
TEST_F(EncryptionOperationsTest, AesEcbRoundTripSuccess) {
ASSERT_EQ(KM_ERROR_OK, GenerateKey(ParamBuilder().AesEncryptionKey(128).Option(TAG_BLOCK_MODE,
KM_MODE_ECB)));
diff --git a/include/keymaster/authorization_set.h b/include/keymaster/authorization_set.h
index b83cc72..0e87fde 100644
--- a/include/keymaster/authorization_set.h
+++ b/include/keymaster/authorization_set.h
@@ -201,6 +201,14 @@
}
/**
+ * Returns true if the specified tag is present, and therefore has the value 'true'.
+ */
+ template <keymaster_tag_t Tag>
+ bool GetTagValue(TypedTag<KM_BOOL, Tag> tag) const {
+ return GetTagValueBool(tag);
+ }
+
+ /**
* If the specified \p tag exists, places its value in \p val and returns true. If \p tag is
* not present, leaves \p val unmodified and returns false.
*/
@@ -305,6 +313,7 @@
bool GetTagValueLong(keymaster_tag_t tag, uint64_t* val) const;
bool GetTagValueDate(keymaster_tag_t tag, uint64_t* val) const;
bool GetTagValueBlob(keymaster_tag_t tag, keymaster_blob_t* val) const;
+ bool GetTagValueBool(keymaster_tag_t tag) const;
keymaster_key_param_t* elems_;
size_t elems_size_;
diff --git a/include/keymaster/keymaster_tags.h b/include/keymaster/keymaster_tags.h
index 761bd95..3d6e637 100644
--- a/include/keymaster/keymaster_tags.h
+++ b/include/keymaster/keymaster_tags.h
@@ -155,7 +155,7 @@
DEFINE_KEYMASTER_TAG(KM_INT, TAG_KEY_SIZE);
DEFINE_KEYMASTER_TAG(KM_INT, TAG_MAC_LENGTH);
DEFINE_KEYMASTER_TAG(KM_INT, TAG_CHUNK_LENGTH);
-DEFINE_KEYMASTER_TAG(KM_BYTES, TAG_NONCE);
+DEFINE_KEYMASTER_TAG(KM_BOOL, TAG_CALLER_NONCE);
DEFINE_KEYMASTER_TAG(KM_LONG, TAG_RSA_PUBLIC_EXPONENT);
DEFINE_KEYMASTER_TAG(KM_BIGNUM, TAG_DSA_GENERATOR);
DEFINE_KEYMASTER_TAG(KM_BIGNUM, TAG_DSA_P);
@@ -177,6 +177,7 @@
DEFINE_KEYMASTER_TAG(KM_BOOL, TAG_ROLLBACK_RESISTANT);
DEFINE_KEYMASTER_TAG(KM_BYTES, TAG_ROOT_OF_TRUST);
DEFINE_KEYMASTER_TAG(KM_BYTES, TAG_ASSOCIATED_DATA);
+DEFINE_KEYMASTER_TAG(KM_BYTES, TAG_NONCE);
#ifdef KEYMASTER_NAME_TAGS
#define DEFINE_KEYMASTER_ENUM_TAG(type, name, enumtype) \
diff --git a/soft_keymaster_device.cpp b/soft_keymaster_device.cpp
index 0724765..9bc4861 100644
--- a/soft_keymaster_device.cpp
+++ b/soft_keymaster_device.cpp
@@ -680,6 +680,13 @@
if (response.error != KM_ERROR_OK)
return response.error;
+ if (response.output_params.size() > 0) {
+ keymaster_key_param_set_t out_params_set;
+ response.output_params.CopyToParamSet(&out_params_set);
+ *out_params = out_params_set.params;
+ *out_params_count = out_params_set.length;
+ }
+
*operation_handle = response.op_handle;
return KM_ERROR_OK;
}