@@ -33,7 +33,11 @@ const (
3333 delim = ":"
3434 minmsgsize = 32 // min msg size in bytes; >= pipkey.c.prefixLen
3535 tokensize = 32 // token size in bytes
36+ bidsize = 64 // blind id size in bytes; hmac(msg, pubkey)
37+ blindsize = 256 // blinded message size in bytes
3638 hashfn = crypto .SHA384 // 48 byte hash fn for RSA-PSS
39+
40+ pipkeyOpaqueCtx = "pipkey-message-opaque" // context for opaque messages
3741)
3842
3943var (
4246)
4347
4448type PipKeyProvider interface {
49+ // Bid uniquely identifies a blinded PipKeyProvider.
50+ // PipKeyProviders created from same blinded PipKeyState have the same identity.
51+ // If this PipKeyProvider is not yet blinded, it returns nil.
52+ Bid () * Gostr
4553 // Blind generates id:blindMsg:blindingFactor:salt:msg
4654 // id is a 64 byte hmac tying blindMsg to the public key
4755 // blindMsg is a 256 byte blinded message
@@ -53,37 +61,48 @@ type PipKeyProvider interface {
5361 Finalize (blingSig * Gostr ) (* PipKey , error )
5462}
5563
64+ // nb: PipToken inherits fields from Gostr but not its methods.
65+
66+ // PipToken is a 32 byte random token for bespoke auth.
5667type PipToken Gostr
5768
69+ type PipMsg string
70+
71+ // Opaque returns a 32 byte hex derived from the PipMsg.
72+ func (p PipMsg ) Opaque () * Gostr {
73+ oq := hmac256 ([]byte (pipkeyOpaqueCtx ), []byte (p ))
74+ return StrOf (byte2hex (oq ))
75+ }
76+
5877type PipKey struct {
5978 // hex encoded 32 byte msg (random)
60- Msg string
79+ Msg PipMsg
6180 // hex encoded 256 byte sig (unblinded signature)
6281 Sig string
6382 // hex encoded 32 byte sha256(sig) (msg signature hash)
6483 SigHash string
6584}
6685
6786type PipKeyState struct {
68- // hex encoded 64 byte id, tied to Msg and pubjwk .
69- Id string
87+ // hex encoded 64 byte id that identifies BlindMsg .
88+ Bid string
7089 // hex encoded 256 byte blind(Msg)
7190 BlindMsg string
7291 // hex encoded blinding factor (up to 256 bytes)
7392 R string
7493 // hex encoded 48 byte salt (random)
7594 Salt string
7695 // hex encoded 32 byte (client) msg (usually, random)
77- Msg string
96+ Msg PipMsg
7897}
7998
8099func newPipKeyState (id , blindMsg , r , salt , msg string ) * PipKeyState {
81100 return & PipKeyState {
82- Id : id ,
101+ Bid : id ,
83102 BlindMsg : blindMsg ,
84103 R : r ,
85104 Salt : salt ,
86- Msg : msg ,
105+ Msg : PipMsg ( msg ) ,
87106 }
88107}
89108
@@ -101,15 +120,15 @@ func NewPipKeyStateFrom(v *Gostr) (*PipKeyState, error) {
101120 if len (parts ) == 1 {
102121 // if there's only one part, it's the message
103122 return & PipKeyState {
104- Msg : parts [0 ],
123+ Msg : PipMsg ( parts [0 ]) ,
105124 }, nil
106125 } else if len (parts ) == 5 {
107126 return & PipKeyState {
108- Id : parts [0 ],
127+ Bid : parts [0 ],
109128 BlindMsg : parts [1 ],
110129 R : parts [2 ],
111130 Salt : parts [3 ],
112- Msg : parts [4 ],
131+ Msg : PipMsg ( parts [4 ]) ,
113132 }, nil
114133
115134 }
@@ -131,16 +150,16 @@ func (p *PipKeyState) v() string {
131150 return ""
132151 }
133152
134- if len (p .BlindMsg ) != 256 {
135- return p .Msg // may be empty, but that's ok
153+ if len (p .BlindMsg ) != blindsize {
154+ return string ( p .Msg ) // may be empty, but that's ok
136155 }
137156
138157 return strings .Join ([]string {
139- p .Id ,
158+ p .Bid ,
140159 p .BlindMsg ,
141160 p .R ,
142161 p .Salt ,
143- p .Msg ,
162+ string ( p .Msg ) ,
144163 },
145164 delim ,
146165 )
@@ -180,6 +199,8 @@ type pkgen struct {
180199 blindMsg []byte // 256 bytes blindMsg derived from msg, r, salt
181200}
182201
202+ var _ PipKeyProvider = (* pkgen )(nil )
203+
183204// NewPipKeyProvider creates a new PipKeyProvider instance.
184205// pubjwk: JWK string of the public key of the RSA-PSS signer (for which modulus must be 2048 bits, and hash-fn must be SHA384).
185206// msgOrExistingState: if empty, a new PipKeyProvider is created with a random message, if not empty, it's the state of an existing PipKey.
@@ -282,7 +303,25 @@ func newPipKey(bjwk []byte, msgOrExistingState string, msgOnly bool) (PipKeyProv
282303 return k , nil
283304}
284305
285- // Implements PipKey.
306+ // Bid implements PipKeyProvider.
307+ func (k * pkgen ) Bid () * Gostr {
308+ k .mu .Lock ()
309+ defer k .mu .Unlock ()
310+
311+ if k .id == nil {
312+ log .E ("pipkey: who: not blinded" )
313+ return nil
314+ }
315+
316+ if len (k .id ) != 64 {
317+ log .E ("pipkey: who: invalid id size %d" , len (k .id ))
318+ return nil
319+ }
320+
321+ return StrOf (byte2hex (k .id ))
322+ }
323+
324+ // Blind implements PipKeyProvider.
286325func (k * pkgen ) Blind () (* PipKeyState , error ) {
287326 k .mu .Lock ()
288327 defer k .mu .Unlock ()
@@ -310,7 +349,7 @@ func (k *pkgen) Blind() (*PipKeyState, error) {
310349 k .id = hmac256 (k .blindMsg , k .pubkey .N .Bytes ()) // must match with server-side impl
311350 k .state = & verifierState
312351
313- if len (k .id ) != 64 || len (k .blindMsg ) != 256 || len (r .Bytes ()) > 256 || len (salt ) != 48 || len (k .msg ) != 32 {
352+ if len (k .id ) != bidsize || len (k .blindMsg ) != blindsize || len (r .Bytes ()) > 256 || len (salt ) != 48 || len (k .msg ) != minmsgsize {
314353 log .E ("pipkey: blind: invalid state; id %d, blindMsg %d, r %d, salt %d, msg %d" ,
315354 len (k .id ), len (k .blindMsg ), len (r .Bytes ()), len (salt ), len (k .msg ))
316355 return nil , brsa .ErrUnexpectedSize
@@ -326,7 +365,7 @@ func (k *pkgen) Blind() (*PipKeyState, error) {
326365 ), nil
327366}
328367
329- // Implements PipKey .
368+ // Finalize implements PipKeyProvider .
330369func (k * pkgen ) Finalize (blindSig * Gostr ) (* PipKey , error ) {
331370 return k .finalize (blindSig .V ())
332371}
@@ -355,7 +394,7 @@ func (k *pkgen) finalize(blindSig string) (*PipKey, error) {
355394 hashedsigbytes := sha256sum (sigbytes )
356395
357396 return & PipKey {
358- Msg : byte2hex (k .msg ),
397+ Msg : PipMsg ( byte2hex (k .msg ) ),
359398 Sig : byte2hex (sigbytes ),
360399 SigHash : byte2hex (hashedsigbytes ),
361400 }, nil
0 commit comments