summaryrefslogtreecommitdiff
path: root/source/crypto/Hkdf.mc
diff options
context:
space:
mode:
Diffstat (limited to 'source/crypto/Hkdf.mc')
-rw-r--r--source/crypto/Hkdf.mc39
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;
+ }
+}