Skip to content

Commit

Permalink
BlindRSA now supports all variants from RFC9474.
Browse files Browse the repository at this point in the history
  • Loading branch information
armfazh committed Feb 14, 2024
1 parent 2a2b195 commit d218d13
Show file tree
Hide file tree
Showing 3 changed files with 249 additions and 275 deletions.
306 changes: 105 additions & 201 deletions blindsign/blindrsa/brsa.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,8 @@
//
// This package is compliant with the [RFC-9474] document
// and supports the following variants:
// - [NewVerifier] implements RSABSSA-SHA384-PSS-Deterministic
// - [NewDeterministicVerifier] implements RSABSSA-SHA384-PSSZERO-Deterministic
//
// while these variants are not supported yet:
// - RSABSSA-SHA384-PSS-Deterministic
// - RSABSSA-SHA384-PSSZERO-Deterministic
// - RSABSSA-SHA384-PSS-Randomized
// - RSABSSA-SHA384-PSSZERO-Randomized
//
Expand All @@ -28,271 +26,176 @@ import (
"crypto"
"crypto/rand"
"crypto/rsa"
"hash"
"io"
"math/big"

"github.com/cloudflare/circl/blindsign/blindrsa/internal/common"
"github.com/cloudflare/circl/blindsign/blindrsa/internal/keys"
)

// An randomBRSAVerifier represents a Verifier in the RSA blind signature protocol.
// It carries state needed to produce and validate an RSA signature produced
// using the blind RSA protocol.
type randomBRSAVerifier struct {
// Public key of the Signer
pk *rsa.PublicKey

// Identifier of the cryptographic hash function used in producing the message signature
cryptoHash crypto.Hash

// Hash function used in producing the message signature
hash hash.Hash
}
type Variant int

// A deterministicBRSAVerifier is a BRSAVerifier that supports deterministic signatures.
type deterministicBRSAVerifier struct {
// Public key of the Signer
pk *rsa.PublicKey

// Identifier of the cryptographic hash function used in producing the message signature
cryptoHash crypto.Hash
const (
SHA384PSSRandomized Variant = iota // RSABSSA-SHA384_PSS_Randomized
SHA384PSSZeroRandomized // RSABSSA-SHA384_PSSZero_Randomized
SHA384PSSDeterministic // RSABSSA-SHA384_PSS_Deterministic
SHA384PSSZeroDeterministic // RSABSSA-SHA384_PSSZero_Deterministic
)

// Hash function used in producing the message signature
hash hash.Hash
func (v Variant) String() string {
switch v {
case SHA384PSSRandomized:
return "RSABSSA-SHA384-PSS-Randomized"
case SHA384PSSZeroRandomized:
return "RSABSSA-SHA384-PSSZero-Randomized"
case SHA384PSSDeterministic:
return "RSABSSA-SHA384-PSS-Deterministic"
case SHA384PSSZeroDeterministic:
return "RSABSSA-SHA384-PSSZero-Deterministic"
default:
panic(ErrInvalidVariant)
}
}

// Verifier is a type that implements the client side of the blind RSA
// Client is a type that implements the client side of the blind RSA
// protocol, described in https://www.rfc-editor.org/rfc/rfc9474.html#name-rsabssa-variants
type Verifier interface {
// Blind initializes the blind RSA protocol using an input message and source of randomness. The
// signature is deterministic. This function fails if randomness was not provided.
Blind(random io.Reader, message []byte) ([]byte, VerifierState, error)

// FixedBlind runs the Blind function with fixed blind and salt inputs.
FixedBlind(message, blind, salt []byte) ([]byte, VerifierState, error)

// Verify verifies the input (message, signature) pair and produces an error upon failure.
Verify(message, signature []byte) error

// Hash returns the hash function associated with the Verifier.
Hash() hash.Hash
type Client struct {
v Verifier
prefixLen int
}

// NewDeterministicVerifier creates a new DeterministicBRSAVerifier using the corresponding Signer parameters.
// This corresponds to the RSABSSA-SHA384-PSSZERO-Deterministic variant. See the specification for more details:
// https://www.rfc-editor.org/rfc/rfc9474.html#name-rsabssa-variants
func NewDeterministicVerifier(pk *rsa.PublicKey, hash crypto.Hash) Verifier {
h := common.ConvertHashFunction(hash)
return deterministicBRSAVerifier{
pk: pk,
cryptoHash: hash,
hash: h,
func NewClient(v Variant, pk *rsa.PublicKey) (Client, error) {
verif, err := NewVerifier(v, pk)
if err != nil {
return Client{}, err
}
}

// Hash returns the hash function associated with the BRSAVerifier.
func (v deterministicBRSAVerifier) Hash() hash.Hash {
return v.hash
}

// NewVerifier creates a new BRSAVerifier using the corresponding Signer parameters.
// This corresponds to the RSABSSA-SHA384-PSS-Deterministic variant. See the specification for more details:
// https://www.rfc-editor.org/rfc/rfc9474.html#name-rsabssa-variants
func NewVerifier(pk *rsa.PublicKey, hash crypto.Hash) Verifier {
h := common.ConvertHashFunction(hash)
return randomBRSAVerifier{
pk: pk,
cryptoHash: hash,
hash: h,
var prefixLen int
switch v {
case SHA384PSSDeterministic, SHA384PSSZeroDeterministic:
prefixLen = 0
case SHA384PSSRandomized, SHA384PSSZeroRandomized:
prefixLen = 32
default:
return Client{}, ErrInvalidVariant
}
}

// Hash returns the hash function associated with the BRSAVerifier.
func (v randomBRSAVerifier) Hash() hash.Hash {
return v.hash
return Client{verif, prefixLen}, nil
}

func prepareMsg(message, prefix []byte) []byte {
return append(prefix, message...)
}

func fixedBlind(message, salt []byte, r, rInv *big.Int, pk *rsa.PublicKey, hash hash.Hash) ([]byte, VerifierState, error) {
encodedMsg, err := common.EncodeMessageEMSAPSS(message, pk.N, hash, salt)
if err != nil {
return nil, VerifierState{}, err
}

m := new(big.Int).SetBytes(encodedMsg)

bigE := big.NewInt(int64(pk.E))
x := new(big.Int).Exp(r, bigE, pk.N)
z := new(big.Int).Set(m)
z.Mul(z, x)
z.Mod(z, pk.N)

kLen := (pk.N.BitLen() + 7) / 8
blindedMsg := make([]byte, kLen)
z.FillBytes(blindedMsg)
type State struct {
// The hashed and encoded message being signed
encodedMsg []byte

return blindedMsg, VerifierState{
encodedMsg: encodedMsg,
pk: pk,
hash: hash,
salt: salt,
rInv: rInv,
}, nil
// Inverse of the blinding factor produced by the Verifier
rInv *big.Int
}

// Blind initializes the blind RSA protocol using an input message and source of randomness. The
// signature is deterministic. This function fails if randomness was not provided.
//
// See the specification for more details:
// https://www.rfc-editor.org/rfc/rfc9474.html#name-blind
func (v deterministicBRSAVerifier) Blind(random io.Reader, message []byte) ([]byte, VerifierState, error) {
// Prepare is the process by which the message to be signed and
// verified is prepared for input to the blind signing protocol.
func (c Client) Prepare(random io.Reader, message []byte) ([]byte, error) {
if random == nil {
return nil, VerifierState{}, common.ErrInvalidRandomness
return nil, common.ErrInvalidRandomness
}

r, rInv, err := common.GenerateBlindingFactor(random, v.pk.N)
prefix := make([]byte, c.prefixLen)
_, err := io.ReadFull(random, prefix)
if err != nil {
return nil, VerifierState{}, err
}

return fixedBlind(message, nil, r, rInv, v.pk, v.hash)
}

// FixedBlind runs the Blind function with fixed blind and salt inputs.
func (v deterministicBRSAVerifier) FixedBlind(message, blind, salt []byte) ([]byte, VerifierState, error) {
if blind == nil {
return nil, VerifierState{}, common.ErrInvalidRandomness
}

r := new(big.Int).SetBytes(blind)
if r.Cmp(v.pk.N) >= 0 {
return nil, VerifierState{}, common.ErrInvalidBlind
}
rInv := new(big.Int).ModInverse(r, v.pk.N)
if rInv == nil {
return nil, VerifierState{}, common.ErrInvalidBlind
return nil, err
}

return fixedBlind(message, salt, r, rInv, v.pk, v.hash)
return append(append([]byte{}, prefix...), message...), nil
}

// Verify verifies the input (message, signature) pair and produces an error upon failure.
func (v deterministicBRSAVerifier) Verify(message, signature []byte) error {
return common.VerifyMessageSignature(message, signature, 0, keys.NewBigPublicKey(v.pk), v.cryptoHash)
}

// Blind initializes the blind RSA protocol using an input message and source of randomness. The
// signature includes a randomly generated PSS salt whose length equals the size of the underlying
// hash function. This function fails if randomness was not provided.
//
// See the specification for more details:
// https://www.rfc-editor.org/rfc/rfc9474.html#name-blind
func (v randomBRSAVerifier) Blind(random io.Reader, message []byte) ([]byte, VerifierState, error) {
// Blind initializes the blind RSA protocol using an input message and source of randomness.
// This function fails if randomness was not provided.
func (c Client) Blind(random io.Reader, preparedMessage []byte) (blindedMsg []byte, state State, err error) {
if random == nil {
return nil, VerifierState{}, common.ErrInvalidRandomness
return nil, State{}, common.ErrInvalidRandomness
}

salt := make([]byte, v.hash.Size())
_, err := io.ReadFull(random, salt)
salt := make([]byte, c.v.SaltLength)
_, err = io.ReadFull(random, salt)
if err != nil {
return nil, VerifierState{}, err
return nil, State{}, err
}

r, rInv, err := common.GenerateBlindingFactor(random, v.pk.N)
r, rInv, err := common.GenerateBlindingFactor(random, c.v.pk.N)
if err != nil {
return nil, VerifierState{}, err
return nil, State{}, err
}

return fixedBlind(message, salt, r, rInv, v.pk, v.hash)
return c.fixedBlind(preparedMessage, salt, r, rInv)
}

// FixedBlind runs the Blind function with fixed blind and salt inputs.
func (v randomBRSAVerifier) FixedBlind(message, blind, salt []byte) ([]byte, VerifierState, error) {
if blind == nil {
return nil, VerifierState{}, common.ErrInvalidRandomness
}

r := new(big.Int).SetBytes(blind)
if r.Cmp(v.pk.N) >= 0 {
return nil, VerifierState{}, common.ErrInvalidBlind
}

rInv := new(big.Int).ModInverse(r, v.pk.N)
if rInv == nil {
return nil, VerifierState{}, common.ErrInvalidBlind
func (c Client) fixedBlind(message, salt []byte, r, rInv *big.Int) (blindedMsg []byte, state State, err error) {
encodedMsg, err := common.EncodeMessageEMSAPSS(message, c.v.pk.N, c.v.Hash.New(), salt)
if err != nil {
return nil, State{}, err
}

return fixedBlind(message, salt, r, rInv, v.pk, v.hash)
}

// Verify verifies the input (message, signature) pair and produces an error upon failure.
func (v randomBRSAVerifier) Verify(message, signature []byte) error {
return common.VerifyMessageSignature(message, signature, v.hash.Size(), keys.NewBigPublicKey(v.pk), v.cryptoHash)
}

// An VerifierState carries state needed to complete the blind signature protocol
// as a verifier.
type VerifierState struct {
// Public key of the Signer
pk *rsa.PublicKey

// Hash function used in producing the message signature
hash hash.Hash
m := new(big.Int).SetBytes(encodedMsg)

// The hashed and encoded message being signed
encodedMsg []byte
bigE := big.NewInt(int64(c.v.pk.E))
x := new(big.Int).Exp(r, bigE, c.v.pk.N)
z := new(big.Int).Set(m)
z.Mul(z, x)
z.Mod(z, c.v.pk.N)

// The salt used when encoding the message
salt []byte
kLen := (c.v.pk.N.BitLen() + 7) / 8
blindedMsg = make([]byte, kLen)
z.FillBytes(blindedMsg)

// Inverse of the blinding factor produced by the Verifier
rInv *big.Int
return blindedMsg, State{encodedMsg, rInv}, nil
}

// Finalize computes and outputs the final signature, if it's valid. Otherwise, it returns an error.
//
// See the specification for more details:
// https://www.rfc-editor.org/rfc/rfc9474.html#name-finalize
func (state VerifierState) Finalize(data []byte) ([]byte, error) {
kLen := (state.pk.N.BitLen() + 7) / 8
if len(data) != kLen {
func (c Client) Finalize(state State, blindedSig []byte) ([]byte, error) {
kLen := (c.v.pk.N.BitLen() + 7) / 8
if len(blindedSig) != kLen {
return nil, common.ErrUnexpectedSize
}

z := new(big.Int).SetBytes(data)
z := new(big.Int).SetBytes(blindedSig)
s := new(big.Int).Set(state.rInv)
s.Mul(s, z)
s.Mod(s, state.pk.N)
s.Mod(s, c.v.pk.N)

sig := make([]byte, kLen)
s.FillBytes(sig)

err := common.VerifyBlindSignature(keys.NewBigPublicKey(state.pk), state.encodedMsg, sig)
err := common.VerifyBlindSignature(keys.NewBigPublicKey(c.v.pk), state.encodedMsg, sig)
if err != nil {
return nil, err
}

return sig, nil
}

// CopyBlind returns an encoding of the blind value used in the protocol.
func (state VerifierState) CopyBlind() []byte {
r := new(big.Int).ModInverse(state.rInv, state.pk.N)
return r.Bytes()
// Verify verifies the input (message, signature) pair and produces an error upon failure.
func (c Client) Verify(message, signature []byte) error { return c.v.Verify(message, signature) }

type Verifier struct {
// Public key of the Signer
pk *rsa.PublicKey
rsa.PSSOptions
}

func NewVerifier(v Variant, pk *rsa.PublicKey) (Verifier, error) {
switch v {
case SHA384PSSRandomized, SHA384PSSDeterministic:
return Verifier{pk, rsa.PSSOptions{Hash: crypto.SHA384, SaltLength: crypto.SHA384.Size()}}, nil
case SHA384PSSZeroRandomized, SHA384PSSZeroDeterministic:
return Verifier{pk, rsa.PSSOptions{Hash: crypto.SHA384, SaltLength: 0}}, nil
default:
return Verifier{}, ErrInvalidVariant
}
}

// CopySalt returns an encoding of the per-message salt used in the protocol.
func (state VerifierState) CopySalt() []byte {
salt := make([]byte, len(state.salt))
copy(salt, state.salt)
return salt
// Verify verifies the input (message, signature) pair and produces an error upon failure.
func (v Verifier) Verify(message, signature []byte) error {
return common.VerifyMessageSignature(message, signature, v.SaltLength, keys.NewBigPublicKey(v.pk), v.Hash)
}

// An Signer represents the Signer in the blind RSA protocol.
// Signer structure represents the signing server in the blind RSA protocol.
// It carries the raw RSA private key used for signing blinded messages.
type Signer struct {
// An RSA private key
Expand Down Expand Up @@ -334,6 +237,7 @@ func (signer Signer) BlindSign(data []byte) ([]byte, error) {
}

var (
ErrInvalidVariant = common.ErrInvalidVariant
ErrUnexpectedSize = common.ErrUnexpectedSize
ErrInvalidMessageLength = common.ErrInvalidMessageLength
ErrInvalidBlind = common.ErrInvalidBlind
Expand Down
Loading

0 comments on commit d218d13

Please sign in to comment.