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 include signatures, message authentication codes (MACs) and encryption and creating serialised objects. In this case we will use a symmetric key to encrypt a message, and then decrypt it. In this case we will use AES GCM with a static 128-bit key ("0x000102030405060708090a0b0c0d0e0f").
COSE and CBOR - Symmetric Key |
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.
CBOR integrates security into small data objects and small message sizes. This includes signatures, message authentication codes (MACs), encryption and creating serialised objects. In this case, we will use a symmetric key to encrypt a message and then decrypt it. In this case we will use AES GCM with a static 128-bit key (“0x000102030405060708090a0b0c0d0e0f”):
from binascii import unhexlify,hexlify from cose.messages import Enc0Message,CoseMessage from cose.keys import SymmetricKey import sys mymsg="hello" if (len(sys.argv)>1): mymsg=str(sys.argv[1]) msg = Enc0Message( phdr={'ALG': 'A128GCM', 'IV': unhexlify(b'01010101010101010101010101010101')}, uhdr={'KID': b'test@home'}, payload=mymsg.encode() ) cose_key = SymmetricKey(k=unhexlify(b'000102030405060708090a0b0c0d0e0f')) msg.key = cose_key msg.encode() cose_msg = CoseMessage.decode(msg.encode()) cose_msg.key = cose_key rtn=cose_msg.decrypt() print ("Input message: ",mymsg) print ("COSE message: ",msg) print ("COSE encoded: ",hexlify(cose_msg.payload)) print ("Decrypted: ",rtn.decode())
The IV value applied in this case is also a static value of “01010101010101010101010101010101”. A sample run shows the format of the key and message, and where we can encode the encrypted data object into a hex stream:
Input message: Bert Smith COSE key: COSE_Key(Symmetric): {'SymKpK': "b'\\x00\\x01\\x02\\x03\\x04' ... (16 B)", 'KpKty': 'KtySymmetric'}> COSE message: COSE_Encrypt0: [{'Algorithm': 'A128GCM', 'IV': "b'\\x01\\x01\\x01\\x01\\x01' ... (16 B)"}, {'KID': b'test.home'}, b'Bert ' ... (10 B)]> COSE encoded: b'e7ea84bd09703c8e4d96dda0e98b608f232603d3489180263115' Decrypted: Bert Smith
In this case, we have plaintext and authenticated headers, but a ciphertext stream for the payload. We can see that the encoded COSE message is fairly small, given that it also contains an authentication tag and the cipher stream. The COSE message has the header, and the “… (10 B)” part identifies that we have a 10-byte cipher stream (as we have 10 characters in the plaintext message). As we are using a stream cipher (GCM mode), we have the same number of bytes as is in the data stream. In authenticated encryption, we also have additional data, and which appears in plaintext in the header.
Coding
The coding is:
from binascii import unhexlify,hexlify from cose.messages import Enc0Message,CoseMessage from cose.keys import SymmetricKey import sys mymsg="hello" if (len(sys.argv)>1): mymsg=str(sys.argv[1]) msg = Enc0Message( phdr={'ALG': 'A128GCM', 'IV': unhexlify(b'01010101010101010101010101010101')}, uhdr={'KID': b'test@home'}, payload=mymsg.encode() ) cose_key = SymmetricKey(k=unhexlify(b'000102030405060708090a0b0c0d0e0f')) msg.key = cose_key msg.encode() cose_msg = CoseMessage.decode(msg.encode()) cose_msg.key = cose_key rtn=cose_msg.decrypt() print ("Input message: ",mymsg) print ("COSE message: ",msg) print ("COSE encoded: ",hexlify(cose_msg.payload)) print ("Decrypted: ",rtn.decode())
A sample run is:
Input message: Fred Smith12345 COSE message: <COSE_Key(Symmetric): {'SymKpK': "b'\\x00\\x01\\x02\\x03\\x04' ... (16 B)", 'KpKty': 'KtySymmetric'}. COSE message: <COSE_Encrypt0: [{'Algorithm': 'A128GCM', 'IV': "b'\\x01\\x01\\x01\\x01\\x01' ... (16 B)"}, {'KID': b'test.home'}, b'Fred ' ... (15 B)] COSE encoded: b'e3fd93ad09703c8e4d96b84b5836f44fbe678497867d6e8ae0095e81e4f1db' n\Decrypted: Fred Smith12345
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]