aboutsummaryrefslogtreecommitdiff
path: root/source/crypto
diff options
context:
space:
mode:
Diffstat (limited to 'source/crypto')
-rw-r--r--source/crypto/Aes.mc2
-rw-r--r--source/crypto/Hashes.mc2
-rw-r--r--source/crypto/Hkdf.mc39
-rw-r--r--source/crypto/Hmac.mc2
-rw-r--r--source/crypto/Kdf.mc33
-rw-r--r--source/crypto/SealedBox.mc6
-rw-r--r--source/crypto/SelfTest.mc2
-rw-r--r--source/crypto/Sha512.mc2
8 files changed, 57 insertions, 31 deletions
diff --git a/source/crypto/Aes.mc b/source/crypto/Aes.mc
index e77cb86..242448b 100644
--- a/source/crypto/Aes.mc
+++ b/source/crypto/Aes.mc
@@ -15,6 +15,8 @@
import Toybox.Cryptography;
import Toybox.Lang;
+// (:glance): also loaded by the glance, which shows the favourite code (GlanceCode).
+(:glance)
module Aes {
const BLOCK_BYTES = 16;
diff --git a/source/crypto/Hashes.mc b/source/crypto/Hashes.mc
index 14e2cf2..321ea2d 100644
--- a/source/crypto/Hashes.mc
+++ b/source/crypto/Hashes.mc
@@ -9,6 +9,8 @@
import Toybox.Cryptography;
import Toybox.Lang;
+// (:glance): also loaded by the glance, which shows the favourite code (GlanceCode).
+(:glance)
module Hashes {
// OTP and HMAC hash algorithms. The values are stored in entry records, so
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;
+ }
+}
diff --git a/source/crypto/Hmac.mc b/source/crypto/Hmac.mc
index ff620a4..736d2d4 100644
--- a/source/crypto/Hmac.mc
+++ b/source/crypto/Hmac.mc
@@ -16,6 +16,8 @@
import Toybox.Cryptography;
import Toybox.Lang;
+// (:glance): also loaded by the glance, which shows the favourite code (GlanceCode).
+(:glance)
module Hmac {
const IPAD = 0x36;
diff --git a/source/crypto/Kdf.mc b/source/crypto/Kdf.mc
index 5bace1c..e64c8ff 100644
--- a/source/crypto/Kdf.mc
+++ b/source/crypto/Kdf.mc
@@ -1,5 +1,5 @@
// Author: cirakg & claude ai
-// Summary: Key derivation: resumable PBKDF2-HMAC-SHA256 (RFC 8018) with calibration, and HKDF-SHA256 (RFC 5869).
+// Summary: PIN key derivation: resumable PBKDF2-HMAC-SHA256 (RFC 8018) with calibration.
//
// PBKDF2 turns the PIN into a key (README 7.2). It runs as a Jobs.Job, a
// bounded number of iterations per step, because the iteration count is
@@ -7,11 +7,11 @@
// watchdog budget. It uses the native HMAC-SHA256: the object keeps the key
// and digest() resets it, so each iteration is one native call.
//
-// HKDF splits one master key into separate encryption and MAC keys
-// (README 7.3).
+// HKDF, which splits one master key into separate encryption and MAC keys
+// (README 7.3), is in Hkdf.mc (the glance needs it, but not PBKDF2).
//
-// Verified with RFC 7914 section 11 (PBKDF2) and RFC 5869 A.1-A.3 (HKDF),
-// plus seeded vectors from Python's hashlib (test/crypto/KdfTest.mc).
+// Verified with RFC 7914 section 11 (PBKDF2) plus seeded vectors from
+// Python's hashlib (test/crypto/KdfAesTest.mc).
import Toybox.Cryptography;
import Toybox.Lang;
@@ -191,27 +191,4 @@ module Kdf {
}
return estimate > MAX_ITERATIONS ? MAX_ITERATIONS : estimate.toNumber();
}
-
- // HKDF-SHA256 (RFC 5869): extract with salt (empty means 32 zero bytes),
- // then expand to `length` bytes with info. length <= 255 * 32.
- function hkdf(ikm as ByteArray, salt as ByteArray, info as ByteArray, length as Number) as ByteArray {
- if (length < 1 || length > 255 * SHA256_BYTES) {
- throw new Lang.InvalidValueException("HKDF: bad key length");
- }
- var prk = Hmac.nativeSha256(salt.size() > 0 ? salt : new [SHA256_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;
- }
}
diff --git a/source/crypto/SealedBox.mc b/source/crypto/SealedBox.mc
index 0804b96..765a1d8 100644
--- a/source/crypto/SealedBox.mc
+++ b/source/crypto/SealedBox.mc
@@ -20,6 +20,8 @@
import Toybox.Cryptography;
import Toybox.Lang;
+// (:glance): also loaded by the glance, which shows the favourite code (GlanceCode).
+(:glance)
module SealedBox {
const VERSION = 1;
@@ -34,8 +36,8 @@ module SealedBox {
var macKey as ByteArray;
function initialize(masterKey as ByteArray) {
- encKey = Kdf.hkdf(masterKey, []b, Bytes.fromUtf8("OTPW enc v1"), KEY_BYTES);
- macKey = Kdf.hkdf(masterKey, []b, Bytes.fromUtf8("OTPW mac v1"), KEY_BYTES);
+ encKey = Hkdf.derive(masterKey, []b, Bytes.fromUtf8("OTPW enc v1"), KEY_BYTES);
+ macKey = Hkdf.derive(masterKey, []b, Bytes.fromUtf8("OTPW mac v1"), KEY_BYTES);
}
// Wipe both keys (when the session locks).
diff --git a/source/crypto/SelfTest.mc b/source/crypto/SelfTest.mc
index 0d7eae4..87515b6 100644
--- a/source/crypto/SelfTest.mc
+++ b/source/crypto/SelfTest.mc
@@ -54,7 +54,7 @@ module SelfTest {
for (var i = 0; i < 22; i++) {
ikm[i] = 0x0b;
}
- if (!check(Kdf.hkdf(ikm, []b, []b, 42), "8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d9d201395faa4b61a96c8")) { // lint: allow-literal
+ if (!check(Hkdf.derive(ikm, []b, []b, 42), "8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d9d201395faa4b61a96c8")) { // lint: allow-literal
return "HKDF";
}
// RFC 4226 Appendix D, counter 0.
diff --git a/source/crypto/Sha512.mc b/source/crypto/Sha512.mc
index 4248462..37e6607 100644
--- a/source/crypto/Sha512.mc
+++ b/source/crypto/Sha512.mc
@@ -16,6 +16,8 @@
import Toybox.Lang;
+// (:glance): also loaded by the glance, which shows the favourite code (GlanceCode).
+(:glance)
module Sha512 {
// Round constants: the first 64 bits of the fractional parts of the cube