xref: /aosp_15_r20/external/tink/cc/prf/hkdf_prf_key_manager.h (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
1 // Copyright 2019 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 #ifndef TINK_PRF_HKDF_PRF_KEY_MANAGER_H_
18 #define TINK_PRF_HKDF_PRF_KEY_MANAGER_H_
19 
20 #include <memory>
21 #include <string>
22 #include <utility>
23 
24 #include "absl/memory/memory.h"
25 #include "absl/status/status.h"
26 #include "absl/strings/str_cat.h"
27 #include "tink/core/key_type_manager.h"
28 #include "tink/input_stream.h"
29 #include "tink/prf/prf_set.h"
30 #include "tink/subtle/prf/hkdf_streaming_prf.h"
31 #include "tink/subtle/prf/prf_set_util.h"
32 #include "tink/subtle/prf/streaming_prf.h"
33 #include "tink/subtle/random.h"
34 #include "tink/util/constants.h"
35 #include "tink/util/enums.h"
36 #include "tink/util/input_stream_util.h"
37 #include "tink/util/secret_data.h"
38 #include "tink/util/status.h"
39 #include "tink/util/statusor.h"
40 #include "tink/util/validation.h"
41 #include "proto/common.pb.h"
42 #include "proto/hkdf_prf.pb.h"
43 #include "proto/tink.pb.h"
44 
45 namespace crypto {
46 namespace tink {
47 
48 class HkdfPrfKeyManager
49     : public KeyTypeManager<google::crypto::tink::HkdfPrfKey,
50                             google::crypto::tink::HkdfPrfKeyFormat,
51                             List<StreamingPrf, Prf>> {
52  public:
53   class StreamingPrfFactory : public PrimitiveFactory<StreamingPrf> {
Create(const google::crypto::tink::HkdfPrfKey & key)54     crypto::tink::util::StatusOr<std::unique_ptr<StreamingPrf>> Create(
55         const google::crypto::tink::HkdfPrfKey& key) const override {
56       return subtle::HkdfStreamingPrf::New(
57           crypto::tink::util::Enums::ProtoToSubtle(key.params().hash()),
58           util::SecretDataFromStringView(key.key_value()), key.params().salt());
59     }
60   };
61 
62   class PrfSetFactory : public PrimitiveFactory<Prf> {
Create(const google::crypto::tink::HkdfPrfKey & key)63     crypto::tink::util::StatusOr<std::unique_ptr<Prf>> Create(
64         const google::crypto::tink::HkdfPrfKey& key) const override {
65       auto hkdf_result = subtle::HkdfStreamingPrf::New(
66           crypto::tink::util::Enums::ProtoToSubtle(key.params().hash()),
67           util::SecretDataFromStringView(key.key_value()), key.params().salt());
68       if (!hkdf_result.ok()) {
69         return hkdf_result.status();
70       }
71       return subtle::CreatePrfFromStreamingPrf(std::move(hkdf_result.value()));
72     }
73   };
74 
HkdfPrfKeyManager()75   HkdfPrfKeyManager()
76       : KeyTypeManager(absl::make_unique<StreamingPrfFactory>(),
77                        absl::make_unique<PrfSetFactory>()) {}
78 
get_version()79   uint32_t get_version() const override { return 0; }
80 
key_material_type()81   google::crypto::tink::KeyData::KeyMaterialType key_material_type()
82       const override {
83     return google::crypto::tink::KeyData::SYMMETRIC;
84   }
85 
get_key_type()86   const std::string& get_key_type() const override { return key_type_; }
87 
ValidateKey(const google::crypto::tink::HkdfPrfKey & key)88   crypto::tink::util::Status ValidateKey(
89       const google::crypto::tink::HkdfPrfKey& key) const override {
90     crypto::tink::util::Status status =
91         ValidateVersion(key.version(), get_version());
92     if (!status.ok()) return status;
93     status = ValidateKeySize(key.key_value().size());
94     if (!status.ok()) return status;
95     return ValidateParams(key.params());
96   }
97 
ValidateKeyFormat(const google::crypto::tink::HkdfPrfKeyFormat & key_format)98   crypto::tink::util::Status ValidateKeyFormat(
99       const google::crypto::tink::HkdfPrfKeyFormat& key_format) const override {
100     crypto::tink::util::Status status =
101         ValidateVersion(key_format.version(), get_version());
102     if (!status.ok()) return status;
103     status = ValidateKeySize(key_format.key_size());
104     if (!status.ok()) return status;
105     return ValidateParams(key_format.params());
106   }
107 
CreateKey(const google::crypto::tink::HkdfPrfKeyFormat & key_format)108   crypto::tink::util::StatusOr<google::crypto::tink::HkdfPrfKey> CreateKey(
109       const google::crypto::tink::HkdfPrfKeyFormat& key_format) const override {
110     google::crypto::tink::HkdfPrfKey key;
111     key.set_version(get_version());
112     *key.mutable_params() = key_format.params();
113     key.set_key_value(
114         crypto::tink::subtle::Random::GetRandomBytes(key_format.key_size()));
115     return key;
116   }
117 
DeriveKey(const google::crypto::tink::HkdfPrfKeyFormat & key_format,InputStream * input_stream)118   crypto::tink::util::StatusOr<google::crypto::tink::HkdfPrfKey> DeriveKey(
119       const google::crypto::tink::HkdfPrfKeyFormat& key_format,
120       InputStream* input_stream) const override {
121     auto status = ValidateKeyFormat(key_format);
122     if (!status.ok()) {
123       return status;
124     }
125     crypto::tink::util::StatusOr<std::string> randomness =
126         ReadBytesFromStream(key_format.key_size(), input_stream);
127     if (!randomness.ok()) {
128       return randomness.status();
129     }
130     google::crypto::tink::HkdfPrfKey key;
131     key.set_version(get_version());
132     *key.mutable_params() = key_format.params();
133     key.set_key_value(randomness.value());
134     return key;
135   }
136 
137  private:
ValidateKeySize(int key_size)138   crypto::tink::util::Status ValidateKeySize(int key_size) const {
139     if (key_size < kMinKeySizeBytes) {
140       return crypto::tink::util::Status(
141           absl::StatusCode::kInvalidArgument,
142           "Invalid HkdfPrfKey: key_value is too short.");
143     }
144     return crypto::tink::util::OkStatus();
145   }
146 
ValidateParams(const google::crypto::tink::HkdfPrfParams & params)147   crypto::tink::util::Status ValidateParams(
148       const google::crypto::tink::HkdfPrfParams& params) const {
149     // Omitting SHA1 for the moment; there seems to be no reason to allow it.
150     if (params.hash() != google::crypto::tink::HashType::SHA256 &&
151         params.hash() != google::crypto::tink::HashType::SHA512) {
152       return crypto::tink::util::Status(
153           absl::StatusCode::kInvalidArgument,
154           "Invalid HkdfPrfKey: unsupported hash.");
155     }
156     return crypto::tink::util::OkStatus();
157   }
158 
159   // We use a somewhat larger minimum key size than usual, because PRFs might be
160   // used by many users, in which case the security can degrade by a factor
161   // depending on the number of users. (Discussed for example in
162   // https://eprint.iacr.org/2012/159)
163   const int kMinKeySizeBytes = 32;
164   const std::string key_type_ = absl::StrCat(
165       kTypeGoogleapisCom, google::crypto::tink::HkdfPrfKey().GetTypeName());
166 };
167 
168 }  // namespace tink
169 }  // namespace crypto
170 
171 #endif  // TINK_PRF_HKDF_PRF_KEY_MANAGER_H_
172