1 // Copyright 2018 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 ///////////////////////////////////////////////////////////////////////////////
16
17 #include "tink/integration/awskms/aws_kms_aead.h"
18
19 #include "aws/core/auth/AWSCredentialsProvider.h"
20 #include "aws/core/client/AWSClient.h"
21 #include "aws/core/utils/Outcome.h"
22 #include "aws/core/utils/memory/AWSMemory.h"
23 #include "aws/kms/KMSClient.h"
24 #include "aws/kms/KMSErrors.h"
25 #include "aws/kms/model/DecryptRequest.h"
26 #include "aws/kms/model/DecryptResult.h"
27 #include "aws/kms/model/EncryptRequest.h"
28 #include "aws/kms/model/EncryptResult.h"
29 #include "absl/status/status.h"
30 #include "absl/strings/escaping.h"
31 #include "absl/strings/match.h"
32 #include "absl/strings/str_cat.h"
33 #include "absl/strings/string_view.h"
34 #include "tink/aead.h"
35 #include "tink/util/status.h"
36 #include "tink/util/statusor.h"
37
38 namespace crypto {
39 namespace tink {
40 namespace integration {
41 namespace awskms {
42 namespace {
43
AwsErrorToString(Aws::Client::AWSError<Aws::KMS::KMSErrors> err)44 std::string AwsErrorToString(Aws::Client::AWSError<Aws::KMS::KMSErrors> err) {
45 return absl::StrCat("AWS error code: ", err.GetErrorType(), ", ",
46 err.GetExceptionName(), ": ", err.GetMessage());
47 }
48
49 } // namespace
50
New(absl::string_view key_arn,std::shared_ptr<Aws::KMS::KMSClient> aws_client)51 util::StatusOr<std::unique_ptr<Aead>> AwsKmsAead::New(
52 absl::string_view key_arn,
53 std::shared_ptr<Aws::KMS::KMSClient> aws_client) {
54 if (key_arn.empty()) {
55 return util::Status(absl::StatusCode::kInvalidArgument,
56 "Key ARN cannot be empty.");
57 }
58 if (aws_client == nullptr) {
59 return util::Status(absl::StatusCode::kInvalidArgument,
60 "AWS KMS client cannot be null.");
61 }
62 return {absl::WrapUnique(new AwsKmsAead(key_arn, aws_client))};
63 }
64
Encrypt(absl::string_view plaintext,absl::string_view associated_data) const65 util::StatusOr<std::string> AwsKmsAead::Encrypt(
66 absl::string_view plaintext, absl::string_view associated_data) const {
67 Aws::KMS::Model::EncryptRequest req;
68 req.SetKeyId(key_arn_.c_str());
69 Aws::Utils::ByteBuffer plaintext_buffer(
70 reinterpret_cast<const unsigned char*>(plaintext.data()),
71 plaintext.length());
72 req.SetPlaintext(plaintext_buffer);
73 if (!associated_data.empty()) {
74 req.AddEncryptionContext("associatedData",
75 absl::BytesToHexString(associated_data).c_str());
76 }
77 auto outcome = aws_client_->Encrypt(req);
78 if (!outcome.IsSuccess()) {
79 auto& err = outcome.GetError();
80 return util::Status(absl::StatusCode::kInvalidArgument,
81 absl::StrCat("AWS KMS encryption failed with error: ",
82 AwsErrorToString(err)));
83 }
84 auto& blob = outcome.GetResult().GetCiphertextBlob();
85 std::string ciphertext(
86 reinterpret_cast<const char*>(blob.GetUnderlyingData()),
87 blob.GetLength());
88 return ciphertext;
89 }
90
Decrypt(absl::string_view ciphertext,absl::string_view associated_data) const91 util::StatusOr<std::string> AwsKmsAead::Decrypt(
92 absl::string_view ciphertext, absl::string_view associated_data) const {
93 Aws::KMS::Model::DecryptRequest req;
94 req.SetKeyId(key_arn_.c_str());
95 Aws::Utils::ByteBuffer ciphertext_buffer(
96 reinterpret_cast<const unsigned char*>(ciphertext.data()),
97 ciphertext.length());
98 req.SetCiphertextBlob(ciphertext_buffer);
99 if (!associated_data.empty()) {
100 req.AddEncryptionContext("associatedData",
101 absl::BytesToHexString(associated_data).c_str());
102 }
103 auto outcome = aws_client_->Decrypt(req);
104 if (!outcome.IsSuccess()) {
105 auto& err = outcome.GetError();
106 return util::Status(absl::StatusCode::kInvalidArgument,
107 absl::StrCat("AWS KMS decryption failed with error: ",
108 AwsErrorToString(err)));
109 }
110 auto& buffer = outcome.GetResult().GetPlaintext();
111 std::string plaintext(
112 reinterpret_cast<const char*>(buffer.GetUnderlyingData()),
113 buffer.GetLength());
114 return plaintext;
115 }
116
117 } // namespace awskms
118 } // namespace integration
119 } // namespace tink
120 } // namespace crypto
121