diff options
| author | cirakg <cirakg@cirakg.xyz> | 2026-10-21 03:55:10 +0200 |
|---|---|---|
| committer | cirakg <cirakg@cirakg.xyz> | 2026-10-21 03:55:10 +0200 |
| commit | 5e8ac1e2f5a660e55ea132996e1d5730cfa4fa64 (patch) | |
| tree | 9bb99bdca1ef8f33c93c5100816448681329d810 /source/crypto/Hkdf.mc | |
| parent | 88f1cac4fa530fc30fd6ef01970af11c7a959b8e (diff) | |
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 <noreply@anthropic.com>
Diffstat (limited to 'source/crypto/Hkdf.mc')
| -rw-r--r-- | source/crypto/Hkdf.mc | 39 |
1 files changed, 39 insertions, 0 deletions
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; + } +} |
