diff options
| author | cirakg <cirakg@cirakg.xyz> | 2026-10-18 23:44:18 +0200 |
|---|---|---|
| committer | cirakg <cirakg@cirakg.xyz> | 2026-10-18 23:44:18 +0200 |
| commit | e47ae684101981a7c20f3270994a61944059c825 (patch) | |
| tree | c2baab8baafa1be446dad7f224f1a1cf68493825 /source/crypto/Hashes.mc | |
| parent | b70cde45b67e1f6bb65d598d25c1a5184bdab520 (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.mc | 54 |
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(); + } +} |
