diff --git a/CHANGES.rst b/CHANGES.rst index 0c22d20..78b7455 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -4,6 +4,11 @@ Changes Unreleased ---------- +Version 0.9.0 +------------- + +Released 2021-06-04 + - Introduce new() into CWT/COSE. `#115 `__ - Rename Claims.from_dict to Claims.new. `#115 `__ - Rename COSEKey.from_dict to COSEKey.new. `#115 `__ diff --git a/README.md b/README.md index 32d91f4..a0e80fb 100644 --- a/README.md +++ b/README.md @@ -36,14 +36,23 @@ and [CWT](https://tools.ietf.org/html/rfc8392) is required to use this library. Followings are typical and basic examples which create CWT, verify and decode it: -- [MACed CWT](#maced-cwt) -- [Signed CWT](#signed-cwt) -- [Encrypted CWT](#encrypted-cwt) -- [Nested CWT](#nested-cwt) -- [CWT with User-Defined Claims](#cwt-with-user-defined-claims) -- [CWT with PoP Key](#cwt-with-pop-key) +- CWT API + - [MACed CWT](#maced-cwt) + - [Signed CWT](#signed-cwt) + - [Encrypted CWT](#encrypted-cwt) + - [Nested CWT](#nested-cwt) + - [CWT with User-Defined Claims](#cwt-with-user-defined-claims) + - [CWT with PoP Key](#cwt-with-pop-key) + - (See [CWT Usage Examples](https://python-cwt.readthedocs.io/en/stable/cwt_usage.html) for details) +- COSE API + - [COSE MAC0](#cose-mac0) + - [COSE MAC](#cose-mac) + - [COSE Encrypt0](#cose-encrypt0) + - [COSE Encrypt](#cose-encrypt) + - [COSE Signature1](#cose-signature1) + - [COSE Signature](#cose-signature) + - (See [COSE Usage Examples](https://python-cwt.readthedocs.io/en/stable/cose_usage.html) for details) -See [Usage Examples](https://python-cwt.readthedocs.io/en/stable/usage.html) for details. ### MACed CWT @@ -365,6 +374,228 @@ extracted_pop_key.verify(msg, sig) [Usage Examples](https://python-cwt.readthedocs.io/en/stable/usage.html#cwt-with-pop-key) shows other examples which use other confirmation methods for PoP keys. +### COSE MAC0 + +Create a COSE MAC0 message, verify and decode it as follows: + +```py +from cwt import COSE, COSEKey + +mac_key = COSEKey.from_symmetric_key(alg="HS256", kid="01") +ctx = COSE(alg_auto_inclusion=True, kid_auto_inclusion=True) +encoded = ctx.encode_and_mac(b"Hello world!", mac_key) +decoded = ctx.decode(encoded, mac_key) +``` + +Following two samples are other ways of writing the above example: + +```py +from cwt import COSE, COSEKey + +mac_key = COSEKey.from_symmetric_key(alg="HS256", kid="01") +ctx = COSE.new() +encoded = ctx.encode_and_mac( + b"Hello world!", + mac_key, + protected={"alg": "HS256"}, + unprotected={"kid": "01"}, +) +decoded = ctx.decode(encoded, mac_key) +``` + +```py +from cwt import COSE, COSEKey + +mac_key = COSEKey.from_symmetric_key(alg="HS256", kid="01") +ctx = COSE.new() +encoded = ctx.encode_and_mac( + b"Hello world!", + mac_key, + protected={1: 5}, + unprotected={4: b"01"}, +) +decoded = ctx.decode(encoded, mac_key) +``` + +### COSE MAC + +Create a COSE MAC message, verify and decode it as follows: + +```py +from cwt import COSE, COSEKey + +recipient = Recipient.from_json({"alg": "direct", "kid": "01"}) +mac_key = COSEKey.from_symmetric_key(alg="HS512", kid="01") +ctx = COSE.new() +encoded = ctx.encode_and_mac(b"Hello world!", mac_key, recipients=[recipient]) +decoded = ctx.decode(encoded, mac_key) +``` + +Following sample is another way of writing the above example: + +```py +from cwt import COSE, COSEKey + +recipient = Recipient.new(unprotected={"alg": "direct", "kid": "01"}) +mac_key = COSEKey.from_symmetric_key(alg="HS512", kid="01") +ctx = COSE.new() +encoded = ctx.encode_and_mac(b"Hello world!", mac_key, recipients=[recipient]) +decoded = ctx.decode(encoded, mac_key) +``` + +### COSE Encrypt0 + +Create a COSE Encrypt0 message, verify and decode it as follows: + +```py +from cwt import COSE, COSEKey + +enc_key = COSEKey.from_symmetric_key(alg="ChaCha20/Poly1305", kid="01") +ctx = COSE.new(alg_auto_inclusion=True, kid_auto_inclusion=True) +encoded = ctx.encode_and_encrypt(b"Hello world!", enc_key) +decoded = ctx.decode(encoded, enc_key) +``` + +Following sample is another way of writing the above example: + +```py +from cwt import COSE, COSEKey + +enc_key = COSEKey.from_symmetric_key(alg="ChaCha20/Poly1305", kid="01") +ctx = COSE.new() +encoded = ctx.encode_and_encrypt( + b"Hello world!", + enc_key, + nonce=nonce, + protected={"alg": "ChaCha20/Poly1305"}, + unprotected={"kid": "01"}, +) +decoded = ctx.decode(encoded, enc_key) +``` + +### COSE Encrypt + +Create a COSE Encrypt message, verify and decode it as follows: + +```py +from cwt import COSE, COSEKey + +recipient = Recipient.from_json({"alg": "direct", "kid": "01"}) +enc_key = COSEKey.from_symmetric_key(alg="ChaCha20/Poly1305", kid="01") +ctx = COSE.new() +encoded = ctx.encode_and_encrypt( + b"Hello world!", + enc_key, + recipients=[recipient], +) +decoded = ctx.decode(encoded, enc_key) +``` + +Following sample is another way of writing the above example: + +```py +from cwt import COSE, COSEKey + +recipient = Recipient.new(unprotected={"alg": "direct", "kid": "01"}) +enc_key = COSEKey.from_symmetric_key(alg="ChaCha20/Poly1305", kid="01") +ctx = COSE.new() +encoded = ctx.encode_and_mac(b"Hello world!", enc_key, recipients=[recipient]) +decoded = ctx.decode(encoded, enc_key) +``` + +### COSE Signature1 + +Create a COSE Signature1 message, verify and decode it as follows: + +```py +from cwt import COSE, COSEKey + +sig_key = COSEKey.from_jwk( + { + "kty": "EC", + "kid": "01", + "crv": "P-256", + "x": "usWxHK2PmfnHKwXPS54m0kTcGJ90UiglWiGahtagnv8", + "y": "IBOL-C3BttVivg-lSreASjpkttcsz-1rb7btKLv8EX4", + "d": "V8kgd2ZBRuh2dgyVINBUqpPDr7BOMGcF22CQMIUHtNM", + } +) +ctx = COSE.new(alg_auto_inclusion=True, kid_auto_inclusion=True) +encoded = ctx.encode_and_sign(b"Hello world!", sig_key) +decoded = ctx.decode(encoded, sig_key) +``` + +Following sample is another way of writing the above example: + +```py +from cwt import COSE, COSEKey + +sig_key = COSEKey.from_jwk( + { + "kty": "EC", + "kid": "01", + "crv": "P-256", + "x": "usWxHK2PmfnHKwXPS54m0kTcGJ90UiglWiGahtagnv8", + "y": "IBOL-C3BttVivg-lSreASjpkttcsz-1rb7btKLv8EX4", + "d": "V8kgd2ZBRuh2dgyVINBUqpPDr7BOMGcF22CQMIUHtNM", + } +) +ctx = COSE.new() +encoded = ctx.encode_and_sign( + b"Hello world!", + sig_key, + protected={"alg": "ES256"}, + unprotected={"kid": "01"}, +) +decoded = ctx.decode(encoded, sig_key) +``` + +### COSE Signature + +Create a COSE Signature message, verify and decode it as follows: + +```py +from cwt import COSE, Signer + +signer = Signer.from_jwk( + { + "kty": "EC", + "kid": "01", + "crv": "P-256", + "x": "usWxHK2PmfnHKwXPS54m0kTcGJ90UiglWiGahtagnv8", + "y": "IBOL-C3BttVivg-lSreASjpkttcsz-1rb7btKLv8EX4", + "d": "V8kgd2ZBRuh2dgyVINBUqpPDr7BOMGcF22CQMIUHtNM", + }, +) +ctx = COSE.new() +encoded = ctx.encode_and_sign(b"Hello world!", signers=[signer]) +decoded = ctx.decode(encoded, signer.cose_key) +``` + +Following sample is another way of writing the above example: + +```py +from cwt import COSE, COSEKey, Signer + +signer = Signer.new( + cose_key=COSEKey.from_jwk( + { + "kty": "EC", + "kid": "01", + "crv": "P-256", + "x": "usWxHK2PmfnHKwXPS54m0kTcGJ90UiglWiGahtagnv8", + "y": "IBOL-C3BttVivg-lSreASjpkttcsz-1rb7btKLv8EX4", + "d": "V8kgd2ZBRuh2dgyVINBUqpPDr7BOMGcF22CQMIUHtNM", + } + ), + protected={"alg": "ES256"}, + unprotected={"kid": "01"}, +) +ctx = COSE.new() +encoded = ctx.encode_and_sign(b"Hello world!", signers=[signer]) +decoded = ctx.decode(encoded, signer.cose_key) +``` + ## Tests You can run tests from the project root after cloning with: diff --git a/cwt/__init__.py b/cwt/__init__.py index 8e71343..001de83 100644 --- a/cwt/__init__.py +++ b/cwt/__init__.py @@ -15,7 +15,7 @@ from .recipient import Recipient from .signer import Signer -__version__ = "0.8.1" +__version__ = "0.9.0" __title__ = "cwt" __description__ = "A Python implementation of CWT/COSE" __url__ = "https://python-cwt.readthedocs.io"