xref: /aosp_15_r20/external/tink/cc/integration/awskms/aws_kms_aead.cc (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
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