Add RSA encryption and decryption support.

Change-Id: Iceefe0933c80a2169f87fbc01a6fa0fce9644649
diff --git a/google_keymaster_test.cpp b/google_keymaster_test.cpp
index 9924a56..837e2ce 100644
--- a/google_keymaster_test.cpp
+++ b/google_keymaster_test.cpp
@@ -1078,5 +1078,208 @@
     ASSERT_EQ(KM_ERROR_IMPORT_PARAMETER_MISMATCH, import_response.error);
 }
 
+/**
+ * Test class that provides some infrastructure for generating keys and encrypting messages.
+ */
+class EncryptionOperationsTest : public KeymasterTest {
+  protected:
+    void GenerateKey(keymaster_algorithm_t algorithm, keymaster_padding_t padding,
+                     uint32_t key_size) {
+        keymaster_key_param_t params[] = {
+            Authorization(TAG_PURPOSE, KM_PURPOSE_ENCRYPT),
+            Authorization(TAG_PURPOSE, KM_PURPOSE_DECRYPT), Authorization(TAG_ALGORITHM, algorithm),
+            Authorization(TAG_KEY_SIZE, key_size), Authorization(TAG_USER_ID, 7),
+            Authorization(TAG_USER_AUTH_ID, 8), Authorization(TAG_APPLICATION_ID, "app_id", 6),
+            Authorization(TAG_AUTH_TIMEOUT, 300),
+        };
+        GenerateKeyRequest generate_request;
+        generate_request.key_description.Reinitialize(params, array_length(params));
+        if (static_cast<int>(padding) != -1)
+            generate_request.key_description.push_back(TAG_PADDING, padding);
+        device.GenerateKey(generate_request, &generate_response_);
+        EXPECT_EQ(KM_ERROR_OK, generate_response_.error);
+    }
+
+    keymaster_error_t BeginOperation(keymaster_purpose_t purpose,
+                                     const keymaster_key_blob_t& key_blob, uint64_t* op_handle) {
+        BeginOperationRequest begin_request;
+        begin_request.SetKeyMaterial(key_blob);
+        begin_request.purpose = purpose;
+        AddClientParams(&begin_request.additional_params);
+
+        BeginOperationResponse begin_response;
+        device.BeginOperation(begin_request, &begin_response);
+        *op_handle = begin_response.op_handle;
+        return begin_response.error;
+    }
+
+    keymaster_error_t UpdateOperation(uint64_t op_handle, const void* message, size_t size,
+                                      string* output) {
+        UpdateOperationRequest update_request;
+        update_request.op_handle = op_handle;
+        update_request.input.Reinitialize(message, size);
+
+        UpdateOperationResponse update_response;
+        device.UpdateOperation(update_request, &update_response);
+        if (update_response.error == KM_ERROR_OK)
+            output->append(reinterpret_cast<const char*>(update_response.output.peek_read()),
+                           update_response.output.available_read());
+        return update_response.error;
+    }
+
+    keymaster_error_t FinishOperation(uint64_t op_handle, string* output) {
+        FinishOperationRequest finish_request;
+        finish_request.op_handle = op_handle;
+        FinishOperationResponse finish_response;
+        device.FinishOperation(finish_request, &finish_response);
+        if (finish_response.error == KM_ERROR_OK)
+            output->append(reinterpret_cast<const char*>(finish_response.output.peek_read()),
+                           finish_response.output.available_read());
+        return finish_response.error;
+    }
+
+    string ProcessMessage(keymaster_purpose_t purpose, const keymaster_key_blob_t& key_blob,
+                          const void* message, size_t size) {
+        uint64_t op_handle;
+        EXPECT_EQ(KM_ERROR_OK, BeginOperation(purpose, key_blob, &op_handle));
+
+        string result;
+        EXPECT_EQ(KM_ERROR_OK, UpdateOperation(op_handle, message, size, &result));
+        EXPECT_EQ(KM_ERROR_OK, FinishOperation(op_handle, &result));
+        return result;
+    }
+
+    string EncryptMessage(const void* message, size_t size) {
+        return ProcessMessage(KM_PURPOSE_ENCRYPT, generate_response_.key_blob, message, size);
+    }
+
+    string DecryptMessage(const void* ciphertext, size_t size) {
+        return ProcessMessage(KM_PURPOSE_DECRYPT, generate_response_.key_blob, ciphertext, size);
+    }
+
+    void AddClientParams(AuthorizationSet* set) { set->push_back(TAG_APPLICATION_ID, "app_id", 6); }
+
+    const keymaster_key_blob_t& key_blob() { return generate_response_.key_blob; }
+
+    const keymaster_key_blob_t& corrupt_key_blob() {
+        uint8_t* tmp = const_cast<uint8_t*>(generate_response_.key_blob.key_material);
+        ++tmp[generate_response_.key_blob.key_material_size / 2];
+        return generate_response_.key_blob;
+    }
+
+  protected:
+    GenerateKeyResponse generate_response_;
+};
+
+TEST_F(EncryptionOperationsTest, RsaOaepSuccess) {
+    GenerateKey(KM_ALGORITHM_RSA, KM_PAD_RSA_OAEP, 512);
+    const char message[] = "Hello World!";
+    string ciphertext1 = EncryptMessage(message, strlen(message));
+    EXPECT_EQ(512 / 8, ciphertext1.size());
+
+    string ciphertext2 = EncryptMessage(message, strlen(message));
+    EXPECT_EQ(512 / 8, ciphertext2.size());
+
+    // OAEP randomizes padding so every result should be different.
+    EXPECT_NE(ciphertext1, ciphertext2);
+}
+
+TEST_F(EncryptionOperationsTest, RsaOaepRoundTrip) {
+    GenerateKey(KM_ALGORITHM_RSA, KM_PAD_RSA_OAEP, 512);
+    const char message[] = "Hello World!";
+    string ciphertext = EncryptMessage(message, strlen(message));
+    EXPECT_EQ(512 / 8, ciphertext.size());
+
+    string plaintext = DecryptMessage(ciphertext.data(), ciphertext.size());
+    EXPECT_EQ(message, plaintext);
+}
+
+TEST_F(EncryptionOperationsTest, RsaOaepTooLarge) {
+    GenerateKey(KM_ALGORITHM_RSA, KM_PAD_RSA_OAEP, 512);
+    const char message[] = "12345678901234567890123";
+    uint64_t op_handle;
+    string result;
+
+    EXPECT_EQ(KM_ERROR_OK,
+              BeginOperation(KM_PURPOSE_ENCRYPT, generate_response_.key_blob, &op_handle));
+    EXPECT_EQ(KM_ERROR_OK, UpdateOperation(op_handle, message, array_size(message), &result));
+    EXPECT_EQ(KM_ERROR_INVALID_INPUT_LENGTH, FinishOperation(op_handle, &result));
+    EXPECT_EQ(0, result.size());
+}
+
+TEST_F(EncryptionOperationsTest, RsaOaepCorruptedDecrypt) {
+    GenerateKey(KM_ALGORITHM_RSA, KM_PAD_RSA_OAEP, 512);
+    const char message[] = "Hello World!";
+    string ciphertext = EncryptMessage(message, strlen(message));
+    EXPECT_EQ(512 / 8, ciphertext.size());
+
+    // Corrupt the ciphertext
+    ciphertext[512 / 8 / 2]++;
+
+    uint64_t op_handle;
+    string result;
+    EXPECT_EQ(KM_ERROR_OK,
+              BeginOperation(KM_PURPOSE_DECRYPT, generate_response_.key_blob, &op_handle));
+    EXPECT_EQ(KM_ERROR_OK,
+              UpdateOperation(op_handle, ciphertext.data(), ciphertext.size(), &result));
+    EXPECT_EQ(KM_ERROR_UNKNOWN_ERROR, FinishOperation(op_handle, &result));
+    EXPECT_EQ(0, result.size());
+}
+
+TEST_F(EncryptionOperationsTest, RsaPkcs1Success) {
+    GenerateKey(KM_ALGORITHM_RSA, KM_PAD_RSA_PKCS1_1_5_ENCRYPT, 512);
+    const char message[] = "Hello World!";
+    string ciphertext1 = EncryptMessage(message, strlen(message));
+    EXPECT_EQ(512 / 8, ciphertext1.size());
+
+    string ciphertext2 = EncryptMessage(message, strlen(message));
+    EXPECT_EQ(512 / 8, ciphertext2.size());
+
+    // PKCS1 v1.5 randomizes padding so every result should be different.
+    EXPECT_NE(ciphertext1, ciphertext2);
+}
+
+TEST_F(EncryptionOperationsTest, RsaPkcs1RoundTrip) {
+    GenerateKey(KM_ALGORITHM_RSA, KM_PAD_RSA_PKCS1_1_5_ENCRYPT, 512);
+    const char message[] = "Hello World!";
+    string ciphertext = EncryptMessage(message, strlen(message));
+    EXPECT_EQ(512 / 8, ciphertext.size());
+
+    string plaintext = DecryptMessage(ciphertext.data(), ciphertext.size());
+    EXPECT_EQ(message, plaintext);
+}
+
+TEST_F(EncryptionOperationsTest, RsaPkcs1TooLarge) {
+    GenerateKey(KM_ALGORITHM_RSA, KM_PAD_RSA_PKCS1_1_5_ENCRYPT, 512);
+    const char message[] = "1234567890123456789012345678901234567890123456789012";
+    uint64_t op_handle;
+    string result;
+
+    EXPECT_EQ(KM_ERROR_OK,
+              BeginOperation(KM_PURPOSE_ENCRYPT, generate_response_.key_blob, &op_handle));
+    EXPECT_EQ(KM_ERROR_OK, UpdateOperation(op_handle, message, array_size(message), &result));
+    EXPECT_EQ(KM_ERROR_INVALID_INPUT_LENGTH, FinishOperation(op_handle, &result));
+    EXPECT_EQ(0, result.size());
+}
+
+TEST_F(EncryptionOperationsTest, RsaPkcs1CorruptedDecrypt) {
+    GenerateKey(KM_ALGORITHM_RSA, KM_PAD_RSA_PKCS1_1_5_ENCRYPT, 512);
+    const char message[] = "Hello World!";
+    string ciphertext = EncryptMessage(message, strlen(message));
+    EXPECT_EQ(512 / 8, ciphertext.size());
+
+    // Corrupt the ciphertext
+    ciphertext[512 / 8 / 2]++;
+
+    uint64_t op_handle;
+    string result;
+    EXPECT_EQ(KM_ERROR_OK,
+              BeginOperation(KM_PURPOSE_DECRYPT, generate_response_.key_blob, &op_handle));
+    EXPECT_EQ(KM_ERROR_OK,
+              UpdateOperation(op_handle, ciphertext.data(), ciphertext.size(), &result));
+    EXPECT_EQ(KM_ERROR_UNKNOWN_ERROR, FinishOperation(op_handle, &result));
+    EXPECT_EQ(0, result.size());
+}
+
 }  // namespace test
 }  // namespace keymaster