In IoT, How Can We Represent Binary Data Objects and Integrate Security?

Concise Binary Object Representation — Symmetric Key

Photo by Alexander Sinn on Unsplash

In IoT, How Can We Represent Binary Data Objects and Integrate Security?

Concise Binary Object Representation — Symmetric Key

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 [here]. 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 defines the format of binary data with data objects and messages. We can then integrate security with CBOR Object Signing and Encryption (COSE), and which is defined in RFC8152 [here]. 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.

Here is the running code:

https://asecuritysite.com/encryption/cose01?a=Bert%20Smith

We can also create a signature for a message. For this we need to sign with a private key (OKPKpD) and then prove with a public key (OKPKpX):

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
import sys
message='hello'
msg = Sign1Message(phdr = {Algorithm: EdDSA, KID: b'kid2'},payload = message.encode())
cose_key = {KpKty: KtyOKP,OKPKpCurve: Ed25519,KpKeyOps: [SignOp, VerifyOp],OKPKpD: unhexlify(b'9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60'),OKPKpX: unhexlify(b'd75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a')}
if (len(sys.argv)>1):
message=str(sys.argv[1])
cose_key = CoseKey.from_dict(cose_key)
msg.key = cose_key
en = msg.encode(tag=True,sign=True)
print ("Message: ",message)
print ("\nCOSE encoded: ",hexlify(en))
cos = CoseMessage.decode(en)
cos.key = cose_key
print ("Signature: ",cos.verify_signature())
print ("Decrypted: ",cos.payload.decode())

A sample run is here:

https://asecuritysite.com/encryption/cose02

If you are interested, here is an article on ASN.1 DER:

Subscribe: https://billatnapier.medium.com/membership