blob: 22fbd0e9d8bcfd04b7a01044d7c23e305e2b1da7 [file] [log] [blame]
/*
* 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 <stdio.h>
#include <openssl/aes.h>
#include <openssl/err.h>
#include <openssl/rand.h>
#include <keymaster/logger.h>
#include "aes_key.h"
#include "aes_operation.h"
#include "openssl_err.h"
namespace keymaster {
/**
* Abstract base for AES operation factories. This class does all of the work to create
* AES operations.
*/
class AesOperationFactory : public OperationFactory {
public:
virtual KeyType registry_key() const { return KeyType(KM_ALGORITHM_AES, purpose()); }
virtual Operation* CreateOperation(const Key& key, const AuthorizationSet& begin_params,
keymaster_error_t* error);
virtual const keymaster_block_mode_t* SupportedBlockModes(size_t* block_mode_count) const;
virtual const keymaster_padding_t* SupportedPaddingModes(size_t* padding_count) const;
virtual keymaster_purpose_t purpose() const = 0;
private:
virtual Operation* CreateEvpOperation(const SymmetricKey& key,
keymaster_block_mode_t block_mode,
keymaster_padding_t padding, bool caller_iv,
keymaster_error_t* error);
};
Operation* AesOperationFactory::CreateOperation(const Key& key,
const AuthorizationSet& begin_params,
keymaster_error_t* error) {
*error = KM_ERROR_OK;
const SymmetricKey* symmetric_key = static_cast<const SymmetricKey*>(&key);
switch (symmetric_key->key_data_size()) {
case 16:
case 24:
case 32:
break;
default:
*error = KM_ERROR_UNSUPPORTED_KEY_SIZE;
return nullptr;
}
keymaster_block_mode_t block_mode;
if (!begin_params.GetTagValue(TAG_BLOCK_MODE, &block_mode)) {
LOG_E("%d block modes specified in begin params", begin_params.GetTagCount(TAG_BLOCK_MODE));
*error = KM_ERROR_UNSUPPORTED_BLOCK_MODE;
return nullptr;
} else if (!supported(block_mode)) {
LOG_E("Block mode %d not supported", block_mode);
*error = KM_ERROR_UNSUPPORTED_BLOCK_MODE;
return nullptr;
} else if (!key.authorizations().Contains(TAG_BLOCK_MODE, block_mode)) {
LOG_E("Block mode %d was specified, but not authorized by key", block_mode);
*error = KM_ERROR_INCOMPATIBLE_BLOCK_MODE;
return nullptr;
}
keymaster_padding_t padding;
if (!begin_params.GetTagValue(TAG_PADDING, &padding)) {
LOG_E("%d padding modes specified in begin params",
begin_params.GetTagCount(TAG_PADDING));
*error = KM_ERROR_UNSUPPORTED_PADDING_MODE;
return nullptr;
} else if (!supported(padding)) {
LOG_E("Padding mode %d not supported", padding);
*error = KM_ERROR_UNSUPPORTED_PADDING_MODE;
return nullptr;
} else if (!key.authorizations().Contains(TAG_PADDING, padding)) {
LOG_E("Padding mode %d was specified, but not authorized by key", padding);
*error = KM_ERROR_INCOMPATIBLE_PADDING_MODE;
return nullptr;
}
bool caller_nonce = key.authorizations().GetTagValue(TAG_CALLER_NONCE);
if (*error != KM_ERROR_OK)
return nullptr;
switch (block_mode) {
case KM_MODE_ECB:
case KM_MODE_CBC:
return CreateEvpOperation(*symmetric_key, block_mode, padding, caller_nonce, error);
case KM_MODE_CTR:
if (padding != KM_PAD_NONE) {
*error = KM_ERROR_INCOMPATIBLE_PADDING_MODE;
return nullptr;
}
return CreateEvpOperation(*symmetric_key, block_mode, padding, caller_nonce, error);
default:
*error = KM_ERROR_UNSUPPORTED_BLOCK_MODE;
return nullptr;
}
}
Operation* AesOperationFactory::CreateEvpOperation(const SymmetricKey& key,
keymaster_block_mode_t block_mode,
keymaster_padding_t padding, bool caller_iv,
keymaster_error_t* error) {
Operation* op = NULL;
switch (purpose()) {
case KM_PURPOSE_ENCRYPT:
op = new AesEvpEncryptOperation(block_mode, padding, caller_iv, key.key_data(),
key.key_data_size());
break;
case KM_PURPOSE_DECRYPT:
op = new AesEvpDecryptOperation(block_mode, padding, key.key_data(), key.key_data_size());
break;
default:
*error = KM_ERROR_UNSUPPORTED_PURPOSE;
return NULL;
}
if (!op)
*error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
return op;
}
static const keymaster_block_mode_t supported_block_modes[] = {KM_MODE_ECB, KM_MODE_CBC,
KM_MODE_CTR};
const keymaster_block_mode_t*
AesOperationFactory::SupportedBlockModes(size_t* block_mode_count) const {
*block_mode_count = array_length(supported_block_modes);
return supported_block_modes;
}
static const keymaster_padding_t supported_padding_modes[] = {KM_PAD_NONE, KM_PAD_PKCS7};
const keymaster_padding_t*
AesOperationFactory::SupportedPaddingModes(size_t* padding_mode_count) const {
*padding_mode_count = array_length(supported_padding_modes);
return supported_padding_modes;
}
/**
* Concrete factory for AES encryption operations.
*/
class AesEncryptionOperationFactory : public AesOperationFactory {
keymaster_purpose_t purpose() const { return KM_PURPOSE_ENCRYPT; }
};
static OperationFactoryRegistry::Registration<AesEncryptionOperationFactory> encrypt_registration;
/**
* Concrete factory for AES decryption operations.
*/
class AesDecryptionOperationFactory : public AesOperationFactory {
keymaster_purpose_t purpose() const { return KM_PURPOSE_DECRYPT; }
};
static OperationFactoryRegistry::Registration<AesDecryptionOperationFactory> decrypt_registration;
AesEvpOperation::AesEvpOperation(keymaster_purpose_t purpose, keymaster_block_mode_t block_mode,
keymaster_padding_t padding, bool caller_iv, const uint8_t* key,
size_t key_size)
: Operation(purpose), key_size_(key_size), block_mode_(block_mode), padding_(padding),
caller_iv_(caller_iv) {
memcpy(key_, key, key_size_);
EVP_CIPHER_CTX_init(&ctx_);
}
AesEvpOperation::~AesEvpOperation() {
EVP_CIPHER_CTX_cleanup(&ctx_);
}
keymaster_error_t AesEvpOperation::InitializeCipher() {
const EVP_CIPHER* cipher;
switch (block_mode_) {
case KM_MODE_ECB:
switch (key_size_) {
case 16:
cipher = EVP_aes_128_ecb();
break;
case 24:
cipher = EVP_aes_192_ecb();
break;
case 32:
cipher = EVP_aes_256_ecb();
break;
default:
return KM_ERROR_UNSUPPORTED_KEY_SIZE;
}
break;
case KM_MODE_CBC:
switch (key_size_) {
case 16:
cipher = EVP_aes_128_cbc();
break;
case 24:
cipher = EVP_aes_192_cbc();
break;
case 32:
cipher = EVP_aes_256_cbc();
break;
default:
return KM_ERROR_UNSUPPORTED_KEY_SIZE;
}
break;
case KM_MODE_CTR:
switch (key_size_) {
case 16:
cipher = EVP_aes_128_ctr();
break;
case 24:
cipher = EVP_aes_192_ctr();
break;
case 32:
cipher = EVP_aes_256_ctr();
break;
default:
return KM_ERROR_UNSUPPORTED_KEY_SIZE;
}
break;
default:
return KM_ERROR_UNSUPPORTED_BLOCK_MODE;
}
int init_result =
EVP_CipherInit_ex(&ctx_, cipher, NULL /* engine */, key_, iv_.get(), evp_encrypt_mode());
if (!init_result)
return TranslateLastOpenSslError();
switch (padding_) {
case KM_PAD_NONE:
EVP_CIPHER_CTX_set_padding(&ctx_, 0 /* disable padding */);
break;
case KM_PAD_PKCS7:
// This is the default for OpenSSL EVP cipher operations.
break;
default:
return KM_ERROR_UNSUPPORTED_PADDING_MODE;
}
return KM_ERROR_OK;
}
bool AesEvpOperation::need_iv() const {
switch (block_mode_) {
case KM_MODE_CBC:
case KM_MODE_CTR:
return true;
case KM_MODE_ECB:
return false;
default:
// Shouldn't get here.
assert(false);
return false;
}
}
keymaster_error_t AesEvpOperation::Begin(const AuthorizationSet& input_params,
AuthorizationSet* output_params) {
if (!output_params)
return KM_ERROR_OUTPUT_PARAMETER_NULL;
keymaster_error_t error = KM_ERROR_OK;
if (need_iv()) {
switch (purpose()) {
case KM_PURPOSE_ENCRYPT:
if (input_params.find(TAG_NONCE) == -1)
error = GenerateIv();
else if (caller_iv_)
error = GetIv(input_params);
else
error = KM_ERROR_CALLER_NONCE_PROHIBITED;
if (error == KM_ERROR_OK)
output_params->push_back(TAG_NONCE, iv_.get(), AES_BLOCK_SIZE);
break;
case KM_PURPOSE_DECRYPT:
error = GetIv(input_params);
break;
default:
return KM_ERROR_UNSUPPORTED_PURPOSE;
}
}
if (error == KM_ERROR_OK)
error = InitializeCipher();
return error;
}
keymaster_error_t AesEvpOperation::GetIv(const AuthorizationSet& input_params) {
keymaster_blob_t iv_blob;
if (!input_params.GetTagValue(TAG_NONCE, &iv_blob)) {
LOG_E("No IV provided", 0);
return KM_ERROR_INVALID_ARGUMENT;
}
if (iv_blob.data_length != AES_BLOCK_SIZE) {
LOG_E("Expected %d-byte IV for AES operation, but got %d bytes", AES_BLOCK_SIZE,
iv_blob.data_length);
return KM_ERROR_INVALID_NONCE;
}
iv_.reset(dup_array(iv_blob.data, iv_blob.data_length));
if (!iv_.get())
return KM_ERROR_MEMORY_ALLOCATION_FAILED;
return KM_ERROR_OK;
}
keymaster_error_t AesEvpOperation::GenerateIv() {
iv_.reset(new uint8_t[AES_BLOCK_SIZE]);
if (!iv_.get())
return KM_ERROR_MEMORY_ALLOCATION_FAILED;
if (RAND_bytes(iv_.get(), AES_BLOCK_SIZE) != 1)
return TranslateLastOpenSslError();
return KM_ERROR_OK;
}
inline size_t min(size_t a, size_t b) {
if (a < b)
return a;
return b;
}
keymaster_error_t AesEvpOperation::Update(const AuthorizationSet& /* additional_params */,
const Buffer& input, Buffer* output,
size_t* input_consumed) {
output->reserve(input.available_read() + AES_BLOCK_SIZE);
const uint8_t* input_pos = input.peek_read();
const uint8_t* input_end = input_pos + input.available_read();
int output_written = -1;
if (!EVP_CipherUpdate(&ctx_, output->peek_write(), &output_written, input_pos,
input_end - input_pos))
return TranslateLastOpenSslError();
assert(output_written >= 0);
assert(output_written <= (int)output->available_write());
output->advance_write(output_written);
*input_consumed = input.available_read();
return KM_ERROR_OK;
}
keymaster_error_t AesEvpOperation::Finish(const AuthorizationSet& /* additional_params */,
const Buffer& /* signature */, Buffer* output) {
output->reserve(AES_BLOCK_SIZE);
int output_written = -1;
if (!EVP_CipherFinal_ex(&ctx_, output->peek_write(), &output_written)) {
LOG_E("Error encrypting final block: %s", ERR_error_string(ERR_peek_last_error(), NULL));
return TranslateLastOpenSslError();
}
assert(output_written <= AES_BLOCK_SIZE);
output->advance_write(output_written);
return KM_ERROR_OK;
}
keymaster_error_t AesEvpOperation::Abort() {
return KM_ERROR_OK;
}
} // namespace keymaster