As a stretch goal, it would be useful to have a few standard Applications bundled with the main software that can be used to encapsulate Packages for other Applications. There are two main options:
The cipher can be implemented pretty simply using an XOF to generate a pseudo-random stream of bytes that are then XORed to encrypt plaintext or decrypt ciphertext. Example cipher that works in micropython. The Application would have two callbacks with the following signatures:
def encrypt(self, package: Package, key: bytes) -> Package:
""""Encapsulate the given package, encrypting it with the given key
and returning a new Package.
"""
plaintext = package.pack()
iv = token_bytes(16)
ciphertext = ....
return Package.from_blob(self.id, iv + ciphertext)
def decrypt(self, package: Package, key: bytes) -> Package:
"""Open a Package encrypted by this Application, decrypt its
contents using the given key, then return the original Package.
"""
assert package.verify(), 'rejecting corrupted Package'
assert package.app_id == self.id, 'cannot decrypt a Package from a different Application'
assert len(package.blob) > 16, 'invalid Package: must have IV and ciphertext'
iv, ciphertext = package.blob[:16], package.blob[16:]
plaintext = ...
return Package.unpack(plaintext)
This will be dependent upon whatever elliptic curve cryptographic capabilities can be achieved via #1. The Application would have two callbacks with the following signatures:
def encrypt(self, package: Package, sender_privkey: bytes, recipient_pubkey: bytes) -> Package:
""""Encapsulate the given package, encrypting it using ECDHE
and returning a new Package.
"""
plaintext = package.pack()
sender_pubkey: bytes = ...
ciphertext: bytes = ....
return Package.from_blob(self.id, len(sender_pubkey).to_bytes(1, 'big') + sender_pubkey + ciphertext)
def decrypt(self, package: Package, recipient_privkey: bytes) -> Package:
"""Open a Package encrypted by this Application, decrypt its
contents using the given key, then return the original Package.
"""
assert package.verify(), 'rejecting corrupted Package'
assert package.app_id == self.id, 'cannot decrypt a Package from a different Application'
pk_len = int.from_bytes(package.blob[:1], 'big')
assert len(package.blob) > pk_len + 1, 'invalid Package: must have pk_len, pubkey, and ciphertext'
sender_pubkey, ciphertext = package.blob[1:1+pk_len], package.blob[1+pk_len:]
plaintext = ...
return Package.unpack(plaintext)
The above pseudocode is not exact, but it gets the concept across: the Package blobs must include the sender's public key, an IV, etc -- whatever the specific ECDHE implementation requires -- as well as the ciphertext. This assumes that ECDHE will be possible with whatever asymmetric key system is ultimately implemented in this project.
Source code references:
Note that performance of the linked stream cipher must be tested and compared to the performance of AES from the micropython cryptolib module.
Pay now to fund the work behind this issue.
Get updates on progress being made.
Maintainer is rewarded once the issue is completed.
You're funding impactful open source efforts
You want to contribute to this effort
You want to get funding like this too