1 package partiallyblindrsa
2
3 import (
4 "bytes"
5 "crypto"
6 "crypto/rand"
7 "crypto/rsa"
8 "encoding/hex"
9 "encoding/json"
10 "fmt"
11 "io"
12 "math/big"
13 "os"
14 "testing"
15
16 "github.com/cloudflare/circl/blindsign/blindrsa/internal/keys"
17 )
18
19 const (
20 pbrsaTestVectorOutEnvironmentKey = "PBRSA_TEST_VECTORS_OUT"
21 pbrsaTestVectorInEnvironmentKey = "PBRSA_TEST_VECTORS_IN"
22 )
23
24 func loadStrongRSAKey() *rsa.PrivateKey {
25
26 pEnc := "dcd90af1be463632c0d5ea555256a20605af3db667475e190e3af12a34a3324c46a3094062c59fb4b249e0ee6afba8bee14e0276d126c99f4784b23009bf6168ff628ac1486e5ae8e23ce4d362889de4df63109cbd90ef93db5ae64372bfe1c55f832766f21e94ea3322eb2182f10a891546536ba907ad74b8d72469bea396f3"
27 qEnc := "f8ba5c89bd068f57234a3cf54a1c89d5b4cd0194f2633ca7c60b91a795a56fa8c8686c0e37b1c4498b851e3420d08bea29f71d195cfbd3671c6ddc49cf4c1db5b478231ea9d91377ffa98fe95685fca20ba4623212b2f2def4da5b281ed0100b651f6db32112e4017d831c0da668768afa7141d45bbc279f1e0f8735d74395b3"
28 NEnc := "d6930820f71fe517bf3259d14d40209b02a5c0d3d61991c731dd7da39f8d69821552e2318d6c9ad897e603887a476ea3162c1205da9ac96f02edf31df049bd55f142134c17d4382a0e78e275345f165fbe8e49cdca6cf5c726c599dd39e09e75e0f330a33121e73976e4facba9cfa001c28b7c96f8134f9981db6750b43a41710f51da4240fe03106c12acb1e7bb53d75ec7256da3fddd0718b89c365410fce61bc7c99b115fb4c3c318081fa7e1b65a37774e8e50c96e8ce2b2cc6b3b367982366a2bf9924c4bafdb3ff5e722258ab705c76d43e5f1f121b984814e98ea2b2b8725cd9bc905c0bc3d75c2a8db70a7153213c39ae371b2b5dc1dafcb19d6fae9"
29 eEnc := "010001"
30 dEnc := "4e21356983722aa1adedb084a483401c1127b781aac89eab103e1cfc52215494981d18dd8028566d9d499469c25476358de23821c78a6ae43005e26b394e3051b5ca206aa9968d68cae23b5affd9cbb4cb16d64ac7754b3cdba241b72ad6ddfc000facdb0f0dd03abd4efcfee1730748fcc47b7621182ef8af2eeb7c985349f62ce96ab373d2689baeaea0e28ea7d45f2d605451920ca4ea1f0c08b0f1f6711eaa4b7cca66d58a6b916f9985480f90aca97210685ac7b12d2ec3e30a1c7b97b65a18d38a93189258aa346bf2bc572cd7e7359605c20221b8909d599ed9d38164c9c4abf396f897b9993c1e805e574d704649985b600fa0ced8e5427071d7049d"
31
32 p := new(big.Int).SetBytes(mustDecodeHex(pEnc))
33 q := new(big.Int).SetBytes(mustDecodeHex(qEnc))
34 N := new(big.Int).SetBytes(mustDecodeHex(NEnc))
35 e := new(big.Int).SetBytes(mustDecodeHex(eEnc))
36 d := new(big.Int).SetBytes(mustDecodeHex(dEnc))
37
38 primes := make([]*big.Int, 2)
39 primes[0] = p
40 primes[1] = q
41
42 key := &rsa.PrivateKey{
43 PublicKey: rsa.PublicKey{
44 N: N,
45 E: int(e.Int64()),
46 },
47 D: d,
48 Primes: primes,
49 }
50
51 return key
52 }
53
54 func runPBRSA(signer Signer, verifier Verifier, message, metadata []byte, random io.Reader) ([]byte, error) {
55 blindedMsg, state, err := verifier.Blind(random, message, metadata)
56 if err != nil {
57 return nil, err
58 }
59
60 kLen := (signer.sk.Pk.N.BitLen() + 7) / 8
61 if len(blindedMsg) != kLen {
62 return nil, fmt.Errorf("Protocol message (blind message) length mismatch, expected %d, got %d", kLen, len(blindedMsg))
63 }
64
65 blindedSig, err := signer.BlindSign(blindedMsg, metadata)
66 if err != nil {
67 return nil, err
68 }
69
70 if len(blindedSig) != kLen {
71 return nil, fmt.Errorf("Protocol message (blind signature) length mismatch, expected %d, got %d", kLen, len(blindedMsg))
72 }
73
74 sig, err := state.Finalize(blindedSig)
75 if err != nil {
76 return nil, err
77 }
78
79 err = verifier.Verify(message, metadata, sig)
80 if err != nil {
81 return nil, err
82 }
83
84 return sig, nil
85 }
86
87 func mustDecodeHex(h string) []byte {
88 b, err := hex.DecodeString(h)
89 if err != nil {
90 panic(err)
91 }
92 return b
93 }
94
95 func TestPBRSARoundTrip(t *testing.T) {
96 message := []byte("hello world")
97 metadata := []byte("metadata")
98 key := loadStrongRSAKey()
99
100 hash := crypto.SHA384
101 verifier := NewVerifier(&key.PublicKey, hash)
102 signer, err := NewSigner(key, hash)
103 if err != nil {
104 t.Fatal(err)
105 }
106
107 sig, err := runPBRSA(signer, verifier, message, metadata, rand.Reader)
108 if err != nil {
109 t.Fatal(err)
110 }
111 if sig == nil {
112 t.Fatal("nil signature output")
113 }
114 }
115
116 type encodedPBRSATestVector struct {
117 Message string `json:"msg"`
118 Info string `json:"info"`
119 P string `json:"p"`
120 Q string `json:"q"`
121 D string `json:"d"`
122 E string `json:"e"`
123 N string `json:"N"`
124 Eprime string `json:"eprime"`
125 Blind string `json:"blind"`
126 Salt string `json:"salt"`
127 Request string `json:"blinded_msg"`
128 Response string `json:"blinded_sig"`
129 Signature string `json:"sig"`
130 }
131
132 type rawPBRSATestVector struct {
133 privateKey *rsa.PrivateKey
134 message []byte
135 info []byte
136 infoKey []byte
137 blind []byte
138 salt []byte
139 request []byte
140 response []byte
141 signature []byte
142 }
143
144 func mustHex(d []byte) string {
145 return hex.EncodeToString(d)
146 }
147
148 func (tv rawPBRSATestVector) MarshalJSON() ([]byte, error) {
149 pEnc := mustHex(tv.privateKey.Primes[0].Bytes())
150 qEnc := mustHex(tv.privateKey.Primes[1].Bytes())
151 nEnc := mustHex(tv.privateKey.N.Bytes())
152 e := new(big.Int).SetInt64(int64(tv.privateKey.PublicKey.E))
153 eEnc := mustHex(e.Bytes())
154 dEnc := mustHex(tv.privateKey.D.Bytes())
155 ePrimeEnc := mustHex(tv.infoKey)
156 return json.Marshal(encodedPBRSATestVector{
157 P: pEnc,
158 Q: qEnc,
159 D: dEnc,
160 E: eEnc,
161 N: nEnc,
162 Eprime: ePrimeEnc,
163 Message: mustHex(tv.message),
164 Info: mustHex(tv.info),
165 Blind: mustHex(tv.blind),
166 Salt: mustHex(tv.salt),
167 Request: mustHex(tv.request),
168 Response: mustHex(tv.response),
169 Signature: mustHex(tv.signature),
170 })
171 }
172
173 func generatePBRSATestVector(t *testing.T, msg, metadata []byte) rawPBRSATestVector {
174 key := loadStrongRSAKey()
175
176 hash := crypto.SHA384
177 verifier := NewVerifier(&key.PublicKey, hash)
178 signer, err := NewSigner(key, hash)
179 if err != nil {
180 t.Fatal(err)
181 }
182
183 publicKey := keys.NewBigPublicKey(&key.PublicKey)
184 metadataKey := derivePublicKey(hash, publicKey, metadata)
185
186 blindedMsg, state, err := verifier.Blind(rand.Reader, msg, metadata)
187 if err != nil {
188 t.Fatal(err)
189 }
190
191 blindedSig, err := signer.BlindSign(blindedMsg, metadata)
192 if err != nil {
193 t.Fatal(err)
194 }
195
196 sig, err := state.Finalize(blindedSig)
197 if err != nil {
198 t.Fatal(err)
199 }
200
201 err = verifier.Verify(msg, metadata, sig)
202 if err != nil {
203 t.Fatal(err)
204 }
205
206 return rawPBRSATestVector{
207 message: msg,
208 info: metadata,
209 privateKey: key,
210 infoKey: metadataKey.Marshal(),
211 salt: state.CopySalt(),
212 blind: state.CopyBlind(),
213 request: blindedMsg,
214 response: blindedSig,
215 signature: sig,
216 }
217 }
218
219 func verifyTestVector(t *testing.T, vector rawPBRSATestVector) {
220 key := loadStrongRSAKey()
221
222 key.PublicKey.N = vector.privateKey.N
223 key.PublicKey.E = vector.privateKey.E
224 key.D = vector.privateKey.D
225 key.Primes[0] = vector.privateKey.Primes[0]
226 key.Primes[1] = vector.privateKey.Primes[1]
227 key.Precomputed.Dp = nil
228
229 hash := crypto.SHA384
230 signer, err := NewSigner(key, hash)
231 if err != nil {
232 t.Fatal(err)
233 }
234 verifier := NewVerifier(&key.PublicKey, crypto.SHA384)
235
236 r := new(big.Int).SetBytes(vector.blind)
237 rInv := new(big.Int).ModInverse(r, key.N)
238 if r == nil {
239 t.Fatal("Failed to compute blind inverse")
240 }
241
242 blindedMsg, state, err := verifier.FixedBlind(vector.message, vector.info, vector.salt, r.Bytes(), rInv.Bytes())
243 if err != nil {
244 t.Fatal(err)
245 }
246
247 blindSig, err := signer.BlindSign(blindedMsg, vector.info)
248 if err != nil {
249 t.Fatal(err)
250 }
251
252 sig, err := state.Finalize(blindSig)
253 if err != nil {
254 t.Fatal(err)
255 }
256
257 if !bytes.Equal(sig, vector.signature) {
258 t.Errorf("Signature mismatch: expected %x, got %x", sig, vector.signature)
259 }
260 }
261
262 func TestPBRSAGenerateTestVector(t *testing.T) {
263 testCases := []struct {
264 msg []byte
265 metadata []byte
266 }{
267 {
268 []byte("hello world"),
269 []byte("metadata"),
270 },
271 {
272 []byte("hello world"),
273 []byte(""),
274 },
275 {
276 []byte(""),
277 []byte("metadata"),
278 },
279 {
280 []byte(""),
281 []byte(""),
282 },
283 }
284
285 vectors := []rawPBRSATestVector{}
286 for _, testCase := range testCases {
287 vectors = append(vectors, generatePBRSATestVector(t, testCase.msg, testCase.metadata))
288 }
289
290 for _, vector := range vectors {
291 verifyTestVector(t, vector)
292 }
293
294
295 encoded, err := json.Marshal(vectors)
296 if err != nil {
297 t.Fatalf("Error producing test vectors: %v", err)
298 }
299
300 var outputFile string
301 if outputFile = os.Getenv(pbrsaTestVectorOutEnvironmentKey); len(outputFile) > 0 {
302 err := os.WriteFile(outputFile, encoded, 0o600)
303 if err != nil {
304 t.Fatalf("Error writing test vectors: %v", err)
305 }
306 }
307 }
308
309 func BenchmarkPBRSA(b *testing.B) {
310 message := []byte("hello world")
311 metadata := []byte("good doggo")
312 key := loadStrongRSAKey()
313
314 hash := crypto.SHA384
315 verifier := NewVerifier(&key.PublicKey, hash)
316 signer, err := NewSigner(key, hash)
317 if err != nil {
318 b.Fatal(err)
319 }
320
321 var blindedMsg []byte
322 var state VerifierState
323 b.Run("Blind", func(b *testing.B) {
324 for n := 0; n < b.N; n++ {
325 blindedMsg, state, err = verifier.Blind(rand.Reader, message, metadata)
326 if err != nil {
327 b.Fatal(err)
328 }
329 }
330 })
331
332 var blindedSig []byte
333 b.Run("BlindSign", func(b *testing.B) {
334 for n := 0; n < b.N; n++ {
335 blindedSig, err = signer.BlindSign(blindedMsg, metadata)
336 if err != nil {
337 b.Fatal(err)
338 }
339 }
340 })
341
342 var sig []byte
343 b.Run("Finalize", func(b *testing.B) {
344 for n := 0; n < b.N; n++ {
345 sig, err = state.Finalize(blindedSig)
346 if err != nil {
347 b.Fatal(err)
348 }
349 }
350 })
351
352 err = verifier.Verify(message, metadata, sig)
353 if err != nil {
354 b.Fatal(err)
355 }
356 }
357
View as plain text