diff --git a/Cargo.lock b/Cargo.lock index 07145eb..9875f52 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,16 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" +[[package]] +name = "aead" +version = "0.6.0-rc.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b657e772794c6b04730ea897b66a058ccd866c16d1967da05eeeecec39043fe" +dependencies = [ + "crypto-common 0.2.1", + "inout", +] + [[package]] name = "aho-corasick" version = "1.1.4" @@ -62,6 +72,12 @@ dependencies = [ "backtrace", ] +[[package]] +name = "base16ct" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd307490d624467aa6f74b0eabb77633d1f758a7b25f12bceb0b22e08d9726f6" + [[package]] name = "base64ct" version = "1.8.3" @@ -89,6 +105,15 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-buffer" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be" +dependencies = [ + "hybrid-array", +] + [[package]] name = "byteorder" version = "1.5.0" @@ -112,9 +137,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.56" +version = "1.2.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" +checksum = "7a0dd1ca384932ff3641c8718a02769f1698e7563dc6974ffd03346116310423" dependencies = [ "find-msvc-tools", "shlex", @@ -126,6 +151,52 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +[[package]] +name = "chacha20" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures 0.3.0", +] + +[[package]] +name = "chacha20poly1305" +version = "0.11.0-rc.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c9ed179664f12fd6f155f6dd632edf5f3806d48c228c67ff78366f2a0eb6b5e" +dependencies = [ + "aead", + "chacha20", + "cipher", + "poly1305", +] + +[[package]] +name = "cipher" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e34d8227fe1ba289043aeb13792056ff80fd6de1a9f49137a5f499de8e8c78ea" +dependencies = [ + "block-buffer 0.12.0", + "crypto-common 0.2.1", + "inout", +] + +[[package]] +name = "cmov" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de0758edba32d61d1fd9f4d69491b47604b91ee2f7e6b33de7e54ca4ebe55dc3" + +[[package]] +name = "const-oid" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" + [[package]] name = "core-foundation" version = "0.10.1" @@ -142,6 +213,12 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "cpubits" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ef0c543070d296ea414df2dd7625d1b24866ce206709d8a4a424f28377f5861" + [[package]] name = "cpufeatures" version = "0.2.17" @@ -151,12 +228,37 @@ dependencies = [ "libc", ] +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + [[package]] name = "critical-section" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" +[[package]] +name = "crypto-bigint" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9b6a7421484856c90cb2e996b91068d608539bb4e6f0a111b16d70678824d09" +dependencies = [ + "cpubits", + "ctutils", + "getrandom", + "hybrid-array", + "num-traits", + "rand_core", + "subtle", + "zeroize", +] + [[package]] name = "crypto-common" version = "0.1.7" @@ -167,6 +269,27 @@ dependencies = [ "typenum", ] +[[package]] +name = "crypto-common" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77727bb15fa921304124b128af125e7e3b968275d1b108b379190264f4423710" +dependencies = [ + "getrandom", + "hybrid-array", + "rand_core", +] + +[[package]] +name = "ctutils" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1005a6d4446f5120ef475ad3d2af2b30c49c2c9c6904258e3bb30219bebed5e4" +dependencies = [ + "cmov", + "subtle", +] + [[package]] name = "darling" version = "0.20.11" @@ -243,6 +366,16 @@ dependencies = [ "thiserror 2.0.18", ] +[[package]] +name = "der" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71fd89660b2dc699704064e59e9dba0147b903e85319429e131620d022be411b" +dependencies = [ + "const-oid", + "zeroize", +] + [[package]] name = "derive_builder" version = "0.20.2" @@ -274,14 +407,38 @@ dependencies = [ "syn", ] +[[package]] +name = "dhkem" +version = "0.1.0-rc.0" +source = "git+https://github.com/RustCrypto/KEMs?rev=2d277162e0c5ed1c53bb315d0c0dace394cba70a#2d277162e0c5ed1c53bb315d0c0dace394cba70a" +dependencies = [ + "elliptic-curve", + "hkdf", + "k256", + "kem", + "rand_core", + "zeroize", +] + [[package]] name = "digest" version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer", - "crypto-common", + "block-buffer 0.10.4", + "crypto-common 0.1.7", +] + +[[package]] +name = "digest" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4850db49bf08e663084f7fb5c87d202ef91a3907271aff24a94eb97ff039153c" +dependencies = [ + "block-buffer 0.12.0", + "crypto-common 0.2.1", + "ctutils", ] [[package]] @@ -293,12 +450,44 @@ dependencies = [ "litrs", ] +[[package]] +name = "ecdsa" +version = "0.17.0-rc.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91bbdd377139884fafcad8dc43a760a3e1e681aa26db910257fa6535b70e1829" +dependencies = [ + "der", + "elliptic-curve", + "signature", + "zeroize", +] + [[package]] name = "either" version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +[[package]] +name = "elliptic-curve" +version = "0.14.0-rc.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e84043d573efd4ac9d2d125817979a379204bf7e328b25a4a30487e8d100e618" +dependencies = [ + "base16ct", + "crypto-bigint", + "crypto-common 0.2.1", + "digest 0.11.2", + "hkdf", + "hybrid-array", + "rand_core", + "rustcrypto-ff", + "rustcrypto-group", + "sec1", + "subtle", + "zeroize", +] + [[package]] name = "embassy-net" version = "0.7.1" @@ -338,9 +527,9 @@ dependencies = [ [[package]] name = "embassy-time" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4fa65b9284d974dad7a23bb72835c4ec85c0b540d86af7fc4098c88cff51d65" +checksum = "592b0c143ec626e821d4d90da51a2bd91d559d6c442b7c74a47d368c9e23d97a" dependencies = [ "cfg-if", "critical-section", @@ -355,9 +544,9 @@ dependencies = [ [[package]] name = "embassy-time-driver" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0a244c7dc22c8d0289379c8d8830cae06bb93d8f990194d0de5efb3b5ae7ba6" +checksum = "6ee71af1b3a0deaa53eaf2d39252f83504c853646e472400b763060389b9fcc9" dependencies = [ "document-features", ] @@ -521,6 +710,7 @@ dependencies = [ "cfg-if", "libc", "r-efi", + "rand_core", "wasip2", "wasip3", ] @@ -609,6 +799,24 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hkdf" +version = "0.13.0-rc.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbb55385998ae66b8d2d5143c05c94b9025ab863966f0c94ce7a5fde30105092" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.13.0-rc.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60017b071c523c9e5a55dd1253582bff6150c5e96a7e8511e419de1ab5ee97f9" +dependencies = [ + "digest 0.11.2", +] + [[package]] name = "home" version = "0.5.12" @@ -618,6 +826,17 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "hybrid-array" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8655f91cd07f2b9d0c24137bd650fe69617773435ee5ec83022377777ce65ef1" +dependencies = [ + "subtle", + "typenum", + "zeroize", +] + [[package]] name = "i2cdev" version = "0.6.2" @@ -654,6 +873,15 @@ dependencies = [ "serde_core", ] +[[package]] +name = "inout" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4250ce6452e92010fdf7268ccc5d14faa80bb12fc741938534c58f16804e03c7" +dependencies = [ + "hybrid-array", +] + [[package]] name = "io-kit-sys" version = "0.4.1" @@ -681,9 +909,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "jiff" @@ -707,6 +935,27 @@ dependencies = [ "syn", ] +[[package]] +name = "k256" +version = "0.14.0-rc.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d2c6c227649d5ec80eaae541f1736232641a0bcdb3062a52b34edb42054158" +dependencies = [ + "cpubits", + "ecdsa", + "elliptic-curve", +] + +[[package]] +name = "kem" +version = "0.3.0-rc.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3ae2c3347ff4a7af4f679a9e397c2c7e6034a00b773dd2dd3c001d7f40897c9" +dependencies = [ + "crypto-common 0.2.1", + "rand_core", +] + [[package]] name = "leb128fmt" version = "0.1.0" @@ -715,9 +964,9 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "libc" -version = "0.2.182" +version = "0.2.183" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" +checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" [[package]] name = "libm" @@ -949,9 +1198,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.21.3" +version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" [[package]] name = "owo-colors" @@ -999,7 +1248,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89815c69d36021a140146f26659a81d6c2afa33d216d736dd4be5381a7362220" dependencies = [ "pest", - "sha2", + "sha2 0.10.9", ] [[package]] @@ -1019,6 +1268,16 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "poly1305" +version = "0.9.0-rc.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19feddcbdf17fad33f40041c7f9e768faf19455f32a6d52ba1b8b65ffc7b1cae" +dependencies = [ + "cpufeatures 0.3.0", + "universal-hash", +] + [[package]] name = "portable-atomic" version = "1.13.1" @@ -1027,9 +1286,9 @@ checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" [[package]] name = "portable-atomic-util" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a9db96d7fa8782dd8c15ce32ffe8680bbd1e978a43bf51a34d39483540495f5" +checksum = "091397be61a01d4be58e7841595bd4bfedb15f1cd54977d79b8271e94ed799a3" dependencies = [ "portable-atomic", ] @@ -1177,6 +1436,12 @@ version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" +[[package]] +name = "rand_core" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba" + [[package]] name = "regex" version = "1.12.3" @@ -1212,6 +1477,27 @@ version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d" +[[package]] +name = "rustcrypto-ff" +version = "0.14.0-rc.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5db129183b2c139d7d87d08be57cba626c715789db17aec65c8866bfd767d1f" +dependencies = [ + "rand_core", + "subtle", +] + +[[package]] +name = "rustcrypto-group" +version = "0.14.0-rc.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c4b1463f274a3ff6fb2f44da43e576cb9424367bd96f185ead87b52fe00523" +dependencies = [ + "rand_core", + "rustcrypto-ff", + "subtle", +] + [[package]] name = "rustix" version = "0.38.44" @@ -1260,6 +1546,17 @@ dependencies = [ "toml_edit", ] +[[package]] +name = "sachy-crypto" +version = "0.1.0" +dependencies = [ + "chacha20poly1305", + "dhkem", + "elliptic-curve", + "k256", + "sha2 0.11.0-rc.5", +] + [[package]] name = "sachy-esphome" version = "0.1.0" @@ -1299,7 +1596,7 @@ dependencies = [ "defmt 1.0.1", "embassy-time", "sachy-fmt", - "winnow", + "winnow 0.7.15", ] [[package]] @@ -1330,6 +1627,20 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "sec1" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46b9a5ab87780a3189a1d704766579517a04ad59de653b7aad7d38e8a15f7dc" +dependencies = [ + "base16ct", + "ctutils", + "der", + "hybrid-array", + "subtle", + "zeroize", +] + [[package]] name = "semver" version = "1.0.27" @@ -1381,9 +1692,9 @@ dependencies = [ [[package]] name = "serialport" -version = "4.7.3" +version = "4.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2acaf3f973e8616d7ceac415f53fc60e190b2a686fbcf8d27d0256c741c5007b" +checksum = "a4d91116f97173694f1642263b2ff837f80d933aa837e2314969f6728f661df3" dependencies = [ "bitflags 2.11.0", "cfg-if", @@ -1394,7 +1705,7 @@ dependencies = [ "nix 0.26.4", "scopeguard", "unescaper", - "winapi", + "windows-sys 0.52.0", ] [[package]] @@ -1404,8 +1715,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", - "cpufeatures", - "digest", + "cpufeatures 0.2.17", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.11.0-rc.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c5f3b1e2dc8aad28310d8410bd4d7e180eca65fca176c52ab00d364475d0024" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "digest 0.11.2", ] [[package]] @@ -1414,6 +1736,15 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "signature" +version = "3.0.0-rc.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f1880df446116126965eeec169136b2e0251dba37c6223bcc819569550edea3" +dependencies = [ + "rand_core", +] + [[package]] name = "smoltcp" version = "0.12.0" @@ -1450,6 +1781,12 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + [[package]] name = "supports-color" version = "3.0.2" @@ -1493,9 +1830,9 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.26.0" +version = "3.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82a72c767771b47409d2345987fda8628641887d5466101319899796367354a0" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" dependencies = [ "fastrand", "getrandom", @@ -1506,12 +1843,12 @@ dependencies = [ [[package]] name = "terminal_size" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b8cb979cb11c32ce1603f8137b22262a9d131aaa5c37b5678025f22b8becd0" +checksum = "230a1b821ccbd75b185820a1f1ff7b14d21da1e442e22c0863ea5f08771a8874" dependencies = [ "rustix 1.1.4", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -1566,40 +1903,40 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "1.0.0+spec-1.1.0" +version = "1.1.0+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32c2555c699578a4f59f0cc68e5116c8d7cabbd45e1409b989d4be085b53f13e" +checksum = "97251a7c317e03ad83774a8752a7e81fb6067740609f75ea2b585b569a59198f" dependencies = [ "serde_core", ] [[package]] name = "toml_edit" -version = "0.25.4+spec-1.1.0" +version = "0.25.8+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7193cbd0ce53dc966037f54351dbbcf0d5a642c7f0038c382ef9e677ce8c13f2" +checksum = "16bff38f1d86c47f9ff0647e6838d7bb362522bdf44006c7068c2b1e606f1f3c" dependencies = [ "indexmap", "toml_datetime", "toml_parser", "toml_writer", - "winnow", + "winnow 1.0.0", ] [[package]] name = "toml_parser" -version = "1.0.9+spec-1.1.0" +version = "1.1.0+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702d4415e08923e7e1ef96cd5727c0dfed80b4d2fa25db9647fe5eb6f7c5a4c4" +checksum = "2334f11ee363607eb04df9b8fc8a13ca1715a72ba8662a26ac285c98aabb4011" dependencies = [ - "winnow", + "winnow 1.0.0", ] [[package]] name = "toml_writer" -version = "1.0.6+spec-1.1.0" +version = "1.1.0+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607" +checksum = "d282ade6016312faf3e41e57ebbba0c073e4056dab1232ab1cb624199648f8ed" [[package]] name = "typenum" @@ -1652,6 +1989,16 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +[[package]] +name = "universal-hash" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4987bdc12753382e0bec4a65c50738ffaabc998b9cdd1f952fb5f39b0048a96" +dependencies = [ + "crypto-common 0.2.1", + "ctutils", +] + [[package]] name = "version_check" version = "0.9.5" @@ -1728,28 +2075,6 @@ dependencies = [ "rustix 0.38.44", ] -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - [[package]] name = "windows-link" version = "0.2.1" @@ -1758,20 +2083,20 @@ checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] name = "windows-sys" -version = "0.59.0" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.6", + "windows-targets", ] [[package]] name = "windows-sys" -version = "0.60.2" +version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets 0.53.5", + "windows-targets", ] [[package]] @@ -1789,31 +2114,14 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.53.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" -dependencies = [ - "windows-link", - "windows_aarch64_gnullvm 0.53.1", - "windows_aarch64_msvc 0.53.1", - "windows_i686_gnu 0.53.1", - "windows_i686_gnullvm 0.53.1", - "windows_i686_msvc 0.53.1", - "windows_x86_64_gnu 0.53.1", - "windows_x86_64_gnullvm 0.53.1", - "windows_x86_64_msvc 0.53.1", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] [[package]] @@ -1822,84 +2130,42 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" - [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" - [[package]] name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" -[[package]] -name = "windows_i686_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" - [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" - [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_i686_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" - [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" -[[package]] -name = "windows_x86_64_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" - [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" - [[package]] name = "windows_x86_64_msvc" version = "0.52.6" @@ -1907,16 +2173,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] -name = "windows_x86_64_msvc" -version = "0.53.1" +name = "winnow" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" [[package]] name = "winnow" -version = "0.7.14" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" +checksum = "a90e88e4667264a994d34e6d1ab2d26d398dcdca8b7f52bec8668957517fc7d8" dependencies = [ "memchr", ] @@ -2009,6 +2275,12 @@ dependencies = [ "wasmparser", ] +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" + [[package]] name = "zmij" version = "1.0.21" diff --git a/Cargo.toml b/Cargo.toml index 80128b7..e3ff66e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ members = [ "sachy-battery", "sachy-bthome", "sachy-config", + "sachy-crypto", "sachy-esphome", "sachy-fmt", "sachy-fnv", @@ -26,3 +27,6 @@ embassy-time = { version = "0.5" } embassy-sync = { version = "0.7" } embassy-net = { version = "0.7" } defmt = { version = "1" } + +[patch.crates-io] +dhkem = { git = "https://github.com/RustCrypto/KEMs", rev = "2d277162e0c5ed1c53bb315d0c0dace394cba70a" } diff --git a/sachy-crypto/Cargo.toml b/sachy-crypto/Cargo.toml new file mode 100644 index 0000000..c0ff474 --- /dev/null +++ b/sachy-crypto/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "sachy-crypto" +authors.workspace = true +edition.workspace = true +repository.workspace = true +license.workspace = true +version.workspace = true +rust-version.workspace = true + +[dependencies] +chacha20poly1305 = { version = "=0.11.0-rc.3", default-features = false, features = ["getrandom", "alloc"] } +k256 = { version = "=0.14.0-rc.8", default-features = false, features = ["ecdh", "getrandom"] } +sha2 = { version = "=0.11.0-rc.5", default-features = false, features = [] } +dhkem = { version = "0.1.0-rc.0", features = ["getrandom", "k256"] } +elliptic-curve = { version = "0.14.0-rc.28", default-features = false, features = ["ecdh"] } diff --git a/sachy-crypto/README.md b/sachy-crypto/README.md new file mode 100644 index 0000000..f5bc735 --- /dev/null +++ b/sachy-crypto/README.md @@ -0,0 +1,5 @@ +# Sachy's Crypto + +A custom rolled encryption scheme that more or less implements HPKE. + +☢️ **WARNING: DO NOT USE IN PRODUCTION. THIS CRATE IS FOR LEARNING/PERSONAL USAGE. AAAAAAAAAA** ☢️ diff --git a/sachy-crypto/src/lib.rs b/sachy-crypto/src/lib.rs new file mode 100644 index 0000000..423b1e1 --- /dev/null +++ b/sachy-crypto/src/lib.rs @@ -0,0 +1,430 @@ +#![no_std] + +use core::ops::{AddAssign, BitXor}; + +use chacha20poly1305::{ + AeadInOut, ChaCha20Poly1305, KeyInit, + aead::{self, Buffer}, +}; +use dhkem::{ + Encapsulate, Kem, Secp256k1DecapsulationKey, Secp256k1EncapsulationKey, Secp256k1Kem, + TryDecapsulate, + kem::{Ciphertext, SharedKey}, +}; +use elliptic_curve::sec1::{FromSec1Point, ToSec1Point}; +use k256::{Sec1Point, ecdh::SharedSecret, elliptic_curve::subtle::ConstantTimeEq}; + +extern crate alloc; + +/// Error type. +/// +/// This type is deliberately opaque as to avoid potential side-channel +/// leakage (e.g. padding oracle). +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct ProtoError; + +impl core::fmt::Display for ProtoError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.write_str("ProtoError") + } +} + +impl core::error::Error for ProtoError {} + +impl From for ProtoError { + fn from(_value: chacha20poly1305::Error) -> Self { + Self + } +} + +pub struct ClientHandshake(Secp256k1DecapsulationKey); + +pub struct EncapsulatedPublicKey(Secp256k1EncapsulationKey); + +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub enum Role { + Client, + Server, +} + +impl From for u8 { + fn from(value: Role) -> Self { + match value { + Role::Client => 0, + Role::Server => 1, + } + } +} + +impl BitXor for Role { + type Output = u8; + + fn bitxor(self, rhs: Self) -> u8 { + u8::from(self) ^ u8::from(rhs) + } +} + +impl EncapsulatedPublicKey { + pub fn serialize(&self) -> Sec1Point { + self.0.to_sec1_point(true) + } + + pub fn deserialize(buf: &[u8]) -> Result { + Ok(Self( + Secp256k1EncapsulationKey::from_sec1_bytes(buf).map_err(|_| ProtoError)?, + )) + } + + pub fn encapsulate(&self) -> (Ciphertext, SharedKey) { + self.0.encapsulate() + } +} + +impl ClientHandshake { + pub fn send() -> (EncapsulatedPublicKey, Self) { + let (decap, encap) = Secp256k1Kem::generate_keypair(); + + (EncapsulatedPublicKey(encap), Self(decap)) + } + + pub fn finish(self, ciphertext: &[u8], psk: &[u8; 32]) -> Result { + let shared = self + .0 + .try_decapsulate_slice(ciphertext) + .map_err(|_| ProtoError)?; + + TransportState::init(psk, shared, Role::Client) + } +} + +pub struct ServerHandshake(SharedKey); + +impl ServerHandshake { + pub fn receive(buf: &[u8]) -> Result<(Ciphertext, Self), ProtoError> { + let encap = EncapsulatedPublicKey::deserialize(buf)?; + + let (ciphertext, sk) = encap.encapsulate(); + + Ok((ciphertext, Self(sk))) + } + + pub fn finish(self, psk: &[u8; 32]) -> Result { + TransportState::init(psk, self.0, Role::Server) + } +} + +/// Low-level Transport implementation. +/// +/// This trait provides a particular "flavor" of transport, as there are +/// different ways the specifics of the construction can be implemented. +pub trait TransportPrimitive +where + A: AeadInOut, +{ + /// Type used as the Trasnport counter. + type Counter: AddAssign + Copy + Default + Eq; + + /// Value to use when incrementing the Transport counter (i.e. one) + const COUNTER_INCR: Self::Counter; + + /// Maximum number of messages allowed to be sent via Transport + const COUNTER_MAX: Self::Counter; + + /// Encrypt an AEAD message in-place at the given position in the Transport. + fn encrypt_in_place( + &self, + nonce: &aead::Nonce, + associated_data: &[u8], + buffer: &mut dyn Buffer, + ) -> Result<(), ProtoError>; + + /// Decrypt an AEAD message in-place at the given position in the Transport. + fn decrypt_in_place( + &self, + nonce: &aead::Nonce, + associated_data: &[u8], + buffer: &mut dyn Buffer, + ) -> Result<(), ProtoError>; +} + +pub struct SendingState<'a> { + transport: &'a TransportState, + counter: u64, +} + +impl SendingState<'_> { + pub fn encrypt(&mut self, msg: &mut alloc::vec::Vec) -> Result<(), ProtoError> { + let counter = self.counter.to_be_bytes(); + + self.transport.encrypt_in_place( + &self.transport.mix_nonce(&counter, Role::Client), + &counter, + msg, + )?; + + self.counter = self.counter.wrapping_add(TransportState::COUNTER_INCR); + + // If we wrapped around and equal the finish value, we have maxed out the amount of + // messages we can send. + if self.counter.ct_eq(&TransportState::COUNTER_MAX).into() { + Err(ProtoError) + } else { + Ok(()) + } + } +} + +pub struct ReceivingState<'a> { + transport: &'a TransportState, + counter: u64, +} + +impl ReceivingState<'_> { + pub fn decrypt(&mut self, msg: &mut alloc::vec::Vec) -> Result<(), ProtoError> { + let counter = self.counter.to_be_bytes(); + + self.transport.decrypt_in_place( + &self.transport.mix_nonce(&counter, Role::Server), + &counter, + msg, + )?; + + self.counter = self.counter.wrapping_add(TransportState::COUNTER_INCR); + + // If we wrapped around and equal the finish value, we have maxed out the amount of + // messages we can send. + if self.counter.ct_eq(&TransportState::COUNTER_MAX).into() { + Err(ProtoError) + } else { + Ok(()) + } + } +} + +impl TransportPrimitive for TransportState { + type Counter = u64; + + const COUNTER_INCR: Self::Counter = 1; + + const COUNTER_MAX: Self::Counter = u64::MAX; + + fn encrypt_in_place( + &self, + epstein: &aead::Nonce, + associated_data: &[u8], + buffer: &mut dyn Buffer, + ) -> Result<(), ProtoError> { + self.aead + .encrypt_in_place(epstein, associated_data, buffer)?; + Ok(()) + } + + fn decrypt_in_place( + &self, + epstein: &aead::Nonce, + associated_data: &[u8], + buffer: &mut dyn Buffer, + ) -> Result<(), ProtoError> { + self.aead + .decrypt_in_place(epstein, associated_data, buffer)?; + Ok(()) + } +} + +#[repr(align(4))] +pub struct TransportState { + aead: ChaCha20Poly1305, + first: aead::Nonce, + second: aead::Nonce, + role: Role, +} + +impl TransportState { + pub fn init( + psk: &[u8; 32], + shared: impl Into, + role: Role, + ) -> Result { + let noncer = shared.into(); + let kdf = noncer.extract::(Some(psk)); + + let mut key = [0u8; 32]; + + let mut first = aead::Nonce::::default(); + let mut second = aead::Nonce::::default(); + + kdf.expand(b"SachY-Crypt0", &mut key) + .map_err(|_| ProtoError)?; + + kdf.expand(b"N*nceOne", &mut first) + .map_err(|_| ProtoError)?; + kdf.expand(b"N#nceTwo", &mut second) + .map_err(|_| ProtoError)?; + + Ok(Self { + aead: ChaCha20Poly1305::new(&key.into()), + first, + second, + role, + }) + } + + pub fn split(&self) -> (SendingState<'_>, ReceivingState<'_>) { + ( + SendingState { + transport: self, + counter: 0, + }, + ReceivingState { + transport: self, + counter: 0, + }, + ) + } + + fn mix_nonce(&self, position: &[u8; 8], send: Role) -> aead::Nonce { + let mut trump = aead::Nonce::::default(); + + let context_select = self.role ^ send; + + // Role switch allows toggling which nonce to use for encrypting/decrypting + // Callee ROLE XOR Transport ROLE selects either one or other nonce context, + // (0) for first context, (1) for second context + // Sending: Client ^ Client = 0 (select first) + // Receiving: Server ^ Server = 0 (select first) + // Sending: Server ^ Client = 1 (select second) + // Receiving: Client ^ Server = 1 (select second) + let epstein = if context_select.ct_eq(&0).into() { + &self.first + } else { + &self.second + }; + + let (head, tail) = trump.split_at_mut(position.len()); + let (first, second) = epstein.split_at(position.len()); + + // XOR the base nonce with position bytes, copying them to the output nonce + head.iter_mut() + .zip(first) + .zip(position) + .for_each(|((head, ep), pos)| *head = ep ^ pos); + + // Copy rest of base nonce into output nonce + tail.iter_mut() + .zip(second) + .for_each(|(tail, ep)| *tail = *ep); + + trump + } +} + +#[cfg(test)] +mod tests { + use alloc::vec; + use dhkem::Generate; + use elliptic_curve::array::Array; + + use super::*; + + #[test] + fn handshake_protocol_works() -> Result<(), ProtoError> { + let psk: [u8; 32] = [ + 31, 48, 29, 177, 88, 236, 186, 84, 65, 51, 214, 243, 174, 24, 45, 101, 229, 129, 62, + 132, 45, 174, 183, 65, 89, 73, 107, 177, 77, 90, 164, 251, + ]; + + let (ek, client) = ClientHandshake::send(); + + // Pretend to send ek across the webz: client -> server + let (ciphertext, server) = ServerHandshake::receive(ek.serialize().as_bytes())?; + + // Pretend to send ciphertext across the webz: server -> client + let alice = client.finish(&ciphertext, &psk)?; + let bob = server.finish(&psk)?; + + let nonce = aead::Nonce::::generate(); + + let mut buffer1 = vec![0u8; 64]; + let mut buffer2 = vec![0u8; 64]; + + // Using the same nonce to check that the internal AEAD states match. Normally, client/server + // would work with unique derived nonces, because nonce reuse is BAD + alice.aead.encrypt_in_place(&nonce, &[], &mut buffer1)?; + bob.aead.encrypt_in_place(&nonce, &[], &mut buffer2)?; + + // If the nonces match, then we can assume the rest of the internal state is the same too + // so the outputs should match each other + assert_eq!(&buffer1, &buffer2); + + // Both Transports have derived base nonces for each context. + // First context nonces will not match Second context nonces. + assert_eq!(alice.first, bob.first); + assert_eq!(alice.second, bob.second); + assert_ne!(alice.first, alice.second); + assert_ne!(bob.first, bob.second); + + Ok(()) + } + + #[test] + fn two_way_transport_sync_works() -> Result<(), ProtoError> { + let shared_secret = [ + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, + 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, + 0x9c, 0x9d, 0x9e, 0x9f, + ]; + + let psk: [u8; 32] = [ + 31, 48, 29, 177, 88, 236, 186, 84, 65, 51, 214, 243, 174, 24, 45, 101, 229, 129, 62, + 132, 45, 174, 183, 65, 89, 73, 107, 177, 77, 90, 164, 251, + ]; + + let alice = TransportState::init(&psk, Array(shared_secret), Role::Client)?; + let bob = TransportState::init(&psk, Array(shared_secret), Role::Server)?; + + let (mut alice_send, mut alice_recv) = alice.split(); + let (mut bob_send, mut bob_recv) = bob.split(); + + let orig = b"Test Message, Please ignore."; + + let mut msg = orig.to_vec(); + + // a -> b + alice_send.encrypt(&mut msg)?; + + assert_ne!(orig.as_slice(), msg.as_slice()); + let ct1 = msg.clone(); + + bob_recv.decrypt(&mut msg)?; + + // a -> b + alice_send.encrypt(&mut msg)?; + + assert_ne!(msg.as_slice(), ct1.as_slice()); + let ct2 = msg.clone(); + + bob_recv.decrypt(&mut msg)?; + + // b -> a + bob_send.encrypt(&mut msg)?; + + // None of the ciphertexts should match each other + assert_ne!(msg.as_slice(), ct1.as_slice()); + assert_ne!(msg.as_slice(), ct2.as_slice()); + assert_ne!(ct1.as_slice(), ct2.as_slice()); + + alice_recv.decrypt(&mut msg)?; + + assert_eq!(orig.as_slice(), msg.as_slice()); + + // Counters are tracked from sender to receiver + assert_eq!(alice_send.counter, bob_recv.counter); + assert_eq!(bob_send.counter, alice_recv.counter); + + // Counters are not linked on the same side + assert_ne!(alice_send.counter, alice_recv.counter); + assert_ne!(bob_send.counter, bob_recv.counter); + + Ok(()) + } +}