summaryrefslogtreecommitdiff
path: root/source/crypto/Hashes.mc
diff options
context:
space:
mode:
authorcirakg <cirakg@cirakg.xyz>2026-10-18 23:44:18 +0200
committercirakg <cirakg@cirakg.xyz>2026-10-18 23:44:18 +0200
commite47ae684101981a7c20f3270994a61944059c825 (patch)
treec2baab8baafa1be446dad7f224f1a1cf68493825 /source/crypto/Hashes.mc
parentb70cde45b67e1f6bb65d598d25c1a5184bdab520 (diff)
feat(crypto): add SHA-512, HMAC, PBKDF2, HKDF, AES-256 records and self-test
- Sha512: FIPS 180-4 in Monkey C (no native SHA-512), rotations inlined with precomputed masks; constants derived from the primes, not typed. - Hmac: RFC 2104 over SHA-1/256/512 (native HMAC only supports SHA-256). - Kdf: resumable PBKDF2-HMAC-SHA256 job with calibration bounds (2,000-200,000 iterations) and HKDF-SHA256. - Aes: CBC with PKCS#7 over the native cipher; AES-256 chosen. - SealedBox: encrypt-then-MAC records (HKDF-split keys, length-prefixed aad, constant-time tag check before decryption). - SelfTest: known-answer tests for every primitive at start-up. - Bytes (wipe, constant-time equal), Clock (2038-safe widening, trusted clock), Jobs (bounded steps against the watchdog, timer runner). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'source/crypto/Hashes.mc')
-rw-r--r--source/crypto/Hashes.mc54
1 files changed, 54 insertions, 0 deletions
diff --git a/source/crypto/Hashes.mc b/source/crypto/Hashes.mc
new file mode 100644
index 0000000..14e2cf2
--- /dev/null
+++ b/source/crypto/Hashes.mc
@@ -0,0 +1,54 @@
+// Author: cirakg & claude ai
+// Summary: One interface over SHA-1, SHA-256 (native) and SHA-512 (pure Monkey C).
+//
+// Connect IQ has native SHA-1 and SHA-256 (Toybox.Cryptography.Hash) but no
+// SHA-512, which source/crypto/Sha512.mc implements from FIPS 180-4. OTP code
+// asks for an algorithm by its Hashes.Algorithm value and doesn't care which
+// implementation answers.
+
+import Toybox.Cryptography;
+import Toybox.Lang;
+
+module Hashes {
+
+ // OTP and HMAC hash algorithms. The values are stored in entry records, so
+ // never renumber them.
+ enum Algorithm {
+ SHA1 = 0,
+ SHA256 = 1,
+ SHA512 = 2
+ }
+
+ // Input block size in bytes (what HMAC pads its key to).
+ function blockSize(alg as Algorithm) as Number {
+ return alg == SHA512 ? 128 : 64;
+ }
+
+ // Digest length in bytes.
+ function digestSize(alg as Algorithm) as Number {
+ if (alg == SHA1) {
+ return 20;
+ }
+ return alg == SHA256 ? 32 : 64;
+ }
+
+ // True for the three supported values (input from settings or imports is
+ // checked with this before it becomes an Algorithm).
+ function isValid(value as Number) as Boolean {
+ return value == SHA1 || value == SHA256 || value == SHA512;
+ }
+
+ // The digest of data.
+ function digest(alg as Algorithm, data as ByteArray) as ByteArray {
+ if (alg == SHA512) {
+ return Sha512.digest(data);
+ }
+ var hash = new Cryptography.Hash({
+ :algorithm => alg == SHA1 ? Cryptography.HASH_SHA1 : Cryptography.HASH_SHA256
+ });
+ if (data.size() > 0) {
+ hash.update(data);
+ }
+ return hash.digest();
+ }
+}