chromium/third_party/anonymous_tokens/src/anonymous_tokens/cpp/crypto/crypto_utils.h

// Copyright 2023 Google LLC
//
// 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
//
//    https://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.

#ifndef ANONYMOUS_TOKENS_CPP_CRYPTO_CRYPTO_UTILS_H_
#define ANONYMOUS_TOKENS_CPP_CRYPTO_CRYPTO_UTILS_H_

#include <stddef.h>

#include <memory>
#include <optional>
#include <string>

#include "absl/status/statusor.h"
#include "absl/strings/string_view.h"
#include <openssl/base.h>
#include <openssl/bn.h>
#include <openssl/evp.h>
#include <openssl/rsa.h>

namespace anonymous_tokens {

// Internal functions only exposed for testing.
namespace internal {

// Outputs a public metadata `hash` using HKDF with the public metadata as
// input and the rsa modulus as salt. The expected output hash size is passed as
// out_len_bytes.
//
// Implementation follows the steps listed in
// https://datatracker.ietf.org/doc/draft-amjad-cfrg-partially-blind-rsa/
//
// This method internally calls HKDF with output size of more than
// out_len_bytes and later truncates the output to out_len_bytes. This is done
// so that the output is indifferentiable from truly random bytes.
// https://cfrg.github.io/draft-irtf-cfrg-hash-to-curve/draft-irtf-cfrg-hash-to-curve.html#name-hashing-to-a-finite-field
absl::StatusOr<bssl::UniquePtr<BIGNUM>> PublicMetadataHashWithHKDF(
    absl::string_view public_metadata, absl::string_view rsa_modulus_str,
    size_t out_len_bytes);

}  // namespace internal

// Deletes a BN_CTX.
class BnCtxDeleter {};
BnCtxPtr;

// Deletes a BN_MONT_CTX.
class BnMontCtxDeleter {};
BnMontCtxPtr;

// Deletes an EVP_MD_CTX.
class EvpMdCtxDeleter {};
EvpMdCtxPtr;

// Creates and starts a BIGNUM context.
absl::StatusOr<BnCtxPtr> GetAndStartBigNumCtx();

// Creates a new BIGNUM.
absl::StatusOr<bssl::UniquePtr<BIGNUM>> NewBigNum();

// Converts a BIGNUM to string.
absl::StatusOr<std::string> BignumToString(const BIGNUM& big_num,
                                           size_t output_len);

// Converts a string to BIGNUM.
absl::StatusOr<bssl::UniquePtr<BIGNUM>> StringToBignum(
    absl::string_view input_str);

// Retrieve error messages from OpenSSL.
std::string GetSslErrors();

// Mask message using protocol at
// https://datatracker.ietf.org/doc/draft-irtf-cfrg-rsa-blind-signatures/
std::string MaskMessageConcat(absl::string_view mask,
                              absl::string_view message);

// Encode Message and Public Metadata using steps in
// https://datatracker.ietf.org/doc/draft-amjad-cfrg-partially-blind-rsa/
//
// The length of public metadata must fit in 4 bytes.
std::string EncodeMessagePublicMetadata(absl::string_view message,
                                        absl::string_view public_metadata);

// Compute 2^(x - 1/2).
absl::StatusOr<bssl::UniquePtr<BIGNUM>> GetRsaSqrtTwo(int x);

// Compute compute 2^x.
absl::StatusOr<bssl::UniquePtr<BIGNUM>> ComputePowerOfTwo(int x);

// ComputeHash sub-routine used during blindness and verification of RSA blind
// signatures protocol with or without public metadata.
absl::StatusOr<std::string> ComputeHash(absl::string_view input,
                                        const EVP_MD& hasher);

// Computes the Carmichael LCM given phi(p) and phi(q) where N = p*q is a safe
// RSA modulus.
absl::StatusOr<bssl::UniquePtr<BIGNUM>> ComputeCarmichaelLcm(
    const BIGNUM& phi_p, const BIGNUM& phi_q, BN_CTX& bn_ctx);

// Create bssl::UniquePtr<RSA> representing a RSA private key.
//
// Note that this method should not be used to create a key with public exponent
// greater than 2^32.
absl::StatusOr<bssl::UniquePtr<RSA>> CreatePrivateKeyRSA(
    absl::string_view rsa_modulus, absl::string_view public_exponent,
    absl::string_view private_exponent, absl::string_view p,
    absl::string_view q, absl::string_view dp, absl::string_view dq,
    absl::string_view crt);

// Create bssl::UniquePtr<RSA> representing a RSA public key.
//
// Note that this method should not be used to create a key with public exponent
// greater than 2^32.
absl::StatusOr<bssl::UniquePtr<RSA>> CreatePublicKeyRSA(
    absl::string_view rsa_modulus, absl::string_view public_exponent);

// Create bssl::UniquePtr<RSA> representing a RSA public key derived using
// public metadata.
//
// If the boolean "use_rsa_public_exponent" is set to false, the public exponent
// is not used in any computations.
//
// Setting "use_rsa_public_exponent" to true is deprecated.
absl::StatusOr<bssl::UniquePtr<RSA>> CreatePublicKeyRSAWithPublicMetadata(
    const BIGNUM& rsa_modulus, const BIGNUM& public_exponent,
    absl::string_view public_metadata, bool use_rsa_public_exponent);

// Create bssl::UniquePtr<RSA> representing a RSA public key derived using
// public metadata.
//
// If the boolean "use_rsa_public_exponent" is set to false, the public exponent
// is not used in any computations.
//
// Setting "use_rsa_public_exponent" to true is deprecated.
absl::StatusOr<bssl::UniquePtr<RSA>> CreatePublicKeyRSAWithPublicMetadata(
    absl::string_view rsa_modulus, absl::string_view public_exponent,
    absl::string_view public_metadata, bool use_rsa_public_exponent);

// Compute exponent using only the public metadata and RSA modulus n. Assumes
// that n is a safe modulus i.e. it produces a strong RSA key pair. If not, the
// exponent may be invalid.
//
// Empty public metadata is considered to be a valid value for public_metadata
// and will output a valid exponent.
absl::StatusOr<bssl::UniquePtr<BIGNUM>> ComputeExponentWithPublicMetadata(
    const BIGNUM& n, absl::string_view public_metadata);

// Computes exponent by multiplying the public exponent e with the
// exponent derived from public metadata and RSA modulus n. Assumes that n is a
// safe modulus i.e. it produces a strong RSA key pair. If not, the exponent may
// be invalid.
//
// Empty public metadata is considered to be a valid value for public_metadata
// and will output an exponent different than `e` as well.
//
// This function is now deprecated.
absl::StatusOr<bssl::UniquePtr<BIGNUM>>
ComputeExponentWithPublicMetadataAndPublicExponent(
    const BIGNUM& n, const BIGNUM& e, absl::string_view public_metadata);

// Helper method that implements RSA PSS Blind Signatures verification protocol
// for both the standard scheme as well as the public metadata version.
//
// For the public metadata version,
//
// 1) `rsa_public_key' must contain a public exponent derived using the public
// metadata.
//
// 2) The `message' must be an encoding of an original input message
// and the public metadata e.g. by using EncodeMessagePublicMetadata method in
// this file. The caller should make sure that its original input message is a
// random message. In case it is not, it should be concatenated with a random
// string.
absl::Status RsaBlindSignatureVerify(int salt_length, const EVP_MD* sig_hash,
                                     const EVP_MD* mgf1_hash,
                                     absl::string_view signature,
                                     absl::string_view message,
                                     RSA* rsa_public_key);

// This method outputs a DER encoding of RSASSA-PSS (RSA Signature Scheme with
// Appendix - Probabilistic Signature Scheme) Public Key as described here
// https://datatracker.ietf.org/doc/html/rfc3447.html using the object
// identifier(s) here: https://oidref.com/1.2.840.113549.1.1.10  and using a
// fixed salt length of 48 bytes, SHA384 as the signature's hash function as
// well as the hash function that the signature's mask generating function is
// based on. A publicly availble equivalent function is available in Goa here:
// https://github.com/cloudflare/pat-go/blob/11579ba5b0b9b77d3e8e3d5247a98811227ac82e/x509util.go#L56
//
absl::StatusOr<std::string> RsaSsaPssPublicKeyToDerEncoding(const RSA* rsa);

// This method DER encodes inputted RSA public keys and hashes the encodings
// using SHA256. It returns true if the hashes collide on the least significant
// byte, otherwise it returns false.
//
// This method will be used to ensure that a new key's truncated key id does
// not collide with an existing key's truncated key id during key rotation as
// described here:
// https://www.ietf.org/archive/id/draft-ietf-privacypass-protocol-10.html#public-issuer-configuration
absl::StatusOr<bool> PrivacyPassTruncatedTokenKeyIdCollision(
    const RSA* public_key, const RSA* other_public_key);

}  // namespace anonymous_tokens

#endif  // ANONYMOUS_TOKENS_CPP_CRYPTO_CRYPTO_UTILS_H_