| // Copyright 2017 Google Inc. |
| // |
| // 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 "tink/subtle/encrypt_then_authenticate.h" |
| |
| #include <string> |
| #include <vector> |
| |
| #include "tink/aead.h" |
| #include "tink/mac.h" |
| #include "tink/subtle/ind_cpa_cipher.h" |
| #include "tink/subtle/subtle_util_boringssl.h" |
| #include "tink/util/errors.h" |
| #include "tink/util/status.h" |
| #include "tink/util/statusor.h" |
| |
| |
| namespace crypto { |
| namespace tink { |
| namespace subtle { |
| |
| static const std::string longToBigEndianStr(uint64_t value) { |
| uint8_t bytes[8]; |
| for (int i = sizeof(bytes) - 1; i >= 0; i--) { |
| bytes[i] = value & 0xff; |
| value >>= 8; |
| } |
| return std::string(reinterpret_cast<const char*>(&bytes[0]), sizeof(bytes)); |
| } |
| |
| util::StatusOr<std::unique_ptr<Aead>> EncryptThenAuthenticate::New( |
| std::unique_ptr<IndCpaCipher> ind_cpa_cipher, std::unique_ptr<Mac> mac, |
| uint8_t tag_size) { |
| if (tag_size < MIN_TAG_SIZE_IN_BYTES) { |
| return util::Status(util::error::INTERNAL, "tag size too small"); |
| } |
| std::unique_ptr<Aead> aead(new EncryptThenAuthenticate( |
| std::move(ind_cpa_cipher), std::move(mac), tag_size)); |
| return std::move(aead); |
| } |
| |
| util::StatusOr<std::string> EncryptThenAuthenticate::Encrypt( |
| absl::string_view plaintext, |
| absl::string_view additional_data) const { |
| // BoringSSL expects a non-null pointer for plaintext and additional_data, |
| // regardless of whether the size is 0. |
| plaintext = SubtleUtilBoringSSL::EnsureNonNull(plaintext); |
| additional_data = SubtleUtilBoringSSL::EnsureNonNull(additional_data); |
| |
| auto ct = ind_cpa_cipher_->Encrypt(plaintext); |
| if (!ct.ok()) { |
| return ct.status(); |
| } |
| std::string ciphertext(ct.ValueOrDie()); |
| std::string toAuthData(additional_data); |
| toAuthData.append(ciphertext); |
| uint64_t aad_size_in_bits = additional_data.size() * 8; |
| toAuthData.append(longToBigEndianStr(aad_size_in_bits)); |
| auto tag = mac_->ComputeMac(toAuthData); |
| if (!tag.ok()) { |
| return tag.status(); |
| } |
| if (tag.ValueOrDie().size() != tag_size_) { |
| return util::Status(util::error::INTERNAL, "invalid tag size"); |
| } |
| return ciphertext.append(tag.ValueOrDie()); |
| } |
| |
| util::StatusOr<std::string> EncryptThenAuthenticate::Decrypt( |
| absl::string_view ciphertext, |
| absl::string_view additional_data) const { |
| // BoringSSL expects a non-null pointer for additional_data, |
| // regardless of whether the size is 0. |
| additional_data = SubtleUtilBoringSSL::EnsureNonNull(additional_data); |
| |
| if (ciphertext.size() < tag_size_) { |
| return util::Status(util::error::INTERNAL, "ciphertext too short"); |
| } |
| |
| std::string payload = std::string(ciphertext.data(), ciphertext.size()) |
| .substr(0, ciphertext.size() - tag_size_); |
| std::string toAuthData(additional_data); |
| toAuthData.append(payload); |
| uint64_t aad_size_in_bits = additional_data.size() * 8; |
| toAuthData.append(longToBigEndianStr(aad_size_in_bits)); |
| auto verified = mac_->VerifyMac( |
| ciphertext.substr(ciphertext.size() - tag_size_, tag_size_), toAuthData); |
| if (!verified.ok()) { |
| return verified; |
| } |
| |
| auto pt = ind_cpa_cipher_->Decrypt(payload); |
| if (!pt.ok()) { |
| return pt.status(); |
| } |
| |
| return pt.ValueOrDie(); |
| } |
| |
| } // namespace subtle |
| } // namespace tink |
| } // namespace crypto |