Add AES ECB, CBC, OFB and CFB support.

Change-Id: I7a4e8eaa3be5f20e87ab1f16b0b6bfc1fa47b74c
diff --git a/aes_operation.cpp b/aes_operation.cpp
index e605d2a..a54c8d0 100644
--- a/aes_operation.cpp
+++ b/aes_operation.cpp
@@ -17,38 +17,88 @@
 #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 OCB mode operation factories.  This class does all of the work to create
- * OCB mode operations.
+ * Abstract base for AES operation factories.  This class does all of the work to create
+ * AES operations.
  */
-class AesOcbOperationFactory : public OperationFactory {
+class AesOperationFactory : public OperationFactory {
   public:
     virtual KeyType registry_key() const { return KeyType(KM_ALGORITHM_AES, purpose()); }
 
     virtual Operation* CreateOperation(const Key& key, 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* CreateOcbOperation(const SymmetricKey& key, keymaster_error_t* error);
+    virtual Operation* CreateEvpOperation(const SymmetricKey& key,
+                                          keymaster_block_mode_t block_mode,
+                                          keymaster_padding_t padding, keymaster_error_t* error);
 };
 
-Operation* AesOcbOperationFactory::CreateOperation(const Key& key, keymaster_error_t* error) {
+Operation* AesOperationFactory::CreateOperation(const Key& key, keymaster_error_t* error) {
     *error = KM_ERROR_OK;
 
+    const SymmetricKey* symmetric_key = static_cast<const SymmetricKey*>(&key);
+    if (!symmetric_key) {
+        *error = KM_ERROR_UNKNOWN_ERROR;
+        return NULL;
+    }
+
+    switch (symmetric_key->key_data_size()) {
+    case 16:
+    case 24:
+    case 32:
+        break;
+    default:
+        *error = KM_ERROR_UNSUPPORTED_KEY_SIZE;
+        return NULL;
+    }
+
     keymaster_block_mode_t block_mode;
-    if (!key.authorizations().GetTagValue(TAG_BLOCK_MODE, &block_mode) ||
-        block_mode != KM_MODE_OCB) {
+    if (!key.authorizations().GetTagValue(TAG_BLOCK_MODE, &block_mode) || !supported(block_mode))
+        *error = KM_ERROR_UNSUPPORTED_BLOCK_MODE;
+
+    keymaster_padding_t padding = KM_PAD_NONE;
+    key.authorizations().GetTagValue(TAG_PADDING, &padding);
+
+    if (*error != KM_ERROR_OK)
+        return NULL;
+
+    switch (block_mode) {
+    case KM_MODE_OCB:
+        if (padding != KM_PAD_NONE) {
+            *error = KM_ERROR_UNSUPPORTED_PADDING_MODE;
+            return NULL;
+        }
+        return CreateOcbOperation(*symmetric_key, error);
+    case KM_MODE_ECB:
+    case KM_MODE_CBC:
+    case KM_MODE_OFB:
+    case KM_MODE_CFB:
+        return CreateEvpOperation(*symmetric_key, block_mode, padding, error);
+    default:
         *error = KM_ERROR_UNSUPPORTED_BLOCK_MODE;
         return NULL;
     }
+}
+
+Operation* AesOperationFactory::CreateOcbOperation(const SymmetricKey& key,
+                                                   keymaster_error_t* error) {
+    *error = KM_ERROR_OK;
 
     uint32_t chunk_length;
     if (!key.authorizations().GetTagValue(TAG_CHUNK_LENGTH, &chunk_length) ||
@@ -66,60 +116,72 @@
     if (key.authorizations().GetTagValue(TAG_PADDING, &padding) && padding != KM_PAD_NONE)
         *error = KM_ERROR_UNSUPPORTED_PADDING_MODE;
 
-    const SymmetricKey* symmetric_key = static_cast<const SymmetricKey*>(&key);
-    if (!symmetric_key) {
-        *error = KM_ERROR_UNKNOWN_ERROR;
-        return NULL;
-    }
-
-    switch (symmetric_key->key_data_size()) {
-    case 16:
-    case 24:
-    case 32:
-        break;
-    default:
-        *error = KM_ERROR_UNSUPPORTED_KEY_SIZE;
-    }
-
     if (*error != KM_ERROR_OK)
         return NULL;
 
     keymaster_blob_t additional_data = {0, 0};
-    symmetric_key->authorizations().GetTagValue(TAG_ASSOCIATED_DATA, &additional_data);
+    key.authorizations().GetTagValue(TAG_ASSOCIATED_DATA, &additional_data);
 
-    Operation* op =
-        new AesOcbOperation(purpose(), symmetric_key->key_data(), symmetric_key->key_data_size(),
-                            chunk_length, tag_length, additional_data);
+    Operation* op = new AesOcbOperation(purpose(), key.key_data(), key.key_data_size(),
+                                        chunk_length, tag_length, additional_data);
     if (!op)
         *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
     return op;
 }
 
-static const keymaster_block_mode_t supported_block_modes[] = {KM_MODE_OCB};
+Operation* AesOperationFactory::CreateEvpOperation(const SymmetricKey& key,
+                                                   keymaster_block_mode_t block_mode,
+                                                   keymaster_padding_t padding,
+                                                   keymaster_error_t* error) {
+    Operation* op = NULL;
+    switch (purpose()) {
+    case KM_PURPOSE_ENCRYPT:
+        op = new AesEvpEncryptOperation(block_mode, padding, 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_OCB, KM_MODE_ECB, KM_MODE_CBC, KM_MODE_OFB, KM_MODE_CFB};
 
 const keymaster_block_mode_t*
-AesOcbOperationFactory::SupportedBlockModes(size_t* block_mode_count) const {
+AesOperationFactory::SupportedBlockModes(size_t* block_mode_count) const {
     *block_mode_count = array_length(supported_block_modes);
     return supported_block_modes;
 }
 
-/**
- * Concrete factory for AES OCB mode encryption operations.
- */
-class AesOcbEncryptionOperationFactory : public AesOcbOperationFactory {
-    keymaster_purpose_t purpose() const { return KM_PURPOSE_ENCRYPT; }
-};
-static OperationFactoryRegistry::Registration<AesOcbEncryptionOperationFactory>
-    encrypt_registration;
+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 OCB mode decryption operations.
+ * Concrete factory for AES encryption operations.
  */
-class AesOcbDecryptionOperationFactory : public AesOcbOperationFactory {
+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<AesOcbDecryptionOperationFactory>
-    decrypt_registration;
+static OperationFactoryRegistry::Registration<AesDecryptionOperationFactory> decrypt_registration;
 
 keymaster_error_t AesOcbOperation::Initialize(uint8_t* key, size_t key_size, size_t nonce_length,
                                               size_t tag_length) {
@@ -175,4 +237,198 @@
     return KM_ERROR_OK;
 }
 
+AesEvpOperation::AesEvpOperation(keymaster_purpose_t purpose, keymaster_block_mode_t block_mode,
+                                 keymaster_padding_t padding, const uint8_t* key, size_t key_size)
+    : Operation(purpose), key_size_(key_size), block_mode_(block_mode), padding_(padding),
+      cipher_initialized_(false), iv_buffered_(0) {
+    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_OFB:
+        switch (key_size_) {
+        case 16:
+            cipher = EVP_aes_128_ofb();
+            break;
+        case 24:
+            cipher = EVP_aes_192_ofb();
+            break;
+        case 32:
+            cipher = EVP_aes_256_ofb();
+            break;
+        default:
+            return KM_ERROR_UNSUPPORTED_KEY_SIZE;
+        }
+        break;
+    case KM_MODE_CFB:
+        switch (key_size_) {
+        case 16:
+            cipher = EVP_aes_128_cfb();
+            break;
+        case 24:
+            cipher = EVP_aes_192_cfb();
+            break;
+        case 32:
+            cipher = EVP_aes_256_cfb();
+            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_, evp_encrypt_mode());
+
+    if (!init_result)
+        return KM_ERROR_UNKNOWN_ERROR;
+
+    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;
+    }
+
+    cipher_initialized_ = true;
+    return KM_ERROR_OK;
+}
+
+bool AesEvpOperation::need_iv() const {
+    switch (block_mode_) {
+    case KM_MODE_CBC:
+    case KM_MODE_OFB:
+    case KM_MODE_CFB:
+        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 */) {
+    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();
+
+    if (!cipher_initialized_) {
+        if (need_iv()) {
+            switch (purpose()) {
+            case KM_PURPOSE_DECRYPT: {
+                size_t iv_bytes_to_copy = min(input_end - input_pos, AES_BLOCK_SIZE - iv_buffered_);
+                memcpy(iv_ + iv_buffered_, input_pos, iv_bytes_to_copy);
+                input_pos += iv_bytes_to_copy;
+                iv_buffered_ += iv_bytes_to_copy;
+
+                if (iv_buffered_ < AES_BLOCK_SIZE) {
+                    // Don't yet have enough IV bytes.  Wait for another update.
+                    return KM_ERROR_OK;
+                }
+            } break;
+            case KM_PURPOSE_ENCRYPT:
+                if (!RAND_bytes(iv_, AES_BLOCK_SIZE))
+                    return TranslateLastOpenSslError();
+                output->write(iv_, AES_BLOCK_SIZE);
+                break;
+            default:
+                return KM_ERROR_UNSUPPORTED_BLOCK_MODE;
+            }
+        }
+
+        keymaster_error_t error = InitializeCipher();
+        if (error != KM_ERROR_OK)
+            return error;
+    }
+
+    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