1 // Copyright 2023 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 // https://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 #include "anonymous_tokens/cpp/crypto/rsa_blinder.h"
16
17 #include <memory>
18 #include <string>
19 #include <utility>
20 #include <vector>
21
22 #include "absl/status/status.h"
23 #include "absl/status/statusor.h"
24 #include "absl/strings/str_cat.h"
25 #include "absl/strings/string_view.h"
26 #include "anonymous_tokens/cpp/crypto/constants.h"
27 #include "anonymous_tokens/cpp/crypto/crypto_utils.h"
28 #include "anonymous_tokens/cpp/shared/status_utils.h"
29 #include <openssl/digest.h>
30 #include <openssl/rsa.h>
31
32
33 namespace anonymous_tokens {
34
New(absl::string_view rsa_modulus,absl::string_view rsa_public_exponent,const EVP_MD * signature_hash_function,const EVP_MD * mgf1_hash_function,int salt_length,const bool use_rsa_public_exponent,std::optional<absl::string_view> public_metadata)35 absl::StatusOr<std::unique_ptr<RsaBlinder>> RsaBlinder::New(
36 absl::string_view rsa_modulus, absl::string_view rsa_public_exponent,
37 const EVP_MD* signature_hash_function, const EVP_MD* mgf1_hash_function,
38 int salt_length, const bool use_rsa_public_exponent,
39 std::optional<absl::string_view> public_metadata) {
40 bssl::UniquePtr<RSA> rsa_public_key;
41
42 if (!public_metadata.has_value()) {
43 ANON_TOKENS_ASSIGN_OR_RETURN(
44 rsa_public_key, CreatePublicKeyRSA(rsa_modulus, rsa_public_exponent));
45 } else {
46 // If public metadata is passed, RsaBlinder will compute a new public
47 // exponent using the public metadata.
48 //
49 // Empty string is a valid public metadata value.
50 ANON_TOKENS_ASSIGN_OR_RETURN(
51 rsa_public_key, CreatePublicKeyRSAWithPublicMetadata(
52 rsa_modulus, rsa_public_exponent, *public_metadata,
53 use_rsa_public_exponent));
54 }
55
56 ANON_TOKENS_ASSIGN_OR_RETURN(bssl::UniquePtr<BIGNUM> r, NewBigNum());
57 ANON_TOKENS_ASSIGN_OR_RETURN(bssl::UniquePtr<BIGNUM> r_inv_mont, NewBigNum());
58
59 // Limit r between [2, n) so that an r of 1 never happens. An r of 1 doesn't
60 // blind.
61 if (BN_rand_range_ex(r.get(), 2, RSA_get0_n(rsa_public_key.get())) !=
62 kBsslSuccess) {
63 return absl::InternalError(
64 "BN_rand_range_ex failed when called from RsaBlinder::New.");
65 }
66
67 bssl::UniquePtr<BN_CTX> bn_ctx(BN_CTX_new());
68 if (!bn_ctx) {
69 return absl::InternalError("BN_CTX_new failed.");
70 }
71
72 bssl::UniquePtr<BN_MONT_CTX> bn_mont_ctx(BN_MONT_CTX_new_for_modulus(
73 RSA_get0_n(rsa_public_key.get()), bn_ctx.get()));
74 if (!bn_mont_ctx) {
75 return absl::InternalError("BN_MONT_CTX_new_for_modulus failed.");
76 }
77
78 // We wish to compute r^-1 in the Montgomery domain, or r^-1 R mod n. This is
79 // can be done with BN_mod_inverse_blinded followed by BN_to_montgomery, but
80 // it is equivalent and slightly more efficient to first compute r R^-1 mod n
81 // with BN_from_montgomery, and then inverting that to give r^-1 R mod n.
82 int is_r_not_invertible = 0;
83 if (BN_from_montgomery(r_inv_mont.get(), r.get(), bn_mont_ctx.get(),
84 bn_ctx.get()) != kBsslSuccess ||
85 BN_mod_inverse_blinded(r_inv_mont.get(), &is_r_not_invertible,
86 r_inv_mont.get(), bn_mont_ctx.get(),
87 bn_ctx.get()) != kBsslSuccess) {
88 return absl::InternalError(
89 absl::StrCat("BN_mod_inverse failed when called from RsaBlinder::New, "
90 "is_r_not_invertible = ",
91 is_r_not_invertible));
92 }
93
94 return absl::WrapUnique(new RsaBlinder(
95 salt_length, public_metadata, signature_hash_function, mgf1_hash_function,
96 std::move(rsa_public_key), std::move(r), std::move(r_inv_mont),
97 std::move(bn_mont_ctx)));
98 }
99
RsaBlinder(int salt_length,std::optional<absl::string_view> public_metadata,const EVP_MD * sig_hash,const EVP_MD * mgf1_hash,bssl::UniquePtr<RSA> rsa_public_key,bssl::UniquePtr<BIGNUM> r,bssl::UniquePtr<BIGNUM> r_inv_mont,bssl::UniquePtr<BN_MONT_CTX> mont_n)100 RsaBlinder::RsaBlinder(int salt_length,
101 std::optional<absl::string_view> public_metadata,
102 const EVP_MD* sig_hash, const EVP_MD* mgf1_hash,
103 bssl::UniquePtr<RSA> rsa_public_key,
104 bssl::UniquePtr<BIGNUM> r,
105 bssl::UniquePtr<BIGNUM> r_inv_mont,
106 bssl::UniquePtr<BN_MONT_CTX> mont_n)
107 : salt_length_(salt_length),
108 public_metadata_(public_metadata),
109 sig_hash_(sig_hash),
110 mgf1_hash_(mgf1_hash),
111 rsa_public_key_(std::move(rsa_public_key)),
112 r_(std::move(r)),
113 r_inv_mont_(std::move(r_inv_mont)),
114 mont_n_(std::move(mont_n)),
115 blinder_state_(RsaBlinder::BlinderState::kCreated) {}
116
Blind(const absl::string_view message)117 absl::StatusOr<std::string> RsaBlinder::Blind(const absl::string_view message) {
118 // Check that the blinder state was kCreated
119 if (blinder_state_ != RsaBlinder::BlinderState::kCreated) {
120 return absl::FailedPreconditionError(
121 "RsaBlinder is in wrong state to blind message.");
122 }
123 std::string augmented_message(message);
124 if (public_metadata_.has_value()) {
125 augmented_message = EncodeMessagePublicMetadata(message, *public_metadata_);
126 }
127 ANON_TOKENS_ASSIGN_OR_RETURN(std::string digest_str,
128 ComputeHash(augmented_message, *sig_hash_));
129 std::vector<uint8_t> digest(digest_str.begin(), digest_str.end());
130
131 // Construct the PSS padded message, using the same workflow as BoringSSL's
132 // RSA_sign_pss_mgf1 for processing the message (but not signing the message):
133 // google3/third_party/openssl/boringssl/src/crypto/fipsmodule/rsa/rsa.c?l=557
134 if (digest.size() != EVP_MD_size(sig_hash_)) {
135 return absl::InternalError("Invalid input message length.");
136 }
137
138 // Allocate for padded length
139 const int padded_len = BN_num_bytes(RSA_get0_n(rsa_public_key_.get()));
140 std::vector<uint8_t> padded(padded_len);
141
142 // The |md| and |mgf1_md| arguments identify the hash used to calculate
143 // |digest| and the MGF1 hash, respectively. If |mgf1_md| is NULL, |md| is
144 // used. |salt_len| specifies the expected salt length in bytes. If |salt_len|
145 // is -1, then the salt length is the same as the hash length. If -2, then the
146 // salt length is maximal given the size of |rsa|. If unsure, use -1.
147 if (RSA_padding_add_PKCS1_PSS_mgf1(
148 /*rsa=*/rsa_public_key_.get(), /*EM=*/padded.data(),
149 /*mHash=*/digest.data(), /*Hash=*/sig_hash_, /*mgf1Hash=*/mgf1_hash_,
150 /*sLen=*/salt_length_) != kBsslSuccess) {
151 return absl::InternalError(
152 "RSA_padding_add_PKCS1_PSS_mgf1 failed when called from "
153 "RsaBlinder::Blind");
154 }
155
156 bssl::UniquePtr<BN_CTX> bn_ctx(BN_CTX_new());
157 if (!bn_ctx) {
158 return absl::InternalError("BN_CTX_new failed.");
159 }
160
161 std::string encoded_message(padded.begin(), padded.end());
162 ANON_TOKENS_ASSIGN_OR_RETURN(bssl::UniquePtr<BIGNUM> encoded_message_bn,
163 StringToBignum(encoded_message));
164
165 // Take `r^e mod n`. This is an equivalent operation to RSA_encrypt, without
166 // extra encode/decode trips.
167 ANON_TOKENS_ASSIGN_OR_RETURN(bssl::UniquePtr<BIGNUM> rE, NewBigNum());
168 if (BN_mod_exp_mont(rE.get(), r_.get(), RSA_get0_e(rsa_public_key_.get()),
169 RSA_get0_n(rsa_public_key_.get()), bn_ctx.get(),
170 mont_n_.get()) != kBsslSuccess) {
171 return absl::InternalError(
172 "BN_mod_exp_mont failed when called from RsaBlinder::Blind.");
173 }
174
175 // Do `encoded_message*r^e mod n`.
176 //
177 // To avoid leaking side channels, we use Montgomery reduction. This would be
178 // FromMontgomery(ModMulMontgomery(ToMontgomery(m), ToMontgomery(r^e))).
179 // However, this is equivalent to ModMulMontgomery(m, ToMontgomery(r^e)).
180 // Each BN_mod_mul_montgomery removes a factor of R, so by having only one
181 // input in the Montgomery domain, we save a To/FromMontgomery pair.
182 //
183 // Internally, BN_mod_exp_mont actually computes r^e in the Montgomery domain
184 // and converts it out, but there is no public API for this, so we perform an
185 // extra conversion.
186 ANON_TOKENS_ASSIGN_OR_RETURN(bssl::UniquePtr<BIGNUM> multiplication_res,
187 NewBigNum());
188 if (BN_to_montgomery(multiplication_res.get(), rE.get(), mont_n_.get(),
189 bn_ctx.get()) != kBsslSuccess ||
190 BN_mod_mul_montgomery(multiplication_res.get(), encoded_message_bn.get(),
191 multiplication_res.get(), mont_n_.get(),
192 bn_ctx.get()) != kBsslSuccess) {
193 return absl::InternalError(
194 "BN_mod_mul failed when called from RsaBlinder::Blind.");
195 }
196
197 absl::StatusOr<std::string> blinded_msg =
198 BignumToString(*multiplication_res, padded_len);
199
200 // Update RsaBlinder state to kBlinded
201 blinder_state_ = RsaBlinder::BlinderState::kBlinded;
202
203 return blinded_msg;
204 }
205
206 // Unblinds `blind_signature`.
Unblind(const absl::string_view blind_signature)207 absl::StatusOr<std::string> RsaBlinder::Unblind(
208 const absl::string_view blind_signature) {
209 if (blinder_state_ != RsaBlinder::BlinderState::kBlinded) {
210 return absl::FailedPreconditionError(
211 "RsaBlinder is in wrong state to unblind signature.");
212 }
213 const int mod_size = BN_num_bytes(RSA_get0_n(rsa_public_key_.get()));
214 // Parse the signed_blinded_data as BIGNUM.
215 if (blind_signature.size() != mod_size) {
216 return absl::InternalError(absl::StrCat(
217 "Expected blind signature size = ", mod_size,
218 " actual blind signature size = ", blind_signature.size(), " bytes."));
219 }
220
221 bssl::UniquePtr<BN_CTX> bn_ctx(BN_CTX_new());
222 if (!bn_ctx) {
223 return absl::InternalError("BN_CTX_new failed.");
224 }
225
226 ANON_TOKENS_ASSIGN_OR_RETURN(bssl::UniquePtr<BIGNUM> signed_big_num,
227 StringToBignum(blind_signature));
228 ANON_TOKENS_ASSIGN_OR_RETURN(bssl::UniquePtr<BIGNUM> unblinded_sig_big,
229 NewBigNum());
230 // Do `signed_message*r^-1 mod n`.
231 //
232 // To avoid leaking side channels, we use Montgomery reduction. This would be
233 // FromMontgomery(ModMulMontgomery(ToMontgomery(m), ToMontgomery(r^-1))).
234 // However, this is equivalent to ModMulMontgomery(m, ToMontgomery(r^-1)).
235 // Each BN_mod_mul_montgomery removes a factor of R, so by having only one
236 // input in the Montgomery domain, we save a To/FromMontgomery pair.
237 if (BN_mod_mul_montgomery(unblinded_sig_big.get(), signed_big_num.get(),
238 r_inv_mont_.get(), mont_n_.get(),
239 bn_ctx.get()) != kBsslSuccess) {
240 return absl::InternalError(
241 "BN_mod_mul failed when called from RsaBlinder::Unblind.");
242 }
243 absl::StatusOr<std::string> unblinded_signed_message =
244 BignumToString(*unblinded_sig_big, /*output_len=*/mod_size);
245 blinder_state_ = RsaBlinder::BlinderState::kUnblinded;
246 return unblinded_signed_message;
247 }
248
Verify(absl::string_view signature,absl::string_view message)249 absl::Status RsaBlinder::Verify(absl::string_view signature,
250 absl::string_view message) {
251 std::string augmented_message(message);
252 if (public_metadata_.has_value()) {
253 augmented_message = EncodeMessagePublicMetadata(message, *public_metadata_);
254 }
255 return RsaBlindSignatureVerify(salt_length_, sig_hash_, mgf1_hash_, signature,
256 augmented_message, rsa_public_key_.get());
257 }
258
259 } // namespace anonymous_tokens
260
261