github.com/cloudflare/circl@v1.5.0/blindsign/blindrsa/partiallyblindrsa/pbrsa.go (about)

     1  // Package partiallyblindrsa implements a partially blind RSA protocol.
     2  package partiallyblindrsa
     3  
     4  import (
     5  	"crypto"
     6  	"crypto/rand"
     7  	"crypto/rsa"
     8  	"encoding/binary"
     9  	"errors"
    10  	"hash"
    11  	"io"
    12  	"math/big"
    13  
    14  	"github.com/cloudflare/circl/blindsign/blindrsa/internal/common"
    15  	"github.com/cloudflare/circl/blindsign/blindrsa/internal/keys"
    16  	"golang.org/x/crypto/hkdf"
    17  )
    18  
    19  func encodeMessageMetadata(message, metadata []byte) []byte {
    20  	lenBuffer := []byte{'m', 's', 'g', 0, 0, 0, 0}
    21  
    22  	binary.BigEndian.PutUint32(lenBuffer[3:], uint32(len(metadata)))
    23  	framedMetadata := append(lenBuffer, metadata...)
    24  	return append(framedMetadata, message...)
    25  }
    26  
    27  // A randomizedVerifier represents a Verifier in the partially blind RSA signature protocol.
    28  // It carries state needed to produce and validate an RSA signature produced
    29  // using the blind RSA protocol.
    30  type randomizedVerifier struct {
    31  	// Public key of the Signer
    32  	pk *keys.BigPublicKey
    33  
    34  	// Identifier of the cryptographic hash function used in producing the message signature
    35  	cryptoHash crypto.Hash
    36  
    37  	// Hash function used in producing the message signature
    38  	hash hash.Hash
    39  }
    40  
    41  // NewVerifier creates a new PBRSAVerifier using the corresponding Signer parameters.
    42  // This corresponds to the RSAPBSSA-SHA384-PSS-Deterministic variant. See the specification for more details:
    43  // https://datatracker.ietf.org/doc/html/draft-amjad-cfrg-partially-blind-rsa#name-rsapbssa-variants
    44  func NewVerifier(pk *rsa.PublicKey, hash crypto.Hash) Verifier {
    45  	h := common.ConvertHashFunction(hash)
    46  	return randomizedVerifier{
    47  		pk:         keys.NewBigPublicKey(pk),
    48  		cryptoHash: hash,
    49  		hash:       h,
    50  	}
    51  }
    52  
    53  // derivePublicKey tweaks the public key based on the input metadata.
    54  //
    55  // See the specification for more details:
    56  // https://datatracker.ietf.org/doc/html/draft-amjad-cfrg-partially-blind-rsa-00#name-public-key-augmentation
    57  //
    58  // See the following issue for more discussion on HKDF vs hash-to-field:
    59  // https://github.com/cfrg/draft-irtf-cfrg-hash-to-curve/issues/202
    60  func derivePublicKey(h crypto.Hash, pk *keys.BigPublicKey, metadata []byte) *keys.BigPublicKey {
    61  	// expandLen = ceil((ceil(log2(\lambda)/2) + k) / 8), where k is the security parameter of the suite (e.g., k = 128).
    62  	// We stretch the input metadata beyond \lambda bits s.t. the output bytes are indifferentiable from truly random bytes
    63  	lambda := pk.N.BitLen() / 2
    64  	expandLen := uint((lambda + 128) / 8)
    65  
    66  	hkdfSalt := make([]byte, (pk.N.BitLen()+7)/8)
    67  	pk.N.FillBytes(hkdfSalt)
    68  	hkdfInput := append([]byte("key"), append(metadata, 0x00)...)
    69  
    70  	hkdf := hkdf.New(h.New, hkdfInput, hkdfSalt, []byte("PBRSA"))
    71  	bytes := make([]byte, expandLen)
    72  	_, err := hkdf.Read(bytes)
    73  	if err != nil {
    74  		panic(err)
    75  	}
    76  
    77  	// H_MD(D) = 1 || G(x), where G(x) is output of length \lambda-2 bits
    78  	// We do this by sampling \lambda bits, clearing the top two bits (so the output is \lambda-2 bits)
    79  	// and setting the bottom bit (so the result is odd).
    80  	newE := new(big.Int).SetBytes(bytes[:lambda/8])
    81  	newE.SetBit(newE, 0, 1)
    82  	newE.SetBit(newE, lambda-1, 0)
    83  	newE.SetBit(newE, lambda-2, 0)
    84  
    85  	// Compute e_MD = e * H_MD(D)
    86  	return &keys.BigPublicKey{
    87  		N: pk.N,
    88  		E: newE,
    89  	}
    90  }
    91  
    92  // deriveKeyPair tweaks the private key using the metadata as input.
    93  //
    94  // See the specification for more details:
    95  // https://datatracker.ietf.org/doc/html/draft-amjad-cfrg-partially-blind-rsa-00#name-private-key-augmentation
    96  func deriveKeyPair(h crypto.Hash, sk *keys.BigPrivateKey, metadata []byte) *keys.BigPrivateKey {
    97  	// pih(N) = (p-1)(q-1)
    98  	pm1 := new(big.Int).Set(sk.P)
    99  	pm1.Sub(pm1, new(big.Int).SetInt64(int64(1)))
   100  	qm1 := new(big.Int).Set(sk.Q)
   101  	qm1.Sub(qm1, new(big.Int).SetInt64(int64(1)))
   102  	phi := new(big.Int).Mul(pm1, qm1)
   103  
   104  	// d = e^-1 mod phi(N)
   105  	pk := derivePublicKey(h, sk.Pk, metadata)
   106  	bigE := new(big.Int).Mod(pk.E, phi)
   107  	d := new(big.Int).ModInverse(bigE, phi)
   108  	return &keys.BigPrivateKey{
   109  		Pk: pk,
   110  		D:  d,
   111  		P:  sk.P,
   112  		Q:  sk.Q,
   113  	}
   114  }
   115  
   116  func fixedPartiallyBlind(message, salt []byte, r, rInv *big.Int, pk *keys.BigPublicKey, hash hash.Hash) ([]byte, VerifierState, error) {
   117  	encodedMsg, err := common.EncodeMessageEMSAPSS(message, pk.N, hash, salt)
   118  	if err != nil {
   119  		return nil, VerifierState{}, err
   120  	}
   121  
   122  	m := new(big.Int).SetBytes(encodedMsg)
   123  
   124  	bigE := pk.E
   125  	x := new(big.Int).Exp(r, bigE, pk.N)
   126  	z := new(big.Int).Set(m)
   127  	z.Mul(z, x)
   128  	z.Mod(z, pk.N)
   129  
   130  	kLen := (pk.N.BitLen() + 7) / 8
   131  	blindedMsg := make([]byte, kLen)
   132  	z.FillBytes(blindedMsg)
   133  
   134  	return blindedMsg, VerifierState{
   135  		encodedMsg: encodedMsg,
   136  		pk:         pk,
   137  		hash:       hash,
   138  		salt:       salt,
   139  		rInv:       rInv,
   140  	}, nil
   141  }
   142  
   143  // Verifier is a type that implements the client side of the partially blind RSA
   144  // protocol, described in https://datatracker.ietf.org/doc/html/draft-amjad-cfrg-partially-blind-rsa-00
   145  type Verifier interface {
   146  	// Blind initializes the partially blind RSA protocol using an input message and source of
   147  	// randomness. The signature includes a randomly generated PSS salt whose length equals the
   148  	// size of the underlying hash function. This function fails if randomness was not provided.
   149  	Blind(random io.Reader, message, metadata []byte) ([]byte, VerifierState, error)
   150  
   151  	// FixedBlind initializes the partially blind RSA protocol using an input message, metadata, and randomness values.
   152  	FixedBlind(message, metadata, salt, blind, blindInv []byte) ([]byte, VerifierState, error)
   153  
   154  	// Verify verifies the input (message, signature) pair using the augmented public key
   155  	// and produces an error upon failure.
   156  	Verify(message, signature, metadata []byte) error
   157  
   158  	// Hash returns the hash function associated with the Verifier.
   159  	Hash() hash.Hash
   160  }
   161  
   162  // Blind initializes the partially blind RSA protocol using an input message and source of randomness. The
   163  // signature includes a randomly generated PSS salt whose length equals the size of the underlying
   164  // hash function. This function fails if randomness was not provided.
   165  //
   166  // See the specification for more details:
   167  // https://datatracker.ietf.org/doc/html/draft-amjad-cfrg-partially-blind-rsa-00#name-blind
   168  func (v randomizedVerifier) Blind(random io.Reader, message, metadata []byte) ([]byte, VerifierState, error) {
   169  	if random == nil {
   170  		return nil, VerifierState{}, common.ErrInvalidRandomness
   171  	}
   172  
   173  	salt := make([]byte, v.hash.Size())
   174  	_, err := io.ReadFull(rand.Reader, salt)
   175  	if err != nil {
   176  		return nil, VerifierState{}, err
   177  	}
   178  
   179  	r, rInv, err := common.GenerateBlindingFactor(random, v.pk.N)
   180  	if err != nil {
   181  		return nil, VerifierState{}, err
   182  	}
   183  
   184  	return v.FixedBlind(message, metadata, salt, r.Bytes(), rInv.Bytes())
   185  }
   186  
   187  // FixedBlind initializes the partially blind RSA using fixed randomness as input.
   188  func (v randomizedVerifier) FixedBlind(message, metadata, salt, blind, blindInv []byte) ([]byte, VerifierState, error) {
   189  	r := new(big.Int).SetBytes(blind)
   190  	rInv := new(big.Int).SetBytes(blindInv)
   191  	metadataKey := derivePublicKey(v.cryptoHash, v.pk, metadata)
   192  	inputMsg := encodeMessageMetadata(message, metadata)
   193  	return fixedPartiallyBlind(inputMsg, salt, r, rInv, metadataKey, v.hash)
   194  }
   195  
   196  // Verify verifies the input (message, signature) pair using the augmented public key
   197  // and produces an error upon failure.
   198  //
   199  // See the specification for more details:
   200  // https://datatracker.ietf.org/doc/html/draft-amjad-cfrg-partially-blind-rsa-00#name-verification-2
   201  func (v randomizedVerifier) Verify(message, metadata, signature []byte) error {
   202  	metadataKey := derivePublicKey(v.cryptoHash, v.pk, metadata)
   203  	inputMsg := encodeMessageMetadata(message, metadata)
   204  	return common.VerifyMessageSignature(inputMsg, signature, v.hash.Size(), metadataKey, v.cryptoHash)
   205  }
   206  
   207  // Hash returns the hash function associated with the Verifier.
   208  func (v randomizedVerifier) Hash() hash.Hash {
   209  	return v.hash
   210  }
   211  
   212  // A VerifierState carries state needed to complete the blind signature protocol
   213  // as a verifier.
   214  type VerifierState struct {
   215  	// Public key of the Signer
   216  	pk *keys.BigPublicKey
   217  
   218  	// Hash function used in producing the message signature
   219  	hash hash.Hash
   220  
   221  	// The hashed and encoded message being signed
   222  	encodedMsg []byte
   223  
   224  	// The salt used when encoding the message
   225  	salt []byte
   226  
   227  	// Inverse of the blinding factor produced by the Verifier
   228  	rInv *big.Int
   229  }
   230  
   231  // Finalize computes and outputs the final signature, if it's valid. Otherwise, it returns an error.
   232  //
   233  // See the specification for more details:
   234  // https://datatracker.ietf.org/doc/html/draft-amjad-cfrg-partially-blind-rsa-00#name-finalize
   235  func (state VerifierState) Finalize(data []byte) ([]byte, error) {
   236  	kLen := (state.pk.N.BitLen() + 7) / 8
   237  	if len(data) != kLen {
   238  		return nil, common.ErrUnexpectedSize
   239  	}
   240  
   241  	z := new(big.Int).SetBytes(data)
   242  	s := new(big.Int).Set(state.rInv)
   243  	s.Mul(s, z)
   244  	s.Mod(s, state.pk.N)
   245  
   246  	sig := make([]byte, kLen)
   247  	s.FillBytes(sig)
   248  
   249  	err := common.VerifyBlindSignature(state.pk, state.encodedMsg, sig)
   250  	if err != nil {
   251  		return nil, err
   252  	}
   253  
   254  	return sig, nil
   255  }
   256  
   257  // CopyBlind returns an encoding of the blind value used in the protocol.
   258  func (state VerifierState) CopyBlind() []byte {
   259  	r := new(big.Int).ModInverse(state.rInv, state.pk.N)
   260  	return r.Bytes()
   261  }
   262  
   263  // CopySalt returns an encoding of the per-message salt used in the protocol.
   264  func (state VerifierState) CopySalt() []byte {
   265  	salt := make([]byte, len(state.salt))
   266  	copy(salt, state.salt)
   267  	return salt
   268  }
   269  
   270  // An Signer represents the Signer in the blind RSA protocol.
   271  // It carries the raw RSA private key used for signing blinded messages.
   272  type Signer struct {
   273  	// An RSA private key
   274  	sk *keys.BigPrivateKey
   275  	h  crypto.Hash
   276  }
   277  
   278  // isSafePrime returns true if the input prime p is safe, i.e., p = (2 * q) + 1 for some prime q
   279  func isSafePrime(p *big.Int) bool {
   280  	q := new(big.Int).Set(p)
   281  	q.Sub(q, big.NewInt(1))
   282  	q.Div(q, big.NewInt(2))
   283  	return q.ProbablyPrime(20)
   284  }
   285  
   286  // NewSigner creates a new Signer for the blind RSA protocol using an RSA private key.
   287  func NewSigner(sk *rsa.PrivateKey, h crypto.Hash) (Signer, error) {
   288  	bigSk := keys.NewBigPrivateKey(sk)
   289  	if !(isSafePrime(bigSk.P) && isSafePrime(bigSk.Q)) {
   290  		return Signer{}, ErrInvalidPrivateKey
   291  	}
   292  
   293  	return Signer{
   294  		sk: bigSk,
   295  		h:  h,
   296  	}, nil
   297  }
   298  
   299  // BlindSign blindly computes the RSA operation using the Signer's private key on the blinded
   300  // message input, if it's of valid length, and returns an error should the function fail.
   301  //
   302  // See the specification for more details:
   303  // https://datatracker.ietf.org/doc/html/draft-amjad-cfrg-partially-blind-rsa-00#name-blindsign
   304  func (signer Signer) BlindSign(data, metadata []byte) ([]byte, error) {
   305  	kLen := (signer.sk.Pk.N.BitLen() + 7) / 8
   306  	if len(data) != kLen {
   307  		return nil, common.ErrUnexpectedSize
   308  	}
   309  
   310  	m := new(big.Int).SetBytes(data)
   311  	if m.Cmp(signer.sk.Pk.N) > 0 {
   312  		return nil, common.ErrInvalidMessageLength
   313  	}
   314  
   315  	skPrime := deriveKeyPair(signer.h, signer.sk, metadata)
   316  
   317  	s, err := common.DecryptAndCheck(rand.Reader, skPrime, m)
   318  	if err != nil {
   319  		return nil, err
   320  	}
   321  
   322  	blindSig := make([]byte, kLen)
   323  	s.FillBytes(blindSig)
   324  
   325  	return blindSig, nil
   326  }
   327  
   328  var (
   329  	// ErrInvalidPrivateKey is the error used if a private key is invalid
   330  	ErrInvalidPrivateKey    = errors.New("blindsign/blindrsa/partiallyblindrsa: invalid private key")
   331  	ErrUnexpectedSize       = common.ErrUnexpectedSize
   332  	ErrInvalidMessageLength = common.ErrInvalidMessageLength
   333  	ErrInvalidRandomness    = common.ErrInvalidRandomness
   334  )