From d218d1396c604442b41d93e3ae2b74eb3411dcb9 Mon Sep 17 00:00:00 2001 From: armfazh Date: Wed, 11 Oct 2023 13:58:45 -0700 Subject: [PATCH] BlindRSA now supports all variants from RFC9474. --- blindsign/blindrsa/brsa.go | 306 +++++++------------ blindsign/blindrsa/brsa_test.go | 215 ++++++++----- blindsign/blindrsa/internal/common/common.go | 3 + 3 files changed, 249 insertions(+), 275 deletions(-) diff --git a/blindsign/blindrsa/brsa.go b/blindsign/blindrsa/brsa.go index 5268cb905..a0b4cb39e 100644 --- a/blindsign/blindrsa/brsa.go +++ b/blindsign/blindrsa/brsa.go @@ -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 // @@ -28,7 +26,6 @@ import ( "crypto" "crypto/rand" "crypto/rsa" - "hash" "io" "math/big" @@ -36,242 +33,136 @@ import ( "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 } @@ -279,20 +170,32 @@ func (state VerifierState) Finalize(data []byte) ([]byte, error) { 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 @@ -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 diff --git a/blindsign/blindrsa/brsa_test.go b/blindsign/blindrsa/brsa_test.go index 6b7d1a4f2..36e607624 100644 --- a/blindsign/blindrsa/brsa_test.go +++ b/blindsign/blindrsa/brsa_test.go @@ -2,7 +2,6 @@ package blindrsa import ( "bytes" - "crypto" "crypto/rand" "crypto/rsa" "crypto/x509" @@ -20,7 +19,7 @@ import ( ) // 2048-bit RSA private key -var testPrivateKey = testingKey(` +const testPrivateKey = ` -----BEGIN RSA TESTING KEY----- MIIEowIBAAKCAQEAyxrta2qV9bHOATpM/KsluUsuZKIwNOQlCn6rQ8DfOowSmTrx KxEZCNS0cb7DHUtsmtnN2pBhKi7pA1I+beWiJNawLwnlw3TQz+Adj1KcUAp4ovZ5 @@ -47,12 +46,12 @@ IVEW06GXuhv46p0wt3zXx1dcbWX6LdJaDB4MHqevkiDAqHntmXLbmVd9pXCGn/a2 xznO3QKBgHkPJPEiCzRugzgN9UxOT5tNQCSGMOwJUd7qP0TWgvsWHT1N07JLgC8c Yg0f1rCxEAQo5BVppiQFp0FA7W52DUnMEfBtiehZ6xArW7crO91gFRqKBWZ3Jjyz /JcS8m5UgQxC8mmb/2wLD5TDvWw+XCfjUgWmvqIi5dcJgmuTAn5X ------END RSA TESTING KEY-----`) +-----END RSA TESTING KEY-----` func testingKey(s string) string { return strings.ReplaceAll(s, "TESTING KEY", "PRIVATE KEY") } func loadPrivateKey() (*rsa.PrivateKey, error) { - block, _ := pem.Decode([]byte(testPrivateKey)) + block, _ := pem.Decode([]byte(testingKey(testPrivateKey))) if block == nil || block.Type != "RSA PRIVATE KEY" { return nil, fmt.Errorf("PEM private key decoding failed") } @@ -103,10 +102,15 @@ func loadStrongRSAKey() *rsa.PrivateKey { return key } -func runSignatureProtocol(signer Signer, verifier Verifier, message []byte, random io.Reader) ([]byte, error) { - blindedMsg, state, err := verifier.Blind(random, message) +func runSignatureProtocol(signer Signer, client Client, message []byte, random io.Reader) ([]byte, error) { + inputMsg, err := client.Prepare(random, message) if err != nil { - return nil, err + return nil, fmt.Errorf("prepare failed: %w", err) + } + + blindedMsg, state, err := client.Blind(random, inputMsg) + if err != nil { + return nil, fmt.Errorf("blind failed: %w", err) } kLen := (signer.sk.N.BitLen() + 7) / 8 @@ -116,21 +120,21 @@ func runSignatureProtocol(signer Signer, verifier Verifier, message []byte, rand blindedSig, err := signer.BlindSign(blindedMsg) if err != nil { - return nil, err + return nil, fmt.Errorf("blindSign failed: %w", err) } if len(blindedSig) != kLen { return nil, fmt.Errorf("Protocol message (blind signature) length mismatch, expected %d, got %d", kLen, len(blindedMsg)) } - sig, err := state.Finalize(blindedSig) + sig, err := client.Finalize(state, blindedSig) if err != nil { - return nil, err + return nil, fmt.Errorf("finalize failed: %w", err) } - err = verifier.Verify(message, sig) + err = client.Verify(inputMsg, sig) if err != nil { - return nil, err + return nil, fmt.Errorf("verification failed: %w", err) } return sig, nil @@ -143,15 +147,27 @@ func TestRoundTrip(t *testing.T) { t.Fatal(err) } - verifier := NewVerifier(&key.PublicKey, crypto.SHA512) - signer := NewSigner(key) + for _, variant := range []Variant{ + SHA384PSSDeterministic, + SHA384PSSZeroDeterministic, + SHA384PSSRandomized, + SHA384PSSZeroRandomized, + } { + t.Run(variant.String(), func(tt *testing.T) { + client, err := NewClient(variant, &key.PublicKey) + if err != nil { + t.Fatal(err) + } + signer := NewSigner(key) - sig, err := runSignatureProtocol(signer, verifier, message, rand.Reader) - if err != nil { - t.Fatal(err) - } - if sig == nil { - t.Fatal("nil signature output") + sig, err := runSignatureProtocol(signer, client, message, rand.Reader) + if err != nil { + t.Fatal(err) + } + if sig == nil { + t.Fatal("nil signature output") + } + }) } } @@ -162,10 +178,13 @@ func TestDeterministicRoundTrip(t *testing.T) { t.Fatal(err) } - verifier := NewDeterministicVerifier(&key.PublicKey, crypto.SHA512) + client, err := NewClient(SHA384PSSDeterministic, &key.PublicKey) + if err != nil { + t.Fatal(err) + } signer := NewSigner(key) - sig, err := runSignatureProtocol(signer, verifier, message, rand.Reader) + sig, err := runSignatureProtocol(signer, client, message, rand.Reader) if err != nil { t.Fatal(err) } @@ -181,10 +200,13 @@ func TestDeterministicBlindFailure(t *testing.T) { t.Fatal(err) } - verifier := NewDeterministicVerifier(&key.PublicKey, crypto.SHA512) + client, err := NewClient(SHA384PSSDeterministic, &key.PublicKey) + if err != nil { + t.Fatal(err) + } signer := NewSigner(key) - _, err = runSignatureProtocol(signer, verifier, message, nil) + _, err = runSignatureProtocol(signer, client, message, nil) if err == nil { t.Fatal("Expected signature generation to fail with empty randomness") } @@ -197,14 +219,17 @@ func TestRandomSignVerify(t *testing.T) { t.Fatal(err) } - verifier := NewVerifier(&key.PublicKey, crypto.SHA512) + client, err := NewClient(SHA384PSSRandomized, &key.PublicKey) + if err != nil { + t.Fatal(err) + } signer := NewSigner(key) - sig1, err := runSignatureProtocol(signer, verifier, message, rand.Reader) + sig1, err := runSignatureProtocol(signer, client, message, rand.Reader) if err != nil { t.Fatal(err) } - sig2, err := runSignatureProtocol(signer, verifier, message, rand.Reader) + sig2, err := runSignatureProtocol(signer, client, message, rand.Reader) if err != nil { t.Fatal(err) } @@ -236,16 +261,19 @@ func TestFixedRandomSignVerify(t *testing.T) { t.Fatal(err) } - verifier := NewVerifier(&key.PublicKey, crypto.SHA512) + client, err := NewClient(SHA384PSSRandomized, &key.PublicKey) + if err != nil { + t.Fatal(err) + } signer := NewSigner(key) mockRand := &mockRandom{0} - sig1, err := runSignatureProtocol(signer, verifier, message, mockRand) + sig1, err := runSignatureProtocol(signer, client, message, mockRand) if err != nil { t.Fatal(err) } mockRand = &mockRandom{0} - sig2, err := runSignatureProtocol(signer, verifier, message, mockRand) + sig2, err := runSignatureProtocol(signer, client, message, mockRand) if err != nil { t.Fatal(err) } @@ -384,31 +412,29 @@ func verifyTestVector(t *testing.T, vector testVector) { t.Fatal("Failed to compute blind inverse") } - signer := NewSigner(key) - - var verifier Verifier + var variant Variant switch vector.name { case "RSABSSA-SHA384-PSS-Deterministic": - verifier = NewVerifier(&key.PublicKey, crypto.SHA384) + variant = SHA384PSSDeterministic case "RSABSSA-SHA384-PSSZERO-Deterministic": - verifier = NewDeterministicVerifier(&key.PublicKey, crypto.SHA384) - case "RSABSSA-SHA384-PSS-Randomized", "RSABSSA-SHA384-PSSZERO-Randomized": - t.Skipf("variant %v not supported yet", vector.name) + variant = SHA384PSSZeroDeterministic + case "RSABSSA-SHA384-PSS-Randomized": + variant = SHA384PSSRandomized + case "RSABSSA-SHA384-PSSZERO-Randomized": + variant = SHA384PSSZeroRandomized default: t.Fatal("variant not supported") } - inputMsg := prepareMsg(vector.msg, vector.msgPrefix) - got := hex.EncodeToString(inputMsg) - want := hex.EncodeToString(vector.inputMsg) - if got != want { - test.ReportError(t, got, want) - } + signer := NewSigner(key) - blindedMsg, state, err := fixedBlind(inputMsg, vector.salt, r, rInv, &key.PublicKey, verifier.Hash()) + client, err := NewClient(variant, &key.PublicKey) + test.CheckNoErr(t, err, "new client failed") + + blindedMsg, state, err := client.fixedBlind(vector.inputMsg, vector.salt, r, rInv) test.CheckNoErr(t, err, "fixedBlind failed") - got = hex.EncodeToString(blindedMsg) - want = hex.EncodeToString(vector.blindedMessage) + got := hex.EncodeToString(blindedMsg) + want := hex.EncodeToString(vector.blindedMessage) if got != want { test.ReportError(t, got, want) } @@ -421,7 +447,7 @@ func verifyTestVector(t *testing.T, vector testVector) { test.ReportError(t, got, want) } - sig, err := state.Finalize(blindSig) + sig, err := client.Finalize(state, blindSig) test.CheckNoErr(t, err, "finalize failed") got = hex.EncodeToString(sig) want = hex.EncodeToString(vector.sig) @@ -429,8 +455,10 @@ func verifyTestVector(t *testing.T, vector testVector) { test.ReportError(t, got, want) } - err = verifier.Verify(inputMsg, sig) - test.CheckNoErr(t, err, "verification failed") + verifier, err := NewVerifier(variant, &key.PublicKey) + test.CheckNoErr(t, err, "new verifier failed") + + test.CheckNoErr(t, verifier.Verify(vector.inputMsg, sig), "verification failed") } func TestVectors(t *testing.T) { @@ -455,46 +483,73 @@ func TestVectors(t *testing.T) { func BenchmarkBRSA(b *testing.B) { message := []byte("hello world") key := loadStrongRSAKey() + server := NewSigner(key) - verifier := NewVerifier(&key.PublicKey, crypto.SHA512) - signer := NewSigner(key) + client, err := NewClient(SHA384PSSRandomized, &key.PublicKey) + if err != nil { + b.Fatal(err) + } + + inputMsg, err := client.Prepare(rand.Reader, message) + if err != nil { + b.Errorf("prepare failed: %v", err) + } + + blindedMsg, state, err := client.Blind(rand.Reader, inputMsg) + if err != nil { + b.Errorf("blind failed: %v", err) + } + + blindedSig, err := server.BlindSign(blindedMsg) + if err != nil { + b.Errorf("blindSign failed: %v", err) + } + + sig, err := client.Finalize(state, blindedSig) + if err != nil { + b.Errorf("finalize failed: %v", err) + } + + err = client.Verify(inputMsg, sig) + if err != nil { + b.Errorf("verification failed: %v", err) + } - var err error - var blindedMsg []byte - var state VerifierState b.Run("Blind", func(b *testing.B) { for n := 0; n < b.N; n++ { - blindedMsg, state, err = verifier.Blind(rand.Reader, message) + _, _, err := client.Blind(rand.Reader, inputMsg) if err != nil { b.Fatal(err) } } }) - var blindedSig []byte b.Run("BlindSign", func(b *testing.B) { for n := 0; n < b.N; n++ { - blindedSig, err = signer.BlindSign(blindedMsg) + _, err := server.BlindSign(blindedMsg) if err != nil { b.Fatal(err) } } }) - var sig []byte b.Run("Finalize", func(b *testing.B) { for n := 0; n < b.N; n++ { - sig, err = state.Finalize(blindedSig) + _, err := client.Finalize(state, blindedSig) if err != nil { b.Fatal(err) } } }) - err = verifier.Verify(message, sig) - if err != nil { - b.Fatal(err) - } + b.Run("Verify", func(b *testing.B) { + for n := 0; n < b.N; n++ { + err := client.Verify(inputMsg, sig) + if err != nil { + b.Fatal(err) + } + } + }) } func Example_blindrsa() { @@ -503,41 +558,53 @@ func Example_blindrsa() { // Server: generate an RSA keypair. sk, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { - fmt.Fprintf(os.Stderr, "failed to generate RSA key: %v", err) + fmt.Printf("failed to generate RSA key: %v", err) return } pk := &sk.PublicKey server := NewSigner(sk) // Client: stores Server's public key. - verifier := NewVerifier(pk, crypto.SHA384) + client, err := NewClient(SHA384PSSRandomized, pk) + if err != nil { + fmt.Printf("failed to invoke a client: %v", err) + return + } // Protocol (online) - // Client blinds a message. + // Client prepares the message to be signed. msg := []byte("alice and bob") - blindedMsg, state, err := verifier.Blind(rand.Reader, msg) + preparedMessage, err := client.Prepare(rand.Reader, msg) if err != nil { - fmt.Fprintf(os.Stderr, "client failed to generate blinded message: %v", err) + fmt.Printf("client failed to prepare the message: %v", err) + return + } + + // Client blinds a message. + blindedMsg, state, err := client.Blind(rand.Reader, preparedMessage) + if err != nil { + fmt.Printf("client failed to generate blinded message: %v", err) return } // Server signs a blinded message, and produces a blinded signature. blindedSignature, err := server.BlindSign(blindedMsg) if err != nil { - fmt.Fprintf(os.Stderr, "server failed to sign: %v", err) + fmt.Printf("server failed to sign: %v", err) return } - // Client builds a signature from the previous state and the blinded signature. - signature, err := state.Finalize(blindedSignature) + // Client build a signature from the previous state and blinded signature. + signature, err := client.Finalize(state, blindedSignature) if err != nil { - fmt.Fprintf(os.Stderr, "client failed to obtain signature: %v", err) + fmt.Printf("client failed to obtain signature: %v", err) return } - // Client verifies the signature is valid. - ok := verifier.Verify(msg, signature) + // Client build a signature from the previous state and blinded signature. + ok := client.Verify(preparedMessage, signature) + fmt.Printf("Valid signature: %v", ok == nil) // Output: Valid signature: true } diff --git a/blindsign/blindrsa/internal/common/common.go b/blindsign/blindrsa/internal/common/common.go index cc2688c41..55e1c8bfa 100644 --- a/blindsign/blindrsa/internal/common/common.go +++ b/blindsign/blindrsa/internal/common/common.go @@ -128,6 +128,9 @@ func verifyPSS(pub *keys.BigPublicKey, hash crypto.Hash, digest []byte, sig []by } var ( + // ErrInvalidVariant is the error used if the variant request does not exist. + ErrInvalidVariant = errors.New("blindsign/blindrsa: invalid variant requested") + // ErrUnexpectedSize is the error used if the size of a parameter does not match its expected value. ErrUnexpectedSize = errors.New("blindsign/blindrsa: unexpected input size")