• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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