Skip to content

Commit ceb2d90

Browse files
committed
Updating blindrsa to be compliant with RFC9474.
1 parent 44133f7 commit ceb2d90

File tree

4 files changed

+220
-80
lines changed

4 files changed

+220
-80
lines changed

blindsign/blindrsa/brsa.go

+35-16
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,28 @@
1-
package blindrsa
2-
3-
// This package implements the blind RSA protocol based on the CFRG specification:
4-
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-rsa-blind-signatures
1+
// Package blindrsa implements the RSA Blind Signature Protocol.
2+
//
3+
// The RSA Blind Signature protocol, also called RSABSSA
4+
// (RSA Blind Signature with Appendix) is a two-party protocol
5+
// between a Client and Server where they interact to compute
6+
//
7+
// sig = Sign(sk, input_msg),
8+
//
9+
// where `input_msg = Prepare(msg)` is a prepared version of a private
10+
// message `msg` provided by the Client, and `sk` is the private signing
11+
// key provided by the server.
12+
//
13+
// # Supported Variants
514
//
6-
// Blind RSA is an example of a blind signature protocol is a two-party protocol
7-
// for computing a digital signature. One party (the server) holds the signing
8-
// key, and the other (the client) holds the message input. Blindness
9-
// ensures that the server does not learn anything about the client's
10-
// input during the BlindSign step.
15+
// This package is compliant with the [RFC-9474] document
16+
// and supports the following variants:
17+
// - [NewVerifier] implements RSABSSA-SHA384-PSS-Deterministic
18+
// - [NewDeterministicVerifier] implements RSABSSA-SHA384-PSSZERO-Deterministic
19+
//
20+
// while these variants are not supported yet:
21+
// - RSABSSA-SHA384-PSS-Randomized
22+
// - RSABSSA-SHA384-PSSZERO-Randomized
23+
//
24+
// [RFC-9474]: https://www.rfc-editor.org/info/rfc9474
25+
package blindrsa
1126

1227
import (
1328
"crypto"
@@ -48,7 +63,7 @@ type deterministicBRSAVerifier struct {
4863
}
4964

5065
// Verifier is a type that implements the client side of the blind RSA
51-
// protocol, described in https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-rsa-blind-signatures
66+
// protocol, described in https://www.rfc-editor.org/rfc/rfc9474.html#name-rsabssa-variants
5267
type Verifier interface {
5368
// Blind initializes the blind RSA protocol using an input message and source of randomness. The
5469
// signature is deterministic. This function fails if randomness was not provided.
@@ -66,7 +81,7 @@ type Verifier interface {
6681

6782
// NewDeterministicVerifier creates a new DeterministicBRSAVerifier using the corresponding Signer parameters.
6883
// This corresponds to the RSABSSA-SHA384-PSSZERO-Deterministic variant. See the specification for more details:
69-
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-rsa-blind-signatures#name-rsabssa-variants
84+
// https://www.rfc-editor.org/rfc/rfc9474.html#name-rsabssa-variants
7085
func NewDeterministicVerifier(pk *rsa.PublicKey, hash crypto.Hash) Verifier {
7186
h := common.ConvertHashFunction(hash)
7287
return deterministicBRSAVerifier{
@@ -83,7 +98,7 @@ func (v deterministicBRSAVerifier) Hash() hash.Hash {
8398

8499
// NewVerifier creates a new BRSAVerifier using the corresponding Signer parameters.
85100
// This corresponds to the RSABSSA-SHA384-PSS-Deterministic variant. See the specification for more details:
86-
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-rsa-blind-signatures#name-rsabssa-variants
101+
// https://www.rfc-editor.org/rfc/rfc9474.html#name-rsabssa-variants
87102
func NewVerifier(pk *rsa.PublicKey, hash crypto.Hash) Verifier {
88103
h := common.ConvertHashFunction(hash)
89104
return randomBRSAVerifier{
@@ -98,6 +113,10 @@ func (v randomBRSAVerifier) Hash() hash.Hash {
98113
return v.hash
99114
}
100115

116+
func prepareMsg(message, prefix []byte) []byte {
117+
return append(append([]byte{}, prefix...), message...)
118+
}
119+
101120
func fixedBlind(message, salt []byte, r, rInv *big.Int, pk *rsa.PublicKey, hash hash.Hash) ([]byte, VerifierState, error) {
102121
encodedMsg, err := common.EncodeMessageEMSAPSS(message, pk.N, hash, salt)
103122
if err != nil {
@@ -129,7 +148,7 @@ func fixedBlind(message, salt []byte, r, rInv *big.Int, pk *rsa.PublicKey, hash
129148
// signature is deterministic. This function fails if randomness was not provided.
130149
//
131150
// See the specification for more details:
132-
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-rsa-blind-signatures-02#section-5.1.1
151+
// https://www.rfc-editor.org/rfc/rfc9474.html#name-blind
133152
func (v deterministicBRSAVerifier) Blind(random io.Reader, message []byte) ([]byte, VerifierState, error) {
134153
if random == nil {
135154
return nil, VerifierState{}, common.ErrInvalidRandomness
@@ -171,7 +190,7 @@ func (v deterministicBRSAVerifier) Verify(message, signature []byte) error {
171190
// hash function. This function fails if randomness was not provided.
172191
//
173192
// See the specification for more details:
174-
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-rsa-blind-signatures-02#section-5.1.1
193+
// https://www.rfc-editor.org/rfc/rfc9474.html#name-blind
175194
func (v randomBRSAVerifier) Blind(random io.Reader, message []byte) ([]byte, VerifierState, error) {
176195
if random == nil {
177196
return nil, VerifierState{}, common.ErrInvalidRandomness
@@ -237,7 +256,7 @@ type VerifierState struct {
237256
// Finalize computes and outputs the final signature, if it's valid. Otherwise, it returns an error.
238257
//
239258
// See the specification for more details:
240-
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-rsa-blind-signatures-02#section-5.1.3
259+
// https://www.rfc-editor.org/rfc/rfc9474.html#name-finalize
241260
func (state VerifierState) Finalize(data []byte) ([]byte, error) {
242261
kLen := (state.pk.N.BitLen() + 7) / 8
243262
if len(data) != kLen {
@@ -291,7 +310,7 @@ func NewSigner(sk *rsa.PrivateKey) Signer {
291310
// message input, if it's of valid length, and returns an error should the function fail.
292311
//
293312
// See the specification for more details:
294-
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-rsa-blind-signatures-02#section-5.1.2
313+
// https://www.rfc-editor.org/rfc/rfc9474.html#name-blindsign
295314
func (signer Signer) BlindSign(data []byte) ([]byte, error) {
296315
kLen := (signer.sk.N.BitLen() + 7) / 8
297316
if len(data) != kLen {

blindsign/blindrsa/brsa_test.go

+108-32
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ import (
1313
"io"
1414
"math/big"
1515
"os"
16+
"strings"
1617
"testing"
18+
19+
"github.com/cloudflare/circl/internal/test"
1720
)
1821

1922
// 2048-bit RSA private key
@@ -254,31 +257,39 @@ func TestFixedRandomSignVerify(t *testing.T) {
254257
}
255258

256259
type rawTestVector struct {
260+
Name string `json:"name"`
257261
P string `json:"p"`
258262
Q string `json:"q"`
259263
N string `json:"n"`
260264
E string `json:"e"`
261265
D string `json:"d"`
262266
Msg string `json:"msg"`
267+
MsgPrefix string `json:"msg_prefix"`
268+
InputMsg string `json:"input_msg"`
263269
Salt string `json:"salt"`
270+
SaltLen string `json:"sLen"`
271+
IsRandomized string `json:"is_randomized"`
264272
Inv string `json:"inv"`
265-
EncodedMsg string `json:"encoded_msg"`
266-
BlindedMessage string `json:"blinded_message"`
273+
BlindedMessage string `json:"blinded_msg"`
267274
BlindSig string `json:"blind_sig"`
268275
Sig string `json:"sig"`
269276
}
270277

271278
type testVector struct {
272279
t *testing.T
280+
name string
273281
p *big.Int
274282
q *big.Int
275283
n *big.Int
276284
e int
277285
d *big.Int
278286
msg []byte
287+
msgPrefix []byte
288+
inputMsg []byte
279289
salt []byte
290+
saltLen int
291+
isRandomized bool
280292
blindInverse *big.Int
281-
encodedMessage []byte
282293
blindedMessage []byte
283294
blindSig []byte
284295
sig []byte
@@ -290,17 +301,14 @@ type testVectorList struct {
290301
}
291302

292303
func mustUnhexBigInt(number string) *big.Int {
293-
data, err := hex.DecodeString(number)
294-
if err != nil {
295-
panic(err)
296-
}
297-
304+
data := mustUnhex(number)
298305
value := new(big.Int)
299306
value.SetBytes(data)
300307
return value
301308
}
302309

303310
func mustUnhex(value string) []byte {
311+
value = strings.TrimPrefix(value, "0x")
304312
data, err := hex.DecodeString(value)
305313
if err != nil {
306314
panic(err)
@@ -322,14 +330,18 @@ func (tv *testVector) UnmarshalJSON(data []byte) error {
322330
return err
323331
}
324332

333+
tv.name = raw.Name
325334
tv.p = mustUnhexBigInt(raw.P)
326335
tv.q = mustUnhexBigInt(raw.Q)
327336
tv.n = mustUnhexBigInt(raw.N)
328337
tv.e = mustUnhexInt(raw.E)
329338
tv.d = mustUnhexBigInt(raw.D)
330339
tv.msg = mustUnhex(raw.Msg)
340+
tv.msgPrefix = mustUnhex(raw.MsgPrefix)
341+
tv.inputMsg = mustUnhex(raw.InputMsg)
331342
tv.salt = mustUnhex(raw.Salt)
332-
tv.encodedMessage = mustUnhex(raw.EncodedMsg)
343+
tv.saltLen = mustUnhexInt(raw.SaltLen)
344+
tv.isRandomized = mustUnhexInt(raw.IsRandomized) != 0
333345
tv.blindedMessage = mustUnhex(raw.BlindedMessage)
334346
tv.blindInverse = mustUnhexBigInt(raw.Inv)
335347
tv.blindSig = mustUnhex(raw.BlindSig)
@@ -356,16 +368,11 @@ func (tvl *testVectorList) UnmarshalJSON(data []byte) error {
356368
}
357369

358370
func verifyTestVector(t *testing.T, vector testVector) {
359-
key, err := loadPrivateKey()
360-
if err != nil {
361-
t.Fatal(err)
362-
}
363-
371+
key := new(rsa.PrivateKey)
364372
key.PublicKey.N = vector.n
365373
key.PublicKey.E = vector.e
366374
key.D = vector.d
367-
key.Primes[0] = vector.p
368-
key.Primes[1] = vector.q
375+
key.Primes = []*big.Int{vector.p, vector.q}
369376
key.Precomputed.Dp = nil // Remove precomputed CRT values
370377

371378
// Recompute the original blind
@@ -376,34 +383,56 @@ func verifyTestVector(t *testing.T, vector testVector) {
376383
}
377384

378385
signer := NewSigner(key)
379-
verifier := NewVerifier(&key.PublicKey, crypto.SHA384)
380386

381-
blindedMsg, state, err := fixedBlind(vector.msg, vector.salt, r, rInv, &key.PublicKey, verifier.Hash())
382-
if err != nil {
383-
t.Fatal(err)
387+
var verifier Verifier
388+
switch vector.name {
389+
case "RSABSSA-SHA384-PSS-Deterministic":
390+
verifier = NewVerifier(&key.PublicKey, crypto.SHA384)
391+
case "RSABSSA-SHA384-PSSZERO-Deterministic":
392+
verifier = NewDeterministicVerifier(&key.PublicKey, crypto.SHA384)
393+
case "RSABSSA-SHA384-PSS-Randomized", "RSABSSA-SHA384-PSSZERO-Randomized":
394+
t.Skipf("variant %v not supported yet", vector.name)
395+
default:
396+
t.Fatal("variant not supported")
384397
}
385398

386-
blindSig, err := signer.BlindSign(blindedMsg)
387-
if err != nil {
388-
t.Fatal(err)
399+
inputMsg := prepareMsg(vector.msg, vector.msgPrefix)
400+
got := hex.EncodeToString(inputMsg)
401+
want := hex.EncodeToString(vector.inputMsg)
402+
if got != want {
403+
test.ReportError(t, got, want)
389404
}
390405

391-
sig, err := state.Finalize(blindSig)
392-
if err != nil {
393-
t.Fatal(err)
406+
blindedMsg, state, err := fixedBlind(inputMsg, vector.salt, r, rInv, &key.PublicKey, verifier.Hash())
407+
test.CheckNoErr(t, err, "fixedBlind failed")
408+
got = hex.EncodeToString(blindedMsg)
409+
want = hex.EncodeToString(vector.blindedMessage)
410+
if got != want {
411+
test.ReportError(t, got, want)
394412
}
395413

396-
if !bytes.Equal(state.encodedMsg, vector.encodedMessage) {
397-
t.Errorf("Encoded message mismatch: expected %x, got %x", state.encodedMsg, vector.encodedMessage)
414+
blindSig, err := signer.BlindSign(blindedMsg)
415+
test.CheckNoErr(t, err, "blindSign failed")
416+
got = hex.EncodeToString(blindSig)
417+
want = hex.EncodeToString(vector.blindSig)
418+
if got != want {
419+
test.ReportError(t, got, want)
398420
}
399421

400-
if !bytes.Equal(sig, vector.sig) {
401-
t.Errorf("Signature mismatch: expected %x, got %x", sig, vector.sig)
422+
sig, err := state.Finalize(blindSig)
423+
test.CheckNoErr(t, err, "finalize failed")
424+
got = hex.EncodeToString(sig)
425+
want = hex.EncodeToString(vector.sig)
426+
if got != want {
427+
test.ReportError(t, got, want)
402428
}
429+
430+
err = verifier.Verify(inputMsg, sig)
431+
test.CheckNoErr(t, err, "verification failed")
403432
}
404433

405434
func TestVectors(t *testing.T) {
406-
data, err := os.ReadFile("testdata/test_vectors.json")
435+
data, err := os.ReadFile("testdata/test_vectors_rfc9474.json")
407436
if err != nil {
408437
t.Fatal("Failed reading test vectors:", err)
409438
}
@@ -415,7 +444,9 @@ func TestVectors(t *testing.T) {
415444
}
416445

417446
for _, vector := range tvl.vectors {
418-
verifyTestVector(t, vector)
447+
t.Run(vector.name, func(tt *testing.T) {
448+
verifyTestVector(tt, vector)
449+
})
419450
}
420451
}
421452

@@ -463,3 +494,48 @@ func BenchmarkBRSA(b *testing.B) {
463494
b.Fatal(err)
464495
}
465496
}
497+
498+
func Example_blindrsa() {
499+
// Setup (offline)
500+
501+
// Server: generate an RSA keypair.
502+
sk, err := rsa.GenerateKey(rand.Reader, 2048)
503+
if err != nil {
504+
fmt.Fprintf(os.Stderr, "failed to generate RSA key: %v", err)
505+
return
506+
}
507+
pk := &sk.PublicKey
508+
server := NewSigner(sk)
509+
510+
// Client: stores Server's public key.
511+
verifier := NewVerifier(pk, crypto.SHA384)
512+
513+
// Protocol (online)
514+
515+
// Client blinds a message.
516+
msg := []byte("alice and bob")
517+
blindedMsg, state, err := verifier.Blind(rand.Reader, msg)
518+
if err != nil {
519+
fmt.Fprintf(os.Stderr, "client failed to generate blinded message: %v", err)
520+
return
521+
}
522+
523+
// Server signs a blinded message, and produces a blinded signature.
524+
blindedSignature, err := server.BlindSign(blindedMsg)
525+
if err != nil {
526+
fmt.Fprintf(os.Stderr, "server failed to sign: %v", err)
527+
return
528+
}
529+
530+
// Client builds a signature from the previous state and the blinded signature.
531+
signature, err := state.Finalize(blindedSignature)
532+
if err != nil {
533+
fmt.Fprintf(os.Stderr, "client failed to obtain signature: %v", err)
534+
return
535+
}
536+
537+
// Client verifies the signature is valid.
538+
ok := verifier.Verify(msg, signature)
539+
fmt.Printf("Valid signature: %v", ok == nil)
540+
// Output: Valid signature: true
541+
}

0 commit comments

Comments
 (0)