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 EdDSA to create a signature for a message.
COSE and CBOR - EdDSA 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 import sys message='hello' # Generate random keypair: OKPKpD - private key, OKPKpX - public key cose_key = OKPKey.generate_key(crv='ED25519') if (len(sys.argv)>1): message=str(sys.argv[1]) msg = Sign1Message(phdr = {Algorithm: EdDSA, KID: b'mycrypto'},payload = message.encode()) 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(OKPKey): {'OKPKpD': "b'\\xbch\\xfd\\x9b\\xe1' ... (32 B)" , 'OKPKpX' : "b'\\xdc]\\xa2B\\x88' ... (32 B)" , 'OKPKpCurve' : 'Ed25519' , 'KpKty' : 'KtyOKP' }> Private Key: b'bc68fd9be1922cf91469580cdc1217b40c5bc36053ab07b30ffff91857a25df6' Public Key: b'dc5da24288692aef4f882b2fb96b9df1251eb4e01d83709524a44283944ae593' Message: hello COSE message: b"\xd2\x84M\xa2\x01'\x04Hmycrypto\xa0EhelloX@\xa4\x98\xce\x9f\\\x91~\x1c\xb7C\xf3\x1fq\xcb\x8d\xcbO\xa1\x1e\n%\x97TYz/\x13\x1e\xb1\xf9g\xd6\xda\xd3t\x07\xcf\xdfA\r%\xc8\x00\xdc}u\x95\xe2\x9e\xe5n\x8c\x95\xf3\x01\xd2J\x16\xcc(T\xbb\xb6\x0e" COSE encoded (hex): d2844da2012704486d7963727970746fa04568656c6c6f5840a498ce9f5c917e1cb743f31f71cb8dcb4fa11e0a259754597a2f131eb1f967d6dad37407cfdf410d25c800dc7d7595e29ee56e8c95f301d24a16cc2854bbb60e 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]