Skip to content

Commit 0bfd7e5

Browse files
authored
Merge pull request #294 from dajiaji/add-cose-encode
Add encode() to COSE.
2 parents 1875d84 + adf2418 commit 0bfd7e5

5 files changed

Lines changed: 1020 additions & 115 deletions

File tree

README.md

Lines changed: 71 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ And then, you can use it as follows:
3232
>>> from cwt import COSE, COSEKey
3333
>>> ctx = COSE.new()
3434
>>> mac_key = COSEKey.generate_symmetric_key(alg="HS256", kid="01")
35-
>>> encoded = ctx.encode_and_mac(b"Hello world!", mac_key, unprotected={"alg": "HS256"})
35+
>>> encoded = ctx.encode(b"Hello world!", mac_key, protected={"alg": "HS256"}, unprotected={"kid": "01"})
3636
>>> encoded.hex()
3737
'd18443a10105a1044230314c48656c6c6f20776f726c64215820'...
3838
>>> ctx.decode(encoded, mac_key)
@@ -120,15 +120,22 @@ from cwt import COSE, COSEKey
120120
mac_key = COSEKey.generate_symmetric_key(alg="HS256", kid="01")
121121

122122
# The sender side:
123-
sender = COSE.new(alg_auto_inclusion=True, kid_auto_inclusion=True)
124-
encoded = sender.encode_and_mac(b"Hello world!", mac_key)
123+
sender = COSE.new()
124+
encoded = sender.encode(
125+
b"Hello world!",
126+
mac_key,
127+
protected={"alg": "HS256"},
128+
unprotected={"kid": "01"},
129+
)
125130

126131
# The recipient side:
127132
recipient = COSE.new()
128133
assert b"Hello world!" == recipient.decode(encoded, mac_key)
129134
```
130135

131-
Following two samples are other ways of writing the above example:
136+
Following two samples are other ways of writing the above example.
137+
138+
CBOR object can be used for `protected` and `unprotected` headers as follows:
132139

133140
```py
134141
from cwt import COSE, COSEKey
@@ -137,37 +144,40 @@ mac_key = COSEKey.generate_symmetric_key(alg="HS256", kid="01")
137144

138145
# The sender side:
139146
sender = COSE.new()
140-
encoded = sender.encode_and_mac(
147+
encoded = sender.encode(
141148
b"Hello world!",
142149
mac_key,
143-
protected={"alg": "HS256"},
144-
unprotected={"kid": "01"},
150+
protected={1: 5},
151+
unprotected={4: b"01"},
145152
)
146153

147154
# The recipient side:
148155
recipient = COSE.new()
149156
assert b"Hello world!" == recipient.decode(encoded, mac_key)
150157
```
151158

159+
`alg_auto_inclusion` and `kid_auto_inclusion` can be used to omit to specify `alg` and `kid` headers respectively as follows:
160+
152161
```py
153162
from cwt import COSE, COSEKey
154163

155164
mac_key = COSEKey.generate_symmetric_key(alg="HS256", kid="01")
156165

157166
# The sender side:
158-
sender = COSE.new()
159-
encoded = ctx.encode_and_mac(
167+
sender = COSE.new(alg_auto_inclusion=True, kid_auto_inclusion=True)
168+
encoded = sender.encode(
160169
b"Hello world!",
161170
mac_key,
162-
protected={1: 5},
163-
unprotected={4: b"01"},
171+
# protected={"alg": "HS256"},
172+
# unprotected={"kid": "01"},
164173
)
165174

166175
# The recipient side:
167176
recipient = COSE.new()
168177
assert b"Hello world!" == recipient.decode(encoded, mac_key)
169178
```
170179

180+
171181
### COSE MAC
172182

173183
#### Direct Key Distribution for MAC
@@ -183,10 +193,9 @@ mac_key = COSEKey.generate_symmetric_key(alg="HS512", kid="01")
183193

184194
# The sender side:
185195
r = Recipient.new(unprotected={"alg": "direct", "kid": mac_key.kid})
186-
# r = Recipient.new(unprotected={1: -6, 4: mac_key.kid}) # is also acceptable.
187196

188197
sender = COSE.new()
189-
encoded = sender.encode_and_mac(b"Hello world!", mac_key, recipients=[r])
198+
encoded = sender.encode(b"Hello world!", mac_key, protected={"alg": "HS512"}, recipients=[r])
190199

191200
# The recipient side:
192201
recipient = COSE.new()
@@ -212,7 +221,7 @@ r = Recipient.new(
212221
context={"alg": "HS256"},
213222
)
214223
sender = COSE.new(alg_auto_inclusion=True)
215-
encoded = sender.encode_and_mac(
224+
encoded = sender.encode(
216225
b"Hello world!",
217226
shared_key,
218227
recipients=[r],
@@ -242,7 +251,7 @@ enc_key = COSEKey.from_jwk(
242251
)
243252
r = Recipient.new(unprotected={"alg": "A128KW"}, sender_key=enc_key)
244253
sender = COSE.new(alg_auto_inclusion=True)
245-
encoded = sender.encode_and_mac(b"Hello world!", mac_key, recipients=[r])
254+
encoded = sender.encode(b"Hello world!", mac_key, recipients=[r])
246255

247256
# The recipient side:
248257
recipient = COSE.new()
@@ -254,7 +263,7 @@ assert b"Hello world!" == recipient.decode(encoded, enc_key)
254263
The direct key agreement methods can be used to create a shared secret. A KDF (Key Distribution Function) is then
255264
applied to the shared secret to derive a key to be used to protect the data.
256265
The follwing example shows a simple way to make a COSE Encrypt message, verify and decode it with the direct key
257-
agreement methods (``ECDH-ES+HKDF-256`` with various curves).
266+
agreement methods.
258267

259268
```py
260269
from cwt import COSE, COSEKey, Recipient
@@ -275,9 +284,10 @@ r = Recipient.new(
275284
recipient_key=pub_key,
276285
context={"alg": "HS256"},
277286
)
278-
sender = COSE.new(alg_auto_inclusion=True)
279-
encoded = sender.encode_and_mac(
287+
sender = COSE.new()
288+
encoded = sender.encode(
280289
b"Hello world!",
290+
protected={"alg": "HS256"},
281291
recipients=[r],
282292
)
283293

@@ -325,7 +335,7 @@ r = Recipient.new(
325335
context={"alg": "HS256"},
326336
)
327337
sender = COSE.new(alg_auto_inclusion=True)
328-
encoded = sender.encode_and_mac(
338+
encoded = sender.encode(
329339
b"Hello world!",
330340
mac_key,
331341
recipients=[r],
@@ -362,7 +372,29 @@ enc_key = COSEKey.generate_symmetric_key(alg="ChaCha20/Poly1305", kid="01")
362372
# The sender side:
363373
nonce = enc_key.generate_nonce()
364374
sender = COSE.new(alg_auto_inclusion=True, kid_auto_inclusion=True)
365-
encoded = sender.encode_and_encrypt(b"Hello world!", enc_key, unprotected={"iv": nonce})
375+
encoded = sender.encode(b"Hello world!", enc_key, unprotected={5: nonce})
376+
377+
# The recipient side:
378+
recipient = COSE.new()
379+
assert b"Hello world!" == recipient.decode(encoded, enc_key)
380+
```
381+
382+
The following sample is another way of writing the above:
383+
384+
```py
385+
from cwt import COSE, COSEKey
386+
387+
enc_key = COSEKey.generate_symmetric_key(alg="ChaCha20/Poly1305", kid="01")
388+
389+
# The sender side:
390+
nonce = enc_key.generate_nonce()
391+
sender = COSE.new()
392+
encoded = sender.encode(
393+
b"Hello world!",
394+
enc_key,
395+
protected={"alg": "ChaCha20/Poly1305"},
396+
unprotected={"kid": "01", "iv": nonce},
397+
)
366398

367399
# The recipient side:
368400
recipient = COSE.new()
@@ -390,7 +422,7 @@ rpk = COSEKey.from_jwk(
390422
)
391423

392424
sender = COSE.new()
393-
encoded = sender.encode_and_encrypt(
425+
encoded = sender.encode(
394426
b"This is the content.",
395427
rpk,
396428
protected={
@@ -406,8 +438,6 @@ encoded = sender.encode_and_encrypt(
406438
},
407439
)
408440

409-
# print(encoded.hex())
410-
411441
# The recipient side:
412442
rsk = COSEKey.from_jwk(
413443
{
@@ -434,18 +464,16 @@ key distribution method.
434464
```py
435465
from cwt import COSE, COSEKey, Recipient
436466

437-
enc_key = COSEKey.generate_symmetric_key(alg="ChaCha20/Poly1305", kid="01")
438-
439-
# The sender side:
440467
nonce = enc_key.generate_nonce()
441-
r = Recipient.new(unprotected={"alg": "direct", "kid": enc_key.kid})
442-
# r = Recipient.new(unprotected={1: -6, 4: enc_key.kid}) # is also acceptable.
468+
r = Recipient.new(unprotected={"alg": "direct"})
469+
# r = Recipient.new(unprotected={1: -6}) # is also acceptable.
443470

444471
sender = COSE.new()
445-
encoded = sender.encode_and_encrypt(
472+
encoded = sender.encode(
446473
b"Hello world!",
447474
enc_key,
448-
unprotected={5: nonce},
475+
protected={"alg": "ChaCha20/Poly1305"},
476+
unprotected={"kid": enc_key.kid, "iv": nonce},
449477
recipients=[r],
450478
)
451479

@@ -472,7 +500,7 @@ r = Recipient.new(
472500
context={"alg": "A256GCM"},
473501
)
474502
sender = COSE.new(alg_auto_inclusion=True)
475-
encoded = sender.encode_and_encrypt(
503+
encoded = sender.encode(
476504
b"Hello world!",
477505
shared_key,
478506
recipients=[r],
@@ -490,7 +518,7 @@ The AES key wrap algorithm can be used to wrap a MAC key as follows:
490518
```py
491519
from cwt import COSE, COSEKey, Recipient
492520

493-
# A key to be wrapped
521+
# A key to wrap
494522
enc_key = COSEKey.generate_symmetric_key(alg="ChaCha20/Poly1305")
495523

496524
# The sender side:
@@ -507,27 +535,19 @@ r = Recipient.new(
507535
sender_key=wrapping_key,
508536
)
509537
sender = COSE.new(alg_auto_inclusion=True)
510-
encoded = sender.encode_and_encrypt(b"Hello world!", key=enc_key, recipients=[r])
538+
encoded = sender.encode(b"Hello world!", key=enc_key, recipients=[r])
511539

512540
# The recipient side:
513541
recipient = COSE.new()
514-
shared_key = COSEKey.from_jwk(
515-
{
516-
"kty": "oct",
517-
"alg": "A128KW",
518-
"kid": "01",
519-
"k": "hJtXIZ2uSN5kbQfbtTNWbg",
520-
},
521-
)
522-
assert b"Hello world!" == recipient.decode(encoded, shared_key)
542+
assert b"Hello world!" == recipient.decode(encoded, wrapping_key)
523543
```
524544

525545
#### Direct Key Agreement for encryption
526546

527547
The direct key agreement methods can be used to create a shared secret. A KDF (Key Distribution Function) is then
528548
applied to the shared secret to derive a key to be used to protect the data.
529549
The follwing example shows a simple way to make a COSE Encrypt message, verify and decode it with the direct key
530-
agreement methods (``ECDH-ES+HKDF-256`` with various curves).
550+
agreement methods.
531551

532552
```py
533553
from cwt import COSE, COSEKey, Recipient
@@ -548,7 +568,7 @@ r = Recipient.new(
548568
context={"alg": "A128GCM"},
549569
)
550570
sender = COSE.new(alg_auto_inclusion=True)
551-
encoded = sender.encode_and_encrypt(
571+
encoded = sender.encode(
552572
b"Hello world!",
553573
recipients=[r],
554574
)
@@ -603,7 +623,7 @@ r = Recipient.new(
603623
context={"alg": "A128GCM"},
604624
)
605625
sender = COSE.new(alg_auto_inclusion=True)
606-
encoded = sender.encode_and_encrypt(
626+
encoded = sender.encode(
607627
b"Hello world!",
608628
key=enc_key,
609629
unprotected={5: nonce},
@@ -661,14 +681,17 @@ r = Recipient.new(
661681
recipient_key=rpk,
662682
)
663683
sender = COSE.new()
664-
encoded = sender.encode_and_encrypt(
684+
encoded = sender.encode(
665685
b"This is the content.",
686+
enc_key,
666687
protected={
667688
1: 1, # alg: "A128GCM"
668689
},
669690
recipients=[r],
670691
)
671692

693+
# print(encoded.hex())
694+
672695
# The recipient side:
673696
rsk = COSEKey.from_jwk(
674697
{
@@ -703,7 +726,7 @@ priv_key = COSEKey.from_jwk(
703726
}
704727
)
705728
sender = COSE.new(alg_auto_inclusion=True, kid_auto_inclusion=True)
706-
encoded = sender.encode_and_sign(b"Hello world!", priv_key)
729+
encoded = sender.encode(b"Hello world!", priv_key)
707730

708731
# The recipient side:
709732
pub_key = COSEKey.from_jwk(
@@ -738,7 +761,7 @@ signer = Signer.from_jwk(
738761
},
739762
)
740763
sender = COSE.new()
741-
encoded = sender.encode_and_sign(b"Hello world!", signers=[signer])
764+
encoded = sender.encode(b"Hello world!", signers=[signer])
742765

743766
# The recipient side:
744767
recipient = COSE.new()

0 commit comments

Comments
 (0)