Concise Binary Object Representation (CBOR) [1] integrates security into small data objects and small message sizes. COSE (CBOR Object Signing and Encryption) [2] can then build on this to includes signatures, message authentication codes (MACs) and encryption and creating serialised objects. In this case we will use ECDSA to create a signature for a message.
COSE and CBOR - ECDSA Signature |
Outline
In computer security, we often have to represent binary data, in single values or groups of characters, bytes, words, long words, signed integers, floating-point values, double-precision floating-point values, and so on. This might be in the form of a data object, a signature or even encrypted content. For this, the ANS.1 DER format is often used, such as presenting digital certificates and signatures. An improvement on this for small messages with security is Concise Binary Object Representation (CBOR) — and which is defined in RFC8949 [1]. While JSON represents text-based data objects CBOR focuses on binary objects. It has been designed to create a lightweight encoder and decoder. This supports the use of CBOR within an IoT infrastructure. The data, also, does not require a data schema to be able to decode it, along with being extensible.
from cose.messages import CoseMessage from binascii import unhexlify, hexlify from cose.messages import Sign1Message from cose.keys import CoseKey from cose.headers import Algorithm, KID from cose.algorithms import EdDSA from cose.keys.curves import Ed25519 from cose.keys.keyparam import KpKty, OKPKpD, OKPKpX, KpKeyOps, OKPKpCurve from cose.keys.keytype import KtyOKP from cose.keys.keyops import SignOp, VerifyOp from cose.keys import OKPKey, CoseKey from cose.algorithms import Es256 from os import urandom from cose.keys.keytype import KtyEC2 from cose.keys.keyparam import KpAlg, EC2KpD, EC2KpCurve from cose.keys.curves import P256 import sys message='hello' # Generate random keypair: OKPKpD - private key, OKPKpX - public key if (len(sys.argv)>1): message=str(sys.argv[1]) message=message.encode() priv = urandom(32) keyid=b'test' # msg = Sign1Message(phdr = {Algorithm: ECDSA, KID: b'mycrypto'},payload = message.encode()) msg = Sign1Message(phdr={Algorithm: Es256, KID: keyid}, payload=message) cose_key = { KpKty: KtyEC2, KpAlg: Es256, # ECDSA-with-SHA256 EC2KpCurve: P256, EC2KpD: priv, } # See https://python-cwt.readthedocs.io/en/stable/algorithms.html cose_key = CoseKey.from_dict(cose_key) msg.key = cose_key en = msg.encode(tag=True,sign=True) print("Key: ",cose_key) print("Private Key: ",hexlify(cose_key.d)) print("Public Key: ",hexlify(cose_key.x)) print ("\nMessage: ",message) print ("\nCOSE message: ",en) print ("\nCOSE encoded (hex): ",hexlify(en).decode()) cos = CoseMessage.decode(en) cos.key = cose_key print ("Signature: ",cos.verify_signature()) print ("Decrypted: ",cos.payload.decode())
In this case we will create an EdDSA signature, and use a random keypair generation. The private key is defined by OKPKpD and the public key by OKPKpX.
Key: <COSE_Key(EC2Key): {'EC2KpD': "b'\\xa7B\\xabJ\\xa5' ... (32 B)", 'EC2KpY': "b'X\\x0b-R\\x1c' ... (32 B)", 'EC2KpX': "b'\\x0c\\xfa\\xf0\\xaa\\xee' ... (32 B)", 'EC2KpCurve': 'P256', 'KpKty': 'KtyEC2', 'KpAlg': 'Es256'}> Private Key: b'a742ab4aa510c689e38e8bfb1eda771213f5f90f2f035fe68eccf9fd37012033' Public Key: b'0cfaf0aaee80ce7a7b47b1ed34fbe7cfd7e9eb61bd009a513be74e69ab15dcda' Message: b'hello' COSE message: b'\xd2\x84I\xa2\x01&\x04Dtest\xa0EhelloX@\x93\xf8>I\xfe\xffX\xa2\x1b\xdb\xefU\x84\x11jR&\x81\xad~\xda\x1cI\xc5&\xa4\x12\xa7\xcelT7\xbc\x92\xa6\xa9d1\x10\xe5X\x11N\xd2\x93\xea\xfc\x89F\xe3\xa4\x03z\xe5{\xf2V<\xbc\xae\xb6\x04\xef\x94' COSE encoded (hex): d28449a20126044474657374a04568656c6c6f584093f83e49feff58a21bdbef5584116a522681ad7eda1c49c526a412a7ce6c5437bc92a6a9643110e558114ed293eafc8946e3a4037ae57bf2563cbcaeb604ef94 Signature: True Decrypted: hello
In Ed25519, both the public and the private keys are 32 bytes long (256 bits). With the private key, we have a random 32 byte value, whereas the public key is just the x-co-ordinate on the curve.
Coding
To run the code, you need to pip install cose:
References
[1] Bormann, C., & Hoffman, P. (2020). RFC 8949 Concise Binary Object Representation (CBOR). [here].
[2] Schaad, J. (2017), RFC 8152 – CBOR Object Signing and Encryption (COSE), 2017. [here]