xref: /aosp_15_r20/external/tink/cc/subtle/ecies_hkdf_recipient_kem_boringssl.cc (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
1 // Copyright 2017 Google Inc.
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/subtle/ecies_hkdf_recipient_kem_boringssl.h"
18 
19 #include <memory>
20 #include <utility>
21 
22 #include "absl/memory/memory.h"
23 #include "absl/status/status.h"
24 #include "openssl/bn.h"
25 #include "openssl/ec.h"
26 #include "openssl/evp.h"
27 #include "tink/internal/ec_util.h"
28 #include "tink/internal/ssl_unique_ptr.h"
29 #include "tink/subtle/common_enums.h"
30 #include "tink/subtle/hkdf.h"
31 #include "tink/util/errors.h"
32 #include "tink/util/secret_data.h"
33 
34 namespace crypto {
35 namespace tink {
36 namespace subtle {
37 
38 // static
39 util::StatusOr<std::unique_ptr<EciesHkdfRecipientKemBoringSsl>>
New(EllipticCurveType curve,util::SecretData priv_key)40 EciesHkdfRecipientKemBoringSsl::New(EllipticCurveType curve,
41                                     util::SecretData priv_key) {
42   switch (curve) {
43     case EllipticCurveType::NIST_P256:
44     case EllipticCurveType::NIST_P384:
45     case EllipticCurveType::NIST_P521:
46       return EciesHkdfNistPCurveRecipientKemBoringSsl::New(curve,
47                                                            std::move(priv_key));
48     case EllipticCurveType::CURVE25519:
49       return EciesHkdfX25519RecipientKemBoringSsl::New(curve,
50                                                        std::move(priv_key));
51     default:
52       return util::Status(absl::StatusCode::kUnimplemented,
53                           "Unsupported elliptic curve");
54   }
55 }
56 
57 // static
58 util::StatusOr<std::unique_ptr<EciesHkdfRecipientKemBoringSsl>>
New(EllipticCurveType curve,util::SecretData priv_key)59 EciesHkdfNistPCurveRecipientKemBoringSsl::New(EllipticCurveType curve,
60                                               util::SecretData priv_key) {
61   auto status = internal::CheckFipsCompatibility<
62       EciesHkdfNistPCurveRecipientKemBoringSsl>();
63   if (!status.ok()) return status;
64 
65   if (priv_key.empty()) {
66     return util::Status(absl::StatusCode::kInvalidArgument, "empty priv_key");
67   }
68   auto status_or_ec_group = internal::EcGroupFromCurveType(curve);
69   if (!status_or_ec_group.ok()) return status_or_ec_group.status();
70   // TODO(przydatek): consider refactoring internal/ec_util,
71   //     so that the saved group can be used for KEM operations.
72   return {absl::WrapUnique(new EciesHkdfNistPCurveRecipientKemBoringSsl(
73       curve, std::move(priv_key), std::move(status_or_ec_group.value())))};
74 }
75 
76 EciesHkdfNistPCurveRecipientKemBoringSsl::
EciesHkdfNistPCurveRecipientKemBoringSsl(EllipticCurveType curve,util::SecretData priv_key_value,internal::SslUniquePtr<EC_GROUP> ec_group)77     EciesHkdfNistPCurveRecipientKemBoringSsl(
78         EllipticCurveType curve, util::SecretData priv_key_value,
79         internal::SslUniquePtr<EC_GROUP> ec_group)
80     : curve_(curve),
81       priv_key_value_(std::move(priv_key_value)),
82       ec_group_(std::move(ec_group)) {}
83 
84 util::StatusOr<util::SecretData>
GenerateKey(absl::string_view kem_bytes,HashType hash,absl::string_view hkdf_salt,absl::string_view hkdf_info,uint32_t key_size_in_bytes,EcPointFormat point_format) const85 EciesHkdfNistPCurveRecipientKemBoringSsl::GenerateKey(
86     absl::string_view kem_bytes, HashType hash, absl::string_view hkdf_salt,
87     absl::string_view hkdf_info, uint32_t key_size_in_bytes,
88     EcPointFormat point_format) const {
89   auto status_or_ec_point =
90       internal::EcPointDecode(curve_, point_format, kem_bytes);
91   if (!status_or_ec_point.ok()) {
92     return ToStatusF(absl::StatusCode::kInvalidArgument,
93                      "Invalid KEM bytes: %s",
94                      status_or_ec_point.status().message());
95   }
96   internal::SslUniquePtr<EC_POINT> pub_key =
97       std::move(status_or_ec_point.value());
98   internal::SslUniquePtr<BIGNUM> priv_key(
99       BN_bin2bn(priv_key_value_.data(), priv_key_value_.size(), nullptr));
100   auto shared_secret_or =
101       internal::ComputeEcdhSharedSecret(curve_, priv_key.get(), pub_key.get());
102   if (!shared_secret_or.ok()) {
103     return shared_secret_or.status();
104   }
105   util::SecretData shared_secret = shared_secret_or.value();
106   return Hkdf::ComputeEciesHkdfSymmetricKey(
107       hash, kem_bytes, shared_secret, hkdf_salt, hkdf_info, key_size_in_bytes);
108 }
109 
EciesHkdfX25519RecipientKemBoringSsl(internal::SslUniquePtr<EVP_PKEY> private_key)110 EciesHkdfX25519RecipientKemBoringSsl::EciesHkdfX25519RecipientKemBoringSsl(
111     internal::SslUniquePtr<EVP_PKEY> private_key)
112     : private_key_(std::move(private_key)) {}
113 
114 // static
115 util::StatusOr<std::unique_ptr<EciesHkdfRecipientKemBoringSsl>>
New(EllipticCurveType curve,util::SecretData priv_key)116 EciesHkdfX25519RecipientKemBoringSsl::New(EllipticCurveType curve,
117                                           util::SecretData priv_key) {
118   auto status =
119       internal::CheckFipsCompatibility<EciesHkdfX25519RecipientKemBoringSsl>();
120   if (!status.ok()) return status;
121 
122   if (curve != CURVE25519) {
123     return util::Status(absl::StatusCode::kInvalidArgument,
124                         "curve is not CURVE25519");
125   }
126   if (priv_key.size() != internal::X25519KeyPubKeySize()) {
127     return util::Status(absl::StatusCode::kInvalidArgument,
128                         "pubx has unexpected length");
129   }
130 
131   internal::SslUniquePtr<EVP_PKEY> ssl_priv_key(EVP_PKEY_new_raw_private_key(
132       /*type=*/EVP_PKEY_X25519, /*unused=*/nullptr, /*in=*/priv_key.data(),
133       /*len=*/internal::Ed25519KeyPrivKeySize()));
134   if (ssl_priv_key == nullptr) {
135     return util::Status(absl::StatusCode::kInternal,
136                         "EVP_PKEY_new_raw_private_key failed");
137   }
138 
139   return {absl::WrapUnique(
140       new EciesHkdfX25519RecipientKemBoringSsl(std::move(ssl_priv_key)))};
141 }
142 
143 crypto::tink::util::StatusOr<util::SecretData>
GenerateKey(absl::string_view kem_bytes,HashType hash,absl::string_view hkdf_salt,absl::string_view hkdf_info,uint32_t key_size_in_bytes,EcPointFormat point_format) const144 EciesHkdfX25519RecipientKemBoringSsl::GenerateKey(
145     absl::string_view kem_bytes, HashType hash, absl::string_view hkdf_salt,
146     absl::string_view hkdf_info, uint32_t key_size_in_bytes,
147     EcPointFormat point_format) const {
148   if (point_format != EcPointFormat::COMPRESSED) {
149     return util::Status(
150         absl::StatusCode::kInvalidArgument,
151         "X25519 only supports compressed elliptic curve points");
152   }
153 
154   if (kem_bytes.size() != internal::X25519KeyPubKeySize()) {
155     return util::Status(absl::StatusCode::kInvalidArgument,
156                         "kem_bytes has unexpected size");
157   }
158 
159   internal::SslUniquePtr<EVP_PKEY> peer_key(EVP_PKEY_new_raw_public_key(
160       /*type=*/EVP_PKEY_X25519, /*unused=*/nullptr,
161       /*in=*/reinterpret_cast<const uint8_t*>(kem_bytes.data()),
162       /*len=*/internal::Ed25519KeyPubKeySize()));
163   if (peer_key == nullptr) {
164     return util::Status(absl::StatusCode::kInternal,
165                         "EVP_PKEY_new_raw_public_key failed");
166   }
167 
168   util::StatusOr<util::SecretData> shared_secret =
169       internal::ComputeX25519SharedSecret(private_key_.get(), peer_key.get());
170   if (!shared_secret.ok()) {
171     return shared_secret.status();
172   }
173 
174   return Hkdf::ComputeEciesHkdfSymmetricKey(
175       hash, kem_bytes, *shared_secret, hkdf_salt, hkdf_info, key_size_in_bytes);
176 }
177 
178 }  // namespace subtle
179 }  // namespace tink
180 }  // namespace crypto
181