From 5e8ac1e2f5a660e55ea132996e1d5730cfa4fa64 Mon Sep 17 00:00:00 2001 From: cirakg Date: Wed, 21 Oct 2026 03:55:10 +0200 Subject: feat(glance): show the favourite code in the glance (opt-in) With "Show the favourite code in the glance" on, the glance shows the code of the first favourite TOTP or Steam entry without the PIN, with a countdown bar. The glance can't open the vault, so the About scan seals that entry under "g" (device key, aad OTPW-GL-1) after every change, and removes it when the option is off or no entry qualifies; the glance also reads the option itself. HKDF moves to its own module so the glance loads only the crypto it needs (37 % of its 64 KB). Manage entry gains "Mark as favourite (glance)" and "Remove favourite", queued for locked entries like the other changes. Lines are inset on round screens so the Instinct 3's curved glance corner doesn't cut them. Co-Authored-By: Claude Opus 5.5 --- source/crypto/Hkdf.mc | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 source/crypto/Hkdf.mc (limited to 'source/crypto/Hkdf.mc') diff --git a/source/crypto/Hkdf.mc b/source/crypto/Hkdf.mc new file mode 100644 index 0000000..97814b9 --- /dev/null +++ b/source/crypto/Hkdf.mc @@ -0,0 +1,39 @@ +// Author: cirakg & claude ai +// Summary: HKDF-SHA256 (RFC 5869) on the native HMAC, small enough for the glance. +// +// The key derivation SealedBox and KeyManager use for every sub-key. It +// lives apart from Kdf (PBKDF2, which needs the job system) so the glance +// can open the sealed favourite code (GlanceCode) with only the crypto it +// needs. Verified with RFC 5869 test cases 1 to 3 (test/crypto/KdfAesTest.mc) +// and in the start-up self-test. + +import Toybox.Lang; + +(:glance) +module Hkdf { + + const HASH_BYTES = 32; + + // Extract with salt (empty means 32 zero bytes), then expand to + // `length` bytes with info. length <= 255 * 32. + function derive(ikm as ByteArray, salt as ByteArray, info as ByteArray, length as Number) as ByteArray { + if (length < 1 || length > 255 * HASH_BYTES) { + throw new Lang.InvalidValueException("HKDF: bad key length"); + } + var prk = Hmac.nativeSha256(salt.size() > 0 ? salt : new [HASH_BYTES]b, ikm); + var okm = new [0]b; + var block = new [0]b; + for (var counter = 1; okm.size() < length; counter++) { + var input = Bytes.concat(block, info); + input.add(counter); + Bytes.wipe(block); + block = Hmac.nativeSha256(prk, input); + okm.addAll(block); + } + Bytes.wipe(prk); + Bytes.wipe(block); + var key = okm.slice(0, length); + Bytes.wipe(okm); + return key; + } +} -- cgit v1.2.3