Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

crypto: add support for AES CCM #2579

Merged
merged 5 commits into from
Dec 9, 2024

Conversation

ssievert42
Copy link
Contributor

@ssievert42 ssievert42 commented Nov 25, 2024

This adds support for AES CCM and enables it on Linux, Bangle.js 2 and the Bangle.js 2 emulator.

Can be used for creating encrypted BTHome advertisements.
Example that follows https://bthome.io/encryption to encrypt and decrypt a BTHome advertisement:
https://gist.github.com/ssievert42/dd979303b228cbd1c52733a3f63004cf

WIP BTHome module that creates encrypted advertisements (planning on submitting this soon™; check first comment below the gist for creating and setting an encryption key):
https://gist.github.com/ssievert42/1305e4a036d8a3d4a6e14229c2eb01e5

@ssievert42 ssievert42 force-pushed the crypto_aes_ccm branch 2 times, most recently from 74c3d5e to 065aeed Compare November 25, 2024 20:16
@ssievert42
Copy link
Contributor Author

ssievert42 commented Nov 25, 2024

Should this be enabled on Puck.js?
It does use up some precious flash (CODE grows by 3520 B), but might be handy for someone wanting to use BTHome with authenticated encryption.

@gfwilliams
Copy link
Member

gfwilliams commented Nov 26, 2024

Thanks - just looking at this, I'm not quite sure what the differences are but is there any way code can be reused from jswrap_crypto_AEScrypt so we're not having quite so much duplication?

Or at the very least, doing like we do in jswrap_crypto_AEScrypt where we have one function we call from jswrap_crypto_AES_encrypt and jswrap_crypto_AES_decrypt, as it looks like there's a bunch of duplicated code in jswrap_crypto_AES_ccmDecrypt and jswrap_crypto_AES_ccmEncrypt?

On the Puck.js front, maybe I'd leave it out for now - I've spent a lot of time trying to free up hundreds of bytes here and there for Puck.js builds so I'd rather not suddenly fill it up with an extra 3.5k!

@ssievert42
Copy link
Contributor Author

is there any way code can be reused from jswrap_crypto_AEScrypt

Not really (apart from getting the iv, the JSV_GET_AS_CHAR_ARRAY calls and allocating an output buffer). In my initial version of this, I actually had the CCM stuff integrated in jswrap_crypto_AEScrypt, but CCM uses a mbedtls_ccm_context, so the mbedtls_aes_context from jswrap_crypto_AEScrypt cannot be used and I wanted to be able to use this without including all the other AES stuff.

it looks like there's a bunch of duplicated code in jswrap_crypto_AES_ccmDecrypt and jswrap_crypto_AES_ccmEncrypt

I've now moved both encrypting and decrypting into jswrap_crypto_AES_ccmCrypt, and tried to deduplicate what I could.

On the Puck.js front, maybe I'd leave it out for now

Alright, removed from the Puck.js build 👍
I can absolutely understand not wanting to suddenly fill up a third of the remaining storage :)

@ssievert42
Copy link
Contributor Author

Turns out the Bangle.js 2 build can be 1424 B smaller (still an increase compared to current master though) by not configuring mbedtls to enable all AES stuff if the board doesn't use AES.

@gfwilliams
Copy link
Member

Thanks for that! Combining the two functions still helps a lot.

not configuring mbedtls to enable all AES stuff if the board doesn't use AES.

Great! Is that done now?

Some description in the JSON header for ccmEncrypt/Decrypt would be really handy. I know we don't seem to have anything for AES but ideally a small comment that it's for CCM encryption and a very small bit of example code would be perfect.

So what's your main reason for doing this? BTHome?

Before merging, have you tested and got it working with BTHome? It'd be good to ensure we've got everything you need for it to be useful.

@ssievert42
Copy link
Contributor Author

ssievert42 commented Nov 26, 2024

Great! Is that done now?

Should be as of my last push 👍

Some description in the JSON header for ccmEncrypt/Decrypt would be really handy

Oops, totally forgot about that 🙈 I'll try to come up with something.
Is there a nice built-in way to fill an ArrayBuffer with data from a hex-String?
(To provide a key to ccmEncrypt() and ccmDecrypt().)

So what's your main reason for doing this? BTHome?

Yup: Sending encrypted BTHome advertisements in the general direction of Home Assistant.
But apart from BTHome I (currently) don't have another use case for this in mind.

I discovered BTHome like four days ago, but didn't want to use something wireless without some form of security - hence this crypto stuff.
I've actually been trying to use my Bangle.js 2 to talk to Home Assistant for some time now. Ideally bidirectional and without needing a phone, but something that also works while connected to a phone.
There's even a (mostly failed) attempt at using ZigBee somewhere on my computer. I just kind of gave up when I couldn't get multiprotocol to work properly - Home Assistant and a Seeed XIAO BLE, that I turned into a ZigBee sniffer, could see another Seeed XIAO BLE running Espruino, but for the most part not the other way around. Probably because the ZigBee stack didn't get enough radio time to listen for data.

By the way, would you be open to adding the Seeed XIAO BLE to the list of supported boards?
(If I were to create a PR.)
I've been using these with my own board definition and some changes to directly build an uf2 (based on one found here).
For me, personally, these are currently the best way to test stuff on real hardware, because flashing is super quick and requires no software-setup on the host - just double-press the reset button, copy the uf2 to the usb-drive that appears and you're done!
(A way to get to the bootloader from software would be nice though. Since ruining and having to replace the button on my Bangle.js 2, I've got slight paranoia about wrecking tiny buttons.)

have you tested and got it working with BTHome?

Just tested this again; sending encrypted BTHome advertisements and having Home Assistant do something seems to work nicely 👍
To create advertisements I'm using this modified version of the BTHome module (also mentioned in the first comment here).
I've also written a script that follows https://bthome.io/encryption to test if encrypting and decrypting data works as expected. (Uses the same data as in the BTHome docs.)
What I didn't try is receiving and decrypting BTHome advertisements, but since decrypting works that should also work.

@gfwilliams
Copy link
Member

Sorry for the delay, I missed this...

Is there a nice built-in way to fill an ArrayBuffer with data from a hex-String?

Actually no (just the usual JS)... for base64 there's arraybuffer.set(atob(...)). Not sure if there's anything in Node.js/browser that we could implement here? There is https://nodejs.org/api/buffer.html#static-method-bufferfromstring-encoding which might make sense, but I feel like it might end up being too big to keep in for all boards if all the other functionality started getting added.

I discovered BTHome like four days ago, but didn't want to use something wireless without some form of security

My feeling with it was if someone can get close enough to read the BLE advertisement with my Office's temperature, they're probably close enough to look in the window anyway :)

Still, it's nice to have the option...

By the way, would you be open to adding the Seeed XIAO BLE to the list of supported boards?

Yes, that'd be good, thanks!

@gfwilliams gfwilliams merged commit abf0fd9 into espruino:master Dec 9, 2024
@ssievert42
Copy link
Contributor Author

Sorry for the delay, I missed this...

No worries :)

I'm still gonna create a PR soon-ish with some docs for this, probably with something along the lines of let key = new Uint8Array([0xde,0xad,0xbe,0xef]) for initializing ArrayBuffers.

if someone can get close enough to read the BLE advertisement with my Office's temperature, they're probably close enough to look in the window anyway :)

I hadn't thought of it that way 🙈
My usecase is more on the controlling stuff side; I guess somebody living in the apartment next to me could potentially toggle my lights or something.
But yeah, having the option is still nice, especially for someone as paranoid as I am about sending unencrypted data over the air.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants