From d8c9e9b36c09aff16095d137fa9ffb7aad8355c7 Mon Sep 17 00:00:00 2001 From: satvrn Date: Tue, 18 Jul 2023 23:27:53 +0000 Subject: [PATCH] reinstate repo with source from crates.io --- Cargo.lock | 1109 ------------------------------- Cargo.toml | 39 +- LICENSE | 1 + README.md | 164 +++-- README.tpl | 13 - benches/double_ratchet_bench.rs | 98 +-- deny.toml | 204 ------ src/aead.rs | 56 +- src/dh.rs | 53 +- src/header.rs | 148 ++--- src/kdf_chain.rs | 22 +- src/kdf_root.rs | 22 +- src/lib.rs | 172 +++-- src/ratchet.rs | 353 +++++----- tests/mod.rs | 126 ++-- 15 files changed, 632 insertions(+), 1948 deletions(-) delete mode 100644 Cargo.lock delete mode 100644 README.tpl delete mode 100644 deny.toml diff --git a/Cargo.lock b/Cargo.lock deleted file mode 100644 index df11093..0000000 --- a/Cargo.lock +++ /dev/null @@ -1,1109 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "aead" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877" -dependencies = [ - "generic-array", -] - -[[package]] -name = "aes" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" -dependencies = [ - "cfg-if", - "cipher", - "cpufeatures", - "opaque-debug", -] - -[[package]] -name = "aes-gcm-siv" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589c637f0e68c877bbd59a4599bbe849cac8e5f3e4b5a3ebae8f528cd218dcdc" -dependencies = [ - "aead", - "aes", - "cipher", - "ctr", - "polyval", - "subtle", - "zeroize", -] - -[[package]] -name = "ahash" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "464b3811b747f8f7ebc8849c9c728c39f6ac98a055edad93baf9eb330e3f8f9d" -dependencies = [ - "cfg-if", - "getrandom", - "once_cell", - "version_check", -] - -[[package]] -name = "anes" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" - -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi", - "libc", - "winapi", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "base16ct" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" - -[[package]] -name = "base64ct" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6b4d9b1225d28d360ec6a231d65af1fd99a2a095154c8040689617290569c5c" - -[[package]] -name = "bincode" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" -dependencies = [ - "serde", -] - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "block-buffer" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" -dependencies = [ - "generic-array", -] - -[[package]] -name = "block-buffer" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" -dependencies = [ - "generic-array", -] - -[[package]] -name = "bumpalo" -version = "3.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" - -[[package]] -name = "cast" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "ciborium" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c137568cc60b904a7724001b35ce2630fd00d5d84805fbb608ab89509d788f" -dependencies = [ - "ciborium-io", - "ciborium-ll", - "serde", -] - -[[package]] -name = "ciborium-io" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "346de753af073cc87b52b2083a506b38ac176a44cfb05497b622e27be899b369" - -[[package]] -name = "ciborium-ll" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213030a2b5a4e0c0892b6652260cf6ccac84827b83a85a534e178e3906c4cf1b" -dependencies = [ - "ciborium-io", - "half", -] - -[[package]] -name = "cipher" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" -dependencies = [ - "generic-array", -] - -[[package]] -name = "clap" -version = "3.2.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b71c3ce99b7611011217b366d923f1d0a7e07a92bb2dbf1e84508c673ca3bd" -dependencies = [ - "bitflags", - "clap_lex", - "indexmap", - "textwrap", -] - -[[package]] -name = "clap_lex" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" -dependencies = [ - "os_str_bytes", -] - -[[package]] -name = "const-oid" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3" - -[[package]] -name = "cpufeatures" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" -dependencies = [ - "libc", -] - -[[package]] -name = "criterion" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7c76e09c1aae2bc52b3d2f29e13c6572553b30c4aa1b8a49fd70de6412654cb" -dependencies = [ - "anes", - "atty", - "cast", - "ciborium", - "clap", - "criterion-plot", - "itertools", - "lazy_static", - "num-traits", - "oorandom", - "plotters", - "rayon", - "regex", - "serde", - "serde_derive", - "serde_json", - "tinytemplate", - "walkdir", -] - -[[package]] -name = "criterion-plot" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" -dependencies = [ - "cast", - "itertools", -] - -[[package]] -name = "crossbeam-channel" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c02a4d71819009c192cf4872265391563fd6a84c81ff2c0f2a7026ca4c1d85c" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" -dependencies = [ - "cfg-if", - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07db9d94cbd326813772c968ccd25999e5f8ae22f4f8d1b11effa37ef6ce281d" -dependencies = [ - "autocfg", - "cfg-if", - "crossbeam-utils", - "memoffset", - "once_cell", - "scopeguard", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d82ee10ce34d7bc12c2122495e7593a9c41347ecdd64185af4ecf72cb1a7f83" -dependencies = [ - "cfg-if", - "once_cell", -] - -[[package]] -name = "crypto-bigint" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c6a1d5fa1de37e071642dfa44ec552ca5b299adb128fab16138e24b548fd21" -dependencies = [ - "generic-array", - "rand_core", - "subtle", - "zeroize", -] - -[[package]] -name = "crypto-common" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ccfd8c0ee4cce11e45b3fd6f9d5e69e0cc62912aa6a0cb1bf4617b0eba5a12f" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "crypto-mac" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" -dependencies = [ - "generic-array", - "subtle", -] - -[[package]] -name = "ctr" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea" -dependencies = [ - "cipher", -] - -[[package]] -name = "der" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6919815d73839e7ad218de758883aae3a257ba6759ce7a9992501efbb53d705c" -dependencies = [ - "const-oid", - "pem-rfc7468", -] - -[[package]] -name = "digest" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" -dependencies = [ - "generic-array", -] - -[[package]] -name = "digest" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" -dependencies = [ - "block-buffer 0.10.2", - "crypto-common", - "subtle", -] - -[[package]] -name = "double-ratchet-2" -version = "0.3.7" -dependencies = [ - "aes-gcm-siv", - "bincode", - "criterion", - "getrandom", - "hashbrown 0.13.1", - "hkdf", - "hmac 0.12.1", - "p256", - "rand_core", - "serde", - "serde_bytes", - "sha2 0.10.5", - "zeroize", -] - -[[package]] -name = "ecdsa" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0d69ae62e0ce582d56380743515fefaf1a8c70cec685d9677636d7e30ae9dc9" -dependencies = [ - "der", - "elliptic-curve", - "rfc6979", - "signature", -] - -[[package]] -name = "either" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f107b87b6afc2a64fd13cac55fe06d6c8859f12d4b14cbcdd2c67d0976781be" - -[[package]] -name = "elliptic-curve" -version = "0.11.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25b477563c2bfed38a3b7a60964c49e058b2510ad3f12ba3483fd8f62c2306d6" -dependencies = [ - "base16ct", - "base64ct", - "crypto-bigint", - "der", - "ff", - "generic-array", - "group", - "pem-rfc7468", - "rand_core", - "sec1", - "serde", - "serde_json", - "subtle", - "zeroize", -] - -[[package]] -name = "ff" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "131655483be284720a17d74ff97592b8e76576dc25563148601df2d7c9080924" -dependencies = [ - "rand_core", - "subtle", -] - -[[package]] -name = "generic-array" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "wasi", - "wasm-bindgen", -] - -[[package]] -name = "group" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5ac374b108929de78460075f3dc439fa66df9d8fc77e8f12caa5165fcf0c89" -dependencies = [ - "ff", - "rand_core", - "subtle", -] - -[[package]] -name = "half" -version = "1.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "hashbrown" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ff8ae62cd3a9102e5637afc8452c55acf3844001bd5374e0b0bd7b6616c038" -dependencies = [ - "ahash", - "serde", -] - -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - -[[package]] -name = "hkdf" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" -dependencies = [ - "hmac 0.12.1", -] - -[[package]] -name = "hmac" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" -dependencies = [ - "crypto-mac", - "digest 0.9.0", -] - -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest 0.10.3", -] - -[[package]] -name = "indexmap" -version = "1.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", -] - -[[package]] -name = "itertools" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" - -[[package]] -name = "js-sys" -version = "0.3.58" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3fac17f7123a73ca62df411b1bf727ccc805daa070338fda671c86dac1bdc27" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.126" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" - -[[package]] -name = "log" -version = "0.4.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "memoffset" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num-traits" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_cpus" -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "once_cell" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" - -[[package]] -name = "oorandom" -version = "11.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" - -[[package]] -name = "opaque-debug" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" - -[[package]] -name = "os_str_bytes" -version = "6.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ff7415e9ae3fff1225851df9e0d9e4e5479f947619774677a63572e55e80eff" - -[[package]] -name = "p256" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19736d80675fbe9fe33426268150b951a3fb8f5cfca2a23a17c85ef3adb24e3b" -dependencies = [ - "ecdsa", - "elliptic-curve", - "sec1", - "sha2 0.9.9", -] - -[[package]] -name = "pem-rfc7468" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01de5d978f34aa4b2296576379fcc416034702fd94117c56ffd8a1a767cefb30" -dependencies = [ - "base64ct", -] - -[[package]] -name = "pkcs8" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cabda3fb821068a9a4fab19a683eac3af12edf0f34b94a8be53c4972b8149d0" -dependencies = [ - "der", - "spki", - "zeroize", -] - -[[package]] -name = "plotters" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9428003b84df1496fb9d6eeee9c5f8145cb41ca375eb0dad204328888832811f" -dependencies = [ - "num-traits", - "plotters-backend", - "plotters-svg", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "plotters-backend" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "193228616381fecdc1224c62e96946dfbc73ff4384fba576e052ff8c1bea8142" - -[[package]] -name = "plotters-svg" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0918736323d1baff32ee0eade54984f6f201ad7e97d5cfb5d6ab4a358529615" -dependencies = [ - "plotters-backend", -] - -[[package]] -name = "polyval" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1" -dependencies = [ - "cfg-if", - "cpufeatures", - "opaque-debug", - "universal-hash", -] - -[[package]] -name = "proc-macro2" -version = "1.0.47" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand_core" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" -dependencies = [ - "getrandom", -] - -[[package]] -name = "rayon" -version = "1.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d" -dependencies = [ - "autocfg", - "crossbeam-deque", - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f" -dependencies = [ - "crossbeam-channel", - "crossbeam-deque", - "crossbeam-utils", - "num_cpus", -] - -[[package]] -name = "regex" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" -dependencies = [ - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.6.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" - -[[package]] -name = "rfc6979" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96ef608575f6392792f9ecf7890c00086591d29a83910939d430753f7c050525" -dependencies = [ - "crypto-bigint", - "hmac 0.11.0", - "zeroize", -] - -[[package]] -name = "ryu" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "sec1" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08da66b8b0965a5555b6bd6639e68ccba85e1e2506f5fbb089e93f8a04e1a2d1" -dependencies = [ - "der", - "generic-array", - "pkcs8", - "subtle", - "zeroize", -] - -[[package]] -name = "serde" -version = "1.0.149" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "256b9932320c590e707b94576e3cc1f7c9024d0ee6612dfbcf1cb106cbe8e055" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_bytes" -version = "0.11.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfc50e8183eeeb6178dcb167ae34a8051d63535023ae38b5d8d12beae193d37b" -dependencies = [ - "serde", -] - -[[package]] -name = "serde_derive" -version = "1.0.149" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4eae9b04cbffdfd550eb462ed33bc6a1b68c935127d008b27444d08380f94e4" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.82" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "sha2" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" -dependencies = [ - "block-buffer 0.9.0", - "cfg-if", - "cpufeatures", - "digest 0.9.0", - "opaque-debug", -] - -[[package]] -name = "sha2" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9db03534dff993187064c4e0c05a5708d2a9728ace9a8959b77bedf415dac5" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest 0.10.3", -] - -[[package]] -name = "signature" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2807892cfa58e081aa1f1111391c7a0649d4fa127a4ffbe34bcbfb35a1171a4" -dependencies = [ - "digest 0.9.0", - "rand_core", -] - -[[package]] -name = "spki" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d01ac02a6ccf3e07db148d2be087da624fea0221a16152ed01f0496a6b0a27" -dependencies = [ - "base64ct", - "der", -] - -[[package]] -name = "subtle" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" - -[[package]] -name = "syn" -version = "1.0.105" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b9b43d45702de4c839cb9b51d9f529c5dd26a4aff255b42b1ebc03e88ee908" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "synstructure" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "unicode-xid", -] - -[[package]] -name = "textwrap" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" - -[[package]] -name = "tinytemplate" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" -dependencies = [ - "serde", - "serde_json", -] - -[[package]] -name = "typenum" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" - -[[package]] -name = "unicode-ident" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" - -[[package]] -name = "unicode-xid" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" - -[[package]] -name = "universal-hash" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" -dependencies = [ - "generic-array", - "subtle", -] - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "walkdir" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" -dependencies = [ - "same-file", - "winapi", - "winapi-util", -] - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasm-bindgen" -version = "0.2.81" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c53b543413a17a202f4be280a7e5c62a1c69345f5de525ee64f8cfdbc954994" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.81" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5491a68ab4500fa6b4d726bd67408630c3dbe9c4fe7bda16d5c82a1fd8c7340a" -dependencies = [ - "bumpalo", - "lazy_static", - "log", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.81" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c441e177922bc58f1e12c022624b6216378e5febc2f0533e41ba443d505b80aa" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.81" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d94ac45fcf608c1f45ef53e748d35660f168490c10b23704c7779ab8f5c3048" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.81" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a89911bd99e5f3659ec4acf9c4d93b0a90fe4a2a11f15328472058edc5261be" - -[[package]] -name = "web-sys" -version = "0.3.58" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fed94beee57daf8dd7d51f2b15dc2bcde92d7a72304cdf662a4371008b71b90" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[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-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - -[[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 = "zeroize" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd" -dependencies = [ - "zeroize_derive", -] - -[[package]] -name = "zeroize_derive" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f8f187641dad4f680d25c4bfc4225b418165984179f26ca76ec4fb6441d3a17" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] diff --git a/Cargo.toml b/Cargo.toml index abe2f16..90b64a9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,37 +1,29 @@ [package] -name = "double-ratchet-2" -authors = ["Hannes Furmans"] -description = "Implementation of Double Ratchet as specified by Signal." -homepage = "https://github.com/Dione-Software/double-ratchet-2" -repository = "https://github.com/Dione-Software/double-ratchet-2" +name = "double-ratchet-rs" +authors = ["Magnetite Contributors", "Hannes Furmans"] +description = "A pure Rust implementation of the Double Ratchet Algorithm as specified by Signal." +homepage = "https://github.com/magnetite-dev/double-ratchet-rs" +repository = "https://github.com/magnetite-dev/double-ratchet-rs" readme = "README.md" keywords = ["double-ratchet", "crypto", "cryptography", "signal"] -version = "0.3.7" -edition = "2018" +version = "0.4.3" +edition = "2021" license = "MIT" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[badges] -maintenance = { status = "actively-developed" } - - [dependencies] -p256 = {version = "0.10", features = ["ecdh", "arithmetic", "pem", "jwk"]} -rand_core = {version = "0.6"} -getrandom = {version = "0.2.3"} +x25519-dalek = {version = "2.0.0-pre.1", default-features = false, features = ["serde", "u64_backend"]} +rand_core = "0.6" hkdf = "0.12" hmac = "0.12" -aes-gcm-siv = {version = "0.10.3"} -sha2 = {version = "0.10"} +aes-gcm-siv = "0.11" +sha2 = {version = "0.10", default-features = false} serde = {version = "1", default-features = false, features = ["derive"]} -serde_bytes = "0.11" -bincode = "1" +postcard = {version = "1", default-features = false, features = ["alloc"]} hashbrown = {version = "0.13", features = ["serde"]} -zeroize = {version = "1.3", features = ["zeroize_derive"]} +zeroize = {version = "1.5", default-features = false, features = ["zeroize_derive"]} [dev-dependencies] -criterion = "0.4.0" +criterion = "0.4" [[bench]] name = "double_ratchet_bench" @@ -39,6 +31,3 @@ harness = false [profile.release] lto = true - -[features] -wasm = ["getrandom/js"] diff --git a/LICENSE b/LICENSE index db55f40..f6e6c0e 100644 --- a/LICENSE +++ b/LICENSE @@ -1,5 +1,6 @@ MIT License +Copyright (c) 2022 Magnetite Contributors Copyright (c) 2021 Hannes Furmans Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/README.md b/README.md index 0e9e973..2e83b87 100644 --- a/README.md +++ b/README.md @@ -1,71 +1,92 @@ -[![Crate](https://img.shields.io/crates/v/double-ratchet-2)](https://crates.io/crates/double-ratchet-2) -[![License](https://img.shields.io/github/license/Dione-Software/double-ratchet-2)](https://github.com/Dione-Software/double-ratchet-2/blob/main/LICENSE) -[![Coverage Status](https://coveralls.io/repos/github/Dione-Software/double-ratchet-2/badge.svg?branch=main)](https://coveralls.io/github/Dione-Software/double-ratchet-2?branch=main) -[![Workflow Status](https://github.com/Dione-Software/double-ratchet-2/actions/workflows/rust.yml/badge.svg)](https://github.com/Dione-Software/double-ratchet-2/actions/workflows/rust.yml) -![Maintenance](https://img.shields.io/badge/maintenance-activly--developed-brightgreen.svg) +[![Crate](https://img.shields.io/crates/v/double-ratchet-rs)](https://crates.io/crates/double-ratchet-rs) +[![License](https://img.shields.io/github/license/magnetite-dev/double-ratchet-rs)](https://github.com/magnetite-dev/double-ratchet-rs/blob/main/LICENSE) +[![Coverage Status](https://coveralls.io/repos/github/magnetite-dev/double-ratchet-rs/badge.svg?branch=main)](https://coveralls.io/github/magnetite-dev/double-ratchet-rs?branch=main) +[![Workflow Status](https://github.com/magnetite-dev/double-ratchet-rs/actions/workflows/rust.yml/badge.svg)](https://github.com/magnetite-dev/double-ratchet-rs/actions/workflows/rust.yml) -# double-ratchet-2 +# double-ratchet-rs -Implementation of the double ratchet system/encryption as specified by [Signal][1]. +A pure Rust implementation of the Double Ratchet Algorithm as specified by [Signal][1]. -**WARNING! This implementation uses P-256 NOT Curve25519 as specified by Signal!** - -The implementation follows the cryptographic recommendations provided by [Signal][2]. +This implementation follows the cryptographic recommendations provided by [Signal][2]. The AEAD Algorithm uses a constant Nonce. This might be changed in the future. -## Example Usage: +Fork of [double-ratchet-2](https://github.com/Dione-Software/double-ratchet-2). + +## Examples + +### Standard Usage + +Alice encrypts a message which is then decrypted by Bob. -### Standard: ```rust -use double_ratchet_2::ratchet::Ratchet; +use double_ratchet_rs::Ratchet; -let sk = [1; 32]; // Initial Key created by a symmetric key agreement protocol -let (mut bob_ratchet, public_key) = Ratchet::init_bob(sk); // Creating Bobs Ratchet (returns Bobs PublicKey) -let mut alice_ratchet = Ratchet::init_alice(sk, public_key); // Creating Alice Ratchet with Bobs PublicKey -let data = b"Hello World".to_vec(); // Data to be encrypted -let ad = b"Associated Data"; // Associated Data +let sk = [1; 32]; // Shared key created by a symmetric key agreement protocol + +let (mut bob_ratchet, public_key) = Ratchet::init_bob(sk); // Creating Bob's Ratchet (returns Bob's PublicKey) +let mut alice_ratchet = Ratchet::init_alice(sk, public_key); // Creating Alice's Ratchet with Bob's PublicKey + +let data = b"Hello World".to_vec(); // Data to be encrypted +let ad = b"Associated Data"; // Associated data + +let (header, encrypted, nonce) = alice_ratchet.encrypt(&data, ad); // Encrypting message with Alice's Ratchet (Alice always needs to send the first message) +let decrypted = bob_ratchet.decrypt(&header, &encrypted, &nonce, ad); // Decrypt message with Bob's Ratchet -let (header, encrypted, nonce) = alice_ratchet.ratchet_encrypt(&data, ad); // Encrypting message with Alice Ratchet (Alice always needs to send the first message) -let decrypted = bob_ratchet.ratchet_decrypt(&header, &encrypted, &nonce, ad); // Decrypt message with Bobs Ratchet assert_eq!(data, decrypted) ``` -### With lost message: +### Recovering a Lost Message + +Alice encrypts 2 messages for Bob. +The latest message must be decrypted first. + ```rust +use double_ratchet_rs::Ratchet; -let sk = [1; 32]; // Initial Key created by a symmetric key agreement protocol -let (mut bob_ratchet, public_key) = Ratchet::init_bob(sk); // Creating Bobs Ratchet (returns Bobs PublicKey) -let mut alice_ratchet = Ratchet::init_alice(sk, public_key); // Creating Alice Ratchet with Bobs PublicKey -let data = b"Hello World".to_vec(); // Data to be encrypted -let ad = b"Associated Data"; // Associated Data +let sk = [1; 32]; // Shared key created by a symmetric key agreement protocol -let (header1, encrypted1, nonce1) = alice_ratchet.ratchet_encrypt(&data, ad); // Lost message -let (header2, encrypted2, nonce2) = alice_ratchet.ratchet_encrypt(&data, ad); // Successful message +let (mut bob_ratchet, public_key) = Ratchet::init_bob(sk); // Creating Bob's Ratchet (returns Bob's PublicKey) +let mut alice_ratchet = Ratchet::init_alice(sk, public_key); // Creating Alice's Ratchet with Bob's PublicKey -let decrypted2 = bob_ratchet.ratchet_decrypt(&header2, &encrypted2, &nonce2, ad); // Decrypting second message first -let decrypted1 = bob_ratchet.ratchet_decrypt(&header1, &encrypted1, &nonce1, ad); // Decrypting latter message +let data = b"Hello World".to_vec(); // Data to be encrypted +let ad = b"Associated Data"; // Associated data -let comp = decrypted1 == data && decrypted2 == data; -assert!(comp); +let (header1, encrypted1, nonce1) = alice_ratchet.encrypt(&data, ad); // Lost message +let (header2, encrypted2, nonce2) = alice_ratchet.encrypt(&data, ad); // Successful message + +let decrypted2 = bob_ratchet.decrypt(&header2, &encrypted2, &nonce2, ad); // Decrypting second message first +let decrypted1 = bob_ratchet.decrypt(&header1, &encrypted1, &nonce1, ad); // Decrypting latter message + +assert_eq!(data, decrypted1); +assert_eq!(data, decrypted2); ``` -### Encryption before recieving inital message +### Encryption Before Decrypting First Message + +Bob encrypts a message before decrypting one from Alice. +This will result in a panic. ```rust -use double_ratchet_2::ratchet::Ratchet; +use double_ratchet_rs::Ratchet; + let sk = [1; 32]; -let ad = b"Associated Data"; -let (mut bob_ratchet, _) = Ratchet::init_bob(sk); -let data = b"Hello World".to_vec(); -let (_, _, _) = bob_ratchet.ratchet_encrypt(&data, ad); +let (mut bob_ratchet, _) = Ratchet::init_bob(sk); + +let data = b"Hello World".to_vec(); +let ad = b"Associated Data"; + +let (_, _, _) = bob_ratchet.encrypt(&data, ad); ``` -### Encryption after recieving initial message -However bob can (of course) also encrypt messages. This is possible, after decrypting the first message from alice. +### Encryption After Decrypting First Message + +Bob *can* also encrypt messages. +This is only possible after decrypting one from Alice first though. ```rust -use double_ratchet_2::ratchet::Ratchet; +use double_ratchet_rs::Ratchet; + let sk = [1; 32]; let (mut bob_ratchet, public_key) = Ratchet::init_bob(sk); @@ -74,64 +95,83 @@ let mut alice_ratchet = Ratchet::init_alice(sk, public_key); let data = b"Hello World".to_vec(); let ad = b"Associated Data"; -let (header1, encrypted1, nonce1) = alice_ratchet.ratchet_encrypt(&data, ad); -let _decrypted1 = bob_ratchet.ratchet_decrypt(&header1, &encrypted1, &nonce1, ad); +let (header1, encrypted1, nonce1) = alice_ratchet.encrypt(&data, ad); +let _decrypted1 = bob_ratchet.decrypt(&header1, &encrypted1, &nonce1, ad); -let (header2, encrypted2, nonce2) = bob_ratchet.ratchet_encrypt(&data, ad); -let decrypted2 = alice_ratchet.ratchet_decrypt(&header2, &encrypted2, &nonce2, ad); +let (header2, encrypted2, nonce2) = bob_ratchet.encrypt(&data, ad); +let decrypted2 = alice_ratchet.decrypt(&header2, &encrypted2, &nonce2, ad); assert_eq!(data, decrypted2); ``` + ### Constructing and Deconstructing Headers ```rust +use double_ratchet_rs::{Header, Ratchet}; + +let sk = [1; 32]; + +let (mut bob_ratchet, public_key) = Ratchet::init_bob(sk); +let mut alice_ratchet = Ratchet::init_alice(sk, public_key); + +let data = b"hello World".to_vec(); +let ad = b"Associated Data"; + +let (header, _, _) = alice_ratchet.encrypt(&data, ad); let header_bytes: Vec = header.clone().into(); let header_const = Header::from(header_bytes); + assert_eq!(header, header_const); ``` -## Example Ratchet with encrypted headers +### Encrypted Headers ```rust -use double_ratchet_2::ratchet::RatchetEncHeader; +use double_ratchet_rs::RatchetEncHeader; + let sk = [0; 32]; let shared_hka = [1; 32]; let shared_nhkb = [2; 32]; let (mut bob_ratchet, public_key) = RatchetEncHeader::init_bob(sk, shared_hka, shared_nhkb); let mut alice_ratchet = RatchetEncHeader::init_alice(sk, public_key, shared_hka, shared_nhkb); + let data = b"Hello World".to_vec(); let ad = b"Associated Data"; -let (header, encrypted, nonce) = alice_ratchet.ratchet_encrypt(&data, ad); -let decrypted = bob_ratchet.ratchet_decrypt(&header, &encrypted, &nonce, ad); +let (header, encrypted, nonce) = alice_ratchet.encrypt(&data, ad); +let decrypted = bob_ratchet.decrypt(&header, &encrypted, &nonce, ad); + assert_eq!(data, decrypted) ``` -## Export / Import Ratchet with encrypted headers -This ratchet implements import and export functionality. This works over a bincode backend and -maybe useful for saving Ratchets to and loading from a file. +### Exporting / Importing Ratchet w/ Encrypted Headers + +This can be used for storing and using ratchets in a file. + ```rust +use double_ratchet_rs::RatchetEncHeader; + +let sk = [0; 32]; +let shared_hka = [1; 32]; +let shared_nhkb = [2; 32]; + let (bob_ratchet, public_key) = RatchetEncHeader::init_bob(sk, shared_hka, shared_nhkb); let ex_ratchet = bob_ratchet.export(); -let im_ratchet = RatchetEncHeader::import(&ex_ratchet); +let im_ratchet = RatchetEncHeader::import(&ex_ratchet).unwrap(); + assert_eq!(im_ratchet, bob_ratchet) ``` -## Features +## **M**inimum **S**upported **R**ust **V**ersion (MSRV) -Currently the crate only supports one feature: ring. If feature is enabled the crate switches -to ring-compat and uses ring as backend for Sha512 Hashing. May result in slightly better performance. +The current MSRV is 1.61.0. +## License -TODO: -- [x] Standard Double Ratchet -- [x] [Double Ratchet with encrypted headers][3] +This project is licensed under the [MIT license](https://github.com/magnetite-dev/double-ratchet-rs/blob/main/LICENSE). [1]: https://signal.org/docs/specifications/doubleratchet/ [2]: https://signal.org/docs/specifications/doubleratchet/#recommended-cryptographic-algorithms [3]: https://signal.org/docs/specifications/doubleratchet/#double-ratchet-with-header-encryption -Current version: 0.4.0 - -License: MIT diff --git a/README.tpl b/README.tpl deleted file mode 100644 index 71779cc..0000000 --- a/README.tpl +++ /dev/null @@ -1,13 +0,0 @@ -[![Crate](https://img.shields.io/crates/v/double-ratchet-2)](https://crates.io/crates/double-ratchet-2) -[![License](https://img.shields.io/github/license/Dione-Software/double-ratchet-2)](https://github.com/Dione-Software/double-ratchet-2/blob/main/LICENSE) -[![Coverage Status](https://coveralls.io/repos/github/Dione-Software/double-ratchet-2/badge.svg?branch=main)](https://coveralls.io/github/Dione-Software/double-ratchet-2?branch=main) -[![Workflow Status](https://github.com/Dione-Software/double-ratchet-2/actions/workflows/rust.yml/badge.svg)](https://github.com/Dione-Software/double-ratchet-2/actions/workflows/rust.yml) -{{badges}} - -# {{crate}} - -{{readme}} - -Current version: {{version}} - -License: {{license}} \ No newline at end of file diff --git a/benches/double_ratchet_bench.rs b/benches/double_ratchet_bench.rs index 373ae06..0d5558d 100644 --- a/benches/double_ratchet_bench.rs +++ b/benches/double_ratchet_bench.rs @@ -1,13 +1,13 @@ -use double_ratchet_2::ratchet::{Ratchet, RatchetEncHeader}; -use criterion::{Criterion, criterion_main, criterion_group}; +use criterion::{criterion_group, criterion_main, Criterion}; +use double_ratchet_rs::{Ratchet, RatchetEncHeader}; fn ratchet_enc_single() { let sk = [1; 32]; let (mut bob_ratchet, public_key) = Ratchet::init_bob(sk); let mut alice_ratchet = Ratchet::init_alice(sk, public_key); let data = include_bytes!("../src/header.rs").to_vec(); - let (header, encrypted, nonce) = alice_ratchet.ratchet_encrypt(&data, b""); - let _decrypted = bob_ratchet.ratchet_decrypt(&header, &encrypted, &nonce, b""); + let (header, encrypted, nonce) = alice_ratchet.encrypt(&data, b""); + let _decrypted = bob_ratchet.decrypt(&header, &encrypted, &nonce, b""); } fn criterion_benchmark_1(c: &mut Criterion) { @@ -19,10 +19,10 @@ fn ratchet_enc_skip() { let (mut bob_ratchet, public_key) = Ratchet::init_bob(sk); let mut alice_ratchet = Ratchet::init_alice(sk, public_key); let data = include_bytes!("../src/header.rs").to_vec(); - let (header1, encrypted1, nonce1) = alice_ratchet.ratchet_encrypt(&data, b""); - let (header2, encrypted2, nonce2) = alice_ratchet.ratchet_encrypt(&data, b""); - let _decrypted2 = bob_ratchet.ratchet_decrypt(&header2, &encrypted2, &nonce2, b""); - let _decrypted1 = bob_ratchet.ratchet_decrypt(&header1, &encrypted1, &nonce1, b""); + let (header1, encrypted1, nonce1) = alice_ratchet.encrypt(&data, b""); + let (header2, encrypted2, nonce2) = alice_ratchet.encrypt(&data, b""); + let _decrypted2 = bob_ratchet.decrypt(&header2, &encrypted2, &nonce2, b""); + let _decrypted1 = bob_ratchet.decrypt(&header1, &encrypted1, &nonce1, b""); } fn criterion_benchmark_2(c: &mut Criterion) { @@ -34,78 +34,84 @@ fn ratchet_encryt_decrypt_four() { let data = include_bytes!("../src/dh.rs").to_vec(); let (mut bob_ratchet, public_key) = Ratchet::init_bob(sk); let mut alice_ratchet = Ratchet::init_alice(sk, public_key); - let (header1, encrypted1, nonce1) = alice_ratchet.ratchet_encrypt(&data, b""); - let _decrypted1 = bob_ratchet.ratchet_decrypt(&header1, &encrypted1, &nonce1, b""); - let (header2, encrypted2, nonce2) = bob_ratchet.ratchet_encrypt(&data, b""); - let _decrypted2 = alice_ratchet.ratchet_decrypt(&header2, &encrypted2, &nonce2, b""); + let (header1, encrypted1, nonce1) = alice_ratchet.encrypt(&data, b""); + let _decrypted1 = bob_ratchet.decrypt(&header1, &encrypted1, &nonce1, b""); + let (header2, encrypted2, nonce2) = bob_ratchet.encrypt(&data, b""); + let _decrypted2 = alice_ratchet.decrypt(&header2, &encrypted2, &nonce2, b""); } fn criterion_benchmark_3(c: &mut Criterion) { - c.bench_function("Ratchet Dec Four", |b| b.iter(|| ratchet_encryt_decrypt_four())); + c.bench_function("Ratchet Dec Four", |b| { + b.iter(|| ratchet_encryt_decrypt_four()) + }); } fn ratchet_ench_enc_single() { let sk = [1; 32]; let shared_hka = [2; 32]; let shared_nhkb = [3; 32]; - let (mut bob_ratchet, public_key) = RatchetEncHeader::init_bob(sk, - shared_hka, - shared_nhkb); - let mut alice_ratchet = RatchetEncHeader::init_alice(sk, - public_key, - shared_hka, - shared_nhkb); + let (mut bob_ratchet, public_key) = RatchetEncHeader::init_bob(sk, shared_hka, shared_nhkb); + let mut alice_ratchet = RatchetEncHeader::init_alice(sk, public_key, shared_hka, shared_nhkb); let data = include_bytes!("../src/header.rs").to_vec(); - let (header, encrypted, nonce) = alice_ratchet.ratchet_encrypt(&data, b""); - let decrypted = bob_ratchet.ratchet_decrypt(&header, &encrypted, &nonce, b""); + let (header, encrypted, nonce) = alice_ratchet.encrypt(&data, b""); + let decrypted = bob_ratchet.decrypt(&header, &encrypted, &nonce, b""); assert_eq!(data, decrypted) } fn criterion_benchmark_4(c: &mut Criterion) { - c.bench_function("Encrypted Header Ratchet Enc Single", |b| b.iter(|| ratchet_ench_enc_single())); + c.bench_function("Encrypted Header Ratchet Enc Single", |b| { + b.iter(|| ratchet_ench_enc_single()) + }); } fn ratchet_ench_enc_skip() { let sk = [1; 32]; let shared_hka = [2; 32]; let shared_nhkb = [3; 32]; - let (mut bob_ratchet, public_key) = RatchetEncHeader::init_bob(sk, - shared_hka, - shared_nhkb); - let mut alice_ratchet = RatchetEncHeader::init_alice(sk, - public_key, - shared_hka, - shared_nhkb); + let (mut bob_ratchet, public_key) = RatchetEncHeader::init_bob(sk, shared_hka, shared_nhkb); + let mut alice_ratchet = RatchetEncHeader::init_alice(sk, public_key, shared_hka, shared_nhkb); let data = include_bytes!("../src/header.rs").to_vec(); - let (header1, encrypted1, nonce1) = alice_ratchet.ratchet_encrypt(&data, b""); - let (header2, encrypted2, nonce2) = alice_ratchet.ratchet_encrypt(&data, b""); - let _decrypted2 = bob_ratchet.ratchet_decrypt(&header2, &encrypted2, &nonce2, b""); - let _decrypted1 = bob_ratchet.ratchet_decrypt(&header1, &encrypted1, &nonce1, b""); + let (header1, encrypted1, nonce1) = alice_ratchet.encrypt(&data, b""); + let (header2, encrypted2, nonce2) = alice_ratchet.encrypt(&data, b""); + let _decrypted2 = bob_ratchet.decrypt(&header2, &encrypted2, &nonce2, b""); + let _decrypted1 = bob_ratchet.decrypt(&header1, &encrypted1, &nonce1, b""); } fn criterion_benchmark_5(c: &mut Criterion) { - c.bench_function("Encrypted Header Ratchet Enc Skip", |b| b.iter(|| ratchet_ench_enc_skip())); + c.bench_function("Encrypted Header Ratchet Enc Skip", |b| { + b.iter(|| ratchet_ench_enc_skip()) + }); } fn ratchet_ench_decrypt_four() { let sk = [1; 32]; let shared_hka = [2; 32]; let shared_nhkb = [3; 32]; - let (mut bob_ratchet, public_key) = RatchetEncHeader::init_bob(sk, - shared_hka, - shared_nhkb); + let (mut bob_ratchet, public_key) = RatchetEncHeader::init_bob(sk, shared_hka, shared_nhkb); let mut alice_ratchet = RatchetEncHeader::init_alice(sk, public_key, shared_hka, shared_nhkb); let data = include_bytes!("../src/dh.rs").to_vec(); - let (header1, encrypted1, nonce1) = alice_ratchet.ratchet_encrypt(&data, b""); - let _decrypted1 = bob_ratchet.ratchet_decrypt(&header1, &encrypted1, &nonce1, b""); - let (header2, encrypted2, nonce2) = bob_ratchet.ratchet_encrypt(&data, b""); - let _decrypted2 = alice_ratchet.ratchet_decrypt(&header2, &encrypted2, &nonce2, b""); + let (header1, encrypted1, nonce1) = alice_ratchet.encrypt(&data, b""); + let _decrypted1 = bob_ratchet.decrypt(&header1, &encrypted1, &nonce1, b""); + let (header2, encrypted2, nonce2) = bob_ratchet.encrypt(&data, b""); + let _decrypted2 = alice_ratchet.decrypt(&header2, &encrypted2, &nonce2, b""); } fn criterion_benchmark_6(c: &mut Criterion) { - c.bench_function("Encrypted Header Ratchet Dec Four", |b| b.iter(|| ratchet_ench_decrypt_four())); + c.bench_function("Encrypted Header Ratchet Dec Four", |b| { + b.iter(|| ratchet_ench_decrypt_four()) + }); } -criterion_group!(without_enc_headerd, criterion_benchmark_1, criterion_benchmark_2, criterion_benchmark_3); -criterion_group!(with_enc_headerd, criterion_benchmark_4, criterion_benchmark_5, criterion_benchmark_6); -criterion_main!(without_enc_headerd, with_enc_headerd); \ No newline at end of file +criterion_group!( + without_enc_headerd, + criterion_benchmark_1, + criterion_benchmark_2, + criterion_benchmark_3 +); +criterion_group!( + with_enc_headerd, + criterion_benchmark_4, + criterion_benchmark_5, + criterion_benchmark_6 +); +criterion_main!(without_enc_headerd, with_enc_headerd); diff --git a/deny.toml b/deny.toml deleted file mode 100644 index 12aeacf..0000000 --- a/deny.toml +++ /dev/null @@ -1,204 +0,0 @@ -# This template contains all of the possible sections and their default values - -# Note that all fields that take a lint level have these possible values: -# * deny - An error will be produced and the check will fail -# * warn - A warning will be produced, but the check will not fail -# * allow - No warning or error will be produced, though in some cases a note -# will be - -# The values provided in this template are the default values that will be used -# when any section or field is not specified in your own configuration - -# If 1 or more target triples (and optionally, target_features) are specified, -# only the specified targets will be checked when running `cargo deny check`. -# This means, if a particular package is only ever used as a target specific -# dependency, such as, for example, the `nix` crate only being used via the -# `target_family = "unix"` configuration, that only having windows targets in -# this list would mean the nix crate, as well as any of its exclusive -# dependencies not shared by any other crates, would be ignored, as the target -# list here is effectively saying which targets you are building for. -targets = [ - # The triple can be any string, but only the target triples built in to - # rustc (as of 1.40) can be checked against actual config expressions - #{ triple = "x86_64-unknown-linux-musl" }, - # You can also specify which target_features you promise are enabled for a - # particular target. target_features are currently not validated against - # the actual valid features supported by the target architecture. - #{ triple = "wasm32-unknown-unknown", features = ["atomics"] }, -] - -# This section is considered when running `cargo deny check advisories` -# More documentation for the advisories section can be found here: -# https://embarkstudios.github.io/cargo-deny/checks/advisories/cfg.html -[advisories] -# The path where the advisory database is cloned/fetched into -db-path = "~/.cargo/advisory-db" -# The url(s) of the advisory databases to use -db-urls = ["https://github.com/rustsec/advisory-db"] -# The lint level for security vulnerabilities -vulnerability = "deny" -# The lint level for unmaintained crates -unmaintained = "warn" -# The lint level for crates that have been yanked from their source registry -yanked = "warn" -# The lint level for crates with security notices. Note that as of -# 2019-12-17 there are no security notice advisories in -# https://github.com/rustsec/advisory-db -notice = "warn" -# A list of advisory IDs to ignore. Note that ignored advisories will still -# output a note when they are encountered. -ignore = [ - #"RUSTSEC-0000-0000", -] -# Threshold for security vulnerabilities, any vulnerability with a CVSS score -# lower than the range specified will be ignored. Note that ignored advisories -# will still output a note when they are encountered. -# * None - CVSS Score 0.0 -# * Low - CVSS Score 0.1 - 3.9 -# * Medium - CVSS Score 4.0 - 6.9 -# * High - CVSS Score 7.0 - 8.9 -# * Critical - CVSS Score 9.0 - 10.0 -#severity-threshold = - -# This section is considered when running `cargo deny check licenses` -# More documentation for the licenses section can be found here: -# https://embarkstudios.github.io/cargo-deny/checks/licenses/cfg.html -[licenses] -# The lint level for crates which do not have a detectable license -unlicensed = "deny" -# List of explictly allowed licenses -# See https://spdx.org/licenses/ for list of possible licenses -# [possible values: any SPDX 3.11 short identifier (+ optional exception)]. -allow = [ - "MIT", - "Apache-2.0", - "BSD-3-Clause", - #"Apache-2.0 WITH LLVM-exception", -] -# List of explictly disallowed licenses -# See https://spdx.org/licenses/ for list of possible licenses -# [possible values: any SPDX 3.11 short identifier (+ optional exception)]. -deny = [ - #"Nokia", -] -# Lint level for licenses considered copyleft -copyleft = "warn" -# Blanket approval or denial for OSI-approved or FSF Free/Libre licenses -# * both - The license will be approved if it is both OSI-approved *AND* FSF -# * either - The license will be approved if it is either OSI-approved *OR* FSF -# * osi-only - The license will be approved if is OSI-approved *AND NOT* FSF -# * fsf-only - The license will be approved if is FSF *AND NOT* OSI-approved -# * neither - This predicate is ignored and the default lint level is used -allow-osi-fsf-free = "neither" -# Lint level used when no other predicates are matched -# 1. License isn't in the allow or deny lists -# 2. License isn't copyleft -# 3. License isn't OSI/FSF, or allow-osi-fsf-free = "neither" -default = "deny" -# The confidence threshold for detecting a license from license text. -# The higher the value, the more closely the license text must be to the -# canonical license text of a valid SPDX license file. -# [possible values: any between 0.0 and 1.0]. -confidence-threshold = 0.8 -# Allow 1 or more licenses on a per-crate basis, so that particular licenses -# aren't accepted for every possible crate as with the normal allow list -exceptions = [ - # Each entry is the crate and version constraint, and its specific allow - # list - #{ allow = ["Zlib"], name = "adler32", version = "*" }, -] - -# Some crates don't have (easily) machine readable licensing information, -# adding a clarification entry for it allows you to manually specify the -# licensing information -#[[licenses.clarify]] -# The name of the crate the clarification applies to -#name = "ring" -# The optional version constraint for the crate -#version = "*" -# The SPDX expression for the license requirements of the crate -#expression = "MIT AND ISC AND OpenSSL" -# One or more files in the crate's source used as the "source of truth" for -# the license expression. If the contents match, the clarification will be used -# when running the license check, otherwise the clarification will be ignored -# and the crate will be checked normally, which may produce warnings or errors -# depending on the rest of your configuration -#license-files = [ - # Each entry is a crate relative path, and the (opaque) hash of its contents - #{ path = "LICENSE", hash = 0xbd0eed23 } -#] - -[licenses.private] -# If true, ignores workspace crates that aren't published, or are only -# published to private registries -ignore = false -# One or more private registries that you might publish crates to, if a crate -# is only published to private registries, and ignore is true, the crate will -# not have its license(s) checked -registries = [ - #"https://sekretz.com/registry -] - -# This section is considered when running `cargo deny check bans`. -# More documentation about the 'bans' section can be found here: -# https://embarkstudios.github.io/cargo-deny/checks/bans/cfg.html -[bans] -# Lint level for when multiple versions of the same crate are detected -multiple-versions = "warn" -# Lint level for when a crate version requirement is `*` -wildcards = "allow" -# The graph highlighting used when creating dotgraphs for crates -# with multiple versions -# * lowest-version - The path to the lowest versioned duplicate is highlighted -# * simplest-path - The path to the version with the fewest edges is highlighted -# * all - Both lowest-version and simplest-path are used -highlight = "all" -# List of crates that are allowed. Use with care! -allow = [ - #{ name = "ansi_term", version = "=0.11.0" }, -] -# List of crates to deny -deny = [ - # Each entry the name of a crate and a version range. If version is - # not specified, all versions will be matched. - #{ name = "ansi_term", version = "=0.11.0" }, - # - # Wrapper crates can optionally be specified to allow the crate when it - # is a direct dependency of the otherwise banned crate - #{ name = "ansi_term", version = "=0.11.0", wrappers = [] }, -] -# Certain crates/versions that will be skipped when doing duplicate detection. -skip = [ - #{ name = "ansi_term", version = "=0.11.0" }, -] -# Similarly to `skip` allows you to skip certain crates during duplicate -# detection. Unlike skip, it also includes the entire tree of transitive -# dependencies starting at the specified crate, up to a certain depth, which is -# by default infinite -skip-tree = [ - #{ name = "ansi_term", version = "=0.11.0", depth = 20 }, -] - -# This section is considered when running `cargo deny check sources`. -# More documentation about the 'sources' section can be found here: -# https://embarkstudios.github.io/cargo-deny/checks/sources/cfg.html -[sources] -# Lint level for what to happen when a crate from a crate registry that is not -# in the allow list is encountered -unknown-registry = "warn" -# Lint level for what to happen when a crate from a git repository that is not -# in the allow list is encountered -unknown-git = "warn" -# List of URLs for allowed crate registries. Defaults to the crates.io index -# if not specified. If it is specified but empty, no registries are allowed. -allow-registry = ["https://github.com/rust-lang/crates.io-index"] -# List of URLs for allowed Git repositories -allow-git = [] - -[sources.allow-org] -# 1 or more github.com organizations to allow git sources for -# github = [""] -# 1 or more gitlab.com organizations to allow git sources for -# gitlab = [""] -# 1 or more bitbucket.org organizations to allow git sources for -# bitbucket = [""] diff --git a/src/aead.rs b/src/aead.rs index 2d5a63f..3414de8 100644 --- a/src/aead.rs +++ b/src/aead.rs @@ -1,45 +1,57 @@ -use aes_gcm_siv::{Key, Aes256GcmSiv, Nonce}; -use aes_gcm_siv::aead::{NewAead, AeadInPlace}; +use aes_gcm_siv::aead::AeadInPlace; +use aes_gcm_siv::{Aes256GcmSiv, KeyInit, Nonce}; use alloc::vec::Vec; use rand_core::{OsRng, RngCore}; -pub fn encrypt(mk: &[u8; 32], plaintext: &[u8], associated_data: &[u8]) -> (Vec, [u8; 12]) { - let key = Key::from_slice(mk); - let cipher = Aes256GcmSiv::new(key); - let mut nonce_data = [0_u8; 12]; +pub fn encrypt(mk: &[u8; 32], data: &[u8], associated_data: &[u8]) -> (Vec, [u8; 12]) { + let cipher = Aes256GcmSiv::new_from_slice(mk).expect("Encryption failure {}"); + + let mut nonce_data = [0u8; 12]; OsRng::fill_bytes(&mut OsRng, &mut nonce_data); let nonce = Nonce::from_slice(&nonce_data); - let mut buffer = Vec::new(); - buffer.extend_from_slice(plaintext); - cipher.encrypt_in_place(nonce, associated_data, &mut buffer) - .expect("Encryption failed"); + let mut buffer = Vec::new(); + buffer.extend_from_slice(data); + + cipher + .encrypt_in_place(nonce, associated_data, &mut buffer) + .expect("Encryption failure {}"); + (buffer, nonce_data) } -pub fn decrypt(mk: &[u8; 32], ciphertext: &[u8], associated_data: &[u8], nonce: &[u8; 12]) -> Vec { - let key = Key::from_slice(mk); - let cipher = Aes256GcmSiv::new(key); +pub fn decrypt( + mk: &[u8; 32], + enc_data: &[u8], + associated_data: &[u8], + nonce: &[u8; 12], +) -> Vec { + let cipher = Aes256GcmSiv::new_from_slice(mk).expect("Decryption failure {}"); let nonce = Nonce::from_slice(nonce); + let mut buffer = Vec::new(); - buffer.extend_from_slice(ciphertext); - cipher.decrypt_in_place(nonce, associated_data, &mut buffer).expect("Decryption failure {}"); + buffer.extend_from_slice(enc_data); + + cipher + .decrypt_in_place(nonce, associated_data, &mut buffer) + .expect("Decryption failure {}"); + buffer } #[cfg(test)] mod tests { + use crate::aead::{decrypt, encrypt}; use crate::kdf_chain::gen_mk; - use crate::aead::{encrypt, decrypt}; #[test] fn enc_a_dec() { - let test_data = include_bytes!("aead.rs").to_vec(); - let associated_data = include_bytes!("lib.rs").to_vec(); + let test_data = include_bytes!("aead.rs"); + let associated_data = include_bytes!("lib.rs"); let mk = gen_mk(); - let (ciphertext, nonce) = encrypt(&mk, &test_data, &associated_data); - let plaintext = decrypt(&mk, &ciphertext, &associated_data, &nonce); - assert_eq!(test_data, plaintext) + let (enc_data, nonce) = encrypt(&mk, test_data, associated_data); + let data = decrypt(&mk, &enc_data, associated_data, &nonce); + assert_eq!(test_data, data.as_slice()) } -} \ No newline at end of file +} diff --git a/src/dh.rs b/src/dh.rs index aa539d9..74a98c5 100644 --- a/src/dh.rs +++ b/src/dh.rs @@ -1,43 +1,31 @@ +use core::fmt::{Debug, Formatter, Result}; use rand_core::OsRng; -use core::fmt::{Debug, Formatter}; -use core::fmt; -use p256::PublicKey as PublicKey; -use p256::ecdh::SharedSecret; -use p256::SecretKey; -use alloc::vec::Vec; -use alloc::string::ToString; -use p256::elliptic_curve::ecdh::diffie_hellman; +use serde::{Deserialize, Serialize}; +use x25519_dalek::{PublicKey, SharedSecret, StaticSecret}; -#[derive(Clone)] +#[derive(Deserialize, Serialize, Clone)] pub struct DhKeyPair { - pub private_key: SecretKey, + pub private_key: StaticSecret, pub public_key: PublicKey, } - -impl DhKeyPair { - fn ex_public_key_bytes(&self) -> Vec { - self.public_key.to_string().as_bytes().to_vec() - } -} - impl PartialEq for DhKeyPair { fn eq(&self, other: &Self) -> bool { - if self.private_key.to_be_bytes() != other.private_key.to_be_bytes() { - return false + if self.private_key.to_bytes() != other.private_key.to_bytes() { + return false; } - if self.ex_public_key_bytes() != other.ex_public_key_bytes() { - return false + if self.public_key != other.public_key { + return false; } true } } impl Debug for DhKeyPair { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { f.debug_struct("DhKeyPair") - .field("private_key", &self.private_key.to_be_bytes()) - .field("public_key", &self.ex_public_key_bytes()) + .field("private_key", &self.private_key.to_bytes()) + .field("public_key", self.public_key.as_bytes()) .finish() } } @@ -50,8 +38,8 @@ impl Default for DhKeyPair { impl DhKeyPair { pub fn new() -> Self { - let secret = SecretKey::random(&mut OsRng); - let public = secret.public_key(); + let secret = StaticSecret::new(&mut OsRng); + let public = PublicKey::from(&secret); DhKeyPair { private_key: secret, public_key: public, @@ -59,7 +47,7 @@ impl DhKeyPair { } pub fn key_agreement(&self, public_key: &PublicKey) -> SharedSecret { - diffie_hellman(self.private_key.to_nonzero_scalar(), public_key.as_affine()) + self.private_key.diffie_hellman(public_key) } } @@ -78,7 +66,6 @@ pub fn gen_key_pair() -> DhKeyPair { #[cfg(test)] mod tests { use crate::dh::DhKeyPair; - use alloc::string::ToString; #[test] fn key_generation() { @@ -96,14 +83,6 @@ mod tests { assert_eq!(alice_shared_secret.as_bytes(), bob_shared_secret.as_bytes()) } - #[test] - fn ex_public_key() { - let key_pair = DhKeyPair::new(); - let public_key_bytes = key_pair.ex_public_key_bytes(); - let extracted_pk = key_pair.public_key.to_string().as_bytes().to_vec(); - assert_eq!(extracted_pk, public_key_bytes) - } - #[test] fn nq_key_pair() { let key_pair1 = DhKeyPair::new(); @@ -124,4 +103,4 @@ mod tests { let key_pair = DhKeyPair::default(); let _str = alloc::format!("{:?}", key_pair); } -} \ No newline at end of file +} diff --git a/src/header.rs b/src/header.rs index 7402040..2981077 100644 --- a/src/header.rs +++ b/src/header.rs @@ -1,107 +1,62 @@ -use p256::PublicKey; -use crate::dh::DhKeyPair; -use alloc::vec::Vec; -use serde::{Serialize, Deserialize}; +//! Message header. + use crate::aead::encrypt; -use aes_gcm_siv::{Key, Nonce, Aes256GcmSiv}; -use aes_gcm_siv::aead::{NewAead, AeadInPlace}; +use crate::dh::DhKeyPair; +use aes_gcm_siv::aead::AeadInPlace; +use aes_gcm_siv::{Aes256GcmSiv, KeyInit, Nonce}; +use alloc::vec::Vec; +use serde::{Deserialize, Serialize}; +use x25519_dalek::PublicKey; #[cfg(test)] use crate::dh::gen_key_pair; -use alloc::string::{ToString, String}; -use core::str::FromStr; use zeroize::Zeroize; -#[derive(Debug, Clone)] -pub struct Header { - pub public_key: PublicKey, - pub pn: usize, // Previous Chain Length - pub n: usize, // Message Number -} - -#[derive(Serialize, Deserialize, Debug, Zeroize)] +#[derive(Serialize, Deserialize, Debug, Zeroize, Clone, PartialEq, Eq)] #[zeroize(drop)] -struct ExHeader { - #[serde(with = "serde_bytes")] +pub struct Header { ad: Vec, - public_key: Vec, - pn: usize, - n: usize + pub public_key: PublicKey, + pub pn: usize, + pub n: usize, } -// Message Header +// A message header. impl Header { - // #[doc(hidden)] + /// Create a new message header. + /// Requires a [DhKeyPair], previous chain length, and message number. + /// Returns a [Header]. pub fn new(dh_pair: &DhKeyPair, pn: usize, n: usize) -> Self { Header { + ad: Vec::new(), public_key: dh_pair.public_key, pn, n, } } - // #[doc(hidden)] + pub fn concat(&self, ad: &[u8]) -> Vec { - let ex_header = ExHeader { - ad: ad.to_vec(), - public_key: self.public_key.to_string().as_bytes().to_vec(), - pn: self.pn, - n: self.n - }; - bincode::serialize(&ex_header).expect("Failed to serialize Header") + let mut header = self.clone(); + header.ad = ad.to_vec(); + postcard::to_allocvec(&header).expect("Failed to serialize Header") } - pub fn encrypt(&self, hk: &[u8; 32], ad: &[u8]) -> (Vec, [u8; 12]) { + pub fn encrypt(&self, hk: &[u8; 32], ad: &[u8]) -> EncryptedHeader { let header_data = self.concat(ad); - encrypt(hk, &header_data, b"") - } - - pub fn decrypt(hk: &Option<[u8; 32]>, ciphertext: &[u8], nonce: &[u8; 12]) -> Option { - let key_d = match hk { - None => { - return None - }, - Some(d) => d - }; - let key = Key::from_slice(key_d); - let cipher = Aes256GcmSiv::new(key); - - let nonce = Nonce::from_slice(nonce); - let mut buffer = Vec::new(); - buffer.extend_from_slice(ciphertext); - match cipher.decrypt_in_place(nonce, b"", &mut buffer) { - Ok(_) => {} - Err(_) => { - return None - } - }; - Some(Header::from(buffer)) - } - pub fn ex_public_key_bytes(&self) -> Vec { - self.public_key.to_string().as_bytes().to_vec() + let enc_header = encrypt(hk, &header_data, b""); + EncryptedHeader(enc_header.0, enc_header.1) } } impl From> for Header { fn from(d: Vec) -> Self { - let ex_header: ExHeader = bincode::deserialize(&d).unwrap(); - let public_key_string = String::from_utf8(ex_header.public_key.clone()).unwrap(); - Header { - public_key: PublicKey::from_str(&public_key_string).unwrap(), - pn: ex_header.pn, - n: ex_header.n, - } + postcard::from_bytes(&d).unwrap() } } impl From<&[u8]> for Header { fn from(d: &[u8]) -> Self { - let ex_header: ExHeader = bincode::deserialize(d).unwrap(); - let public_key_string = String::from_utf8(ex_header.public_key.clone()).unwrap(); - Header { - public_key: PublicKey::from_str(&public_key_string).unwrap(), - pn: ex_header.pn, - n: ex_header.n, - } + postcard::from_bytes(d).unwrap() } } @@ -111,14 +66,28 @@ impl From
for Vec { } } -impl PartialEq for Header { - fn eq(&self, other: &Self) -> bool { - if self.public_key == other.public_key - && self.pn == other.pn - && self.n == other.n { - return true - } - false +pub struct EncryptedHeader(Vec, [u8; 12]); + +impl EncryptedHeader { + pub fn decrypt(&self, hk: &Option<[u8; 32]>) -> Option
{ + let key_d = match hk { + None => return None, + Some(d) => d, + }; + + let cipher = match Aes256GcmSiv::new_from_slice(key_d) { + Ok(v) => v, + Err(_) => return None, + }; + + let nonce = Nonce::from_slice(&self.1); + let mut buffer = Vec::new(); + buffer.extend_from_slice(&self.0); + match cipher.decrypt_in_place(nonce, b"", &mut buffer) { + Ok(_) => {} + Err(_) => return None, + }; + Some(Header::from(buffer)) } } @@ -130,12 +99,13 @@ pub fn gen_header() -> Header { Header::new(&dh_pair, pn, n) } - #[cfg(test)] mod tests { - use crate::header::{gen_header, Header, ExHeader}; + use x25519_dalek::PublicKey; + + use crate::aead::{decrypt, encrypt}; + use crate::header::{gen_header, Header}; use crate::kdf_chain::gen_mk; - use crate::aead::{encrypt, decrypt}; #[test] fn ser_des() { @@ -172,11 +142,11 @@ mod tests { #[test] fn gen_ex_header() { - let ex_header = ExHeader { + let ex_header = Header { ad: alloc::vec![0], - public_key: alloc::vec![1], + public_key: PublicKey::from([1; 32]), pn: 0, - n: 0 + n: 0, }; let _string = alloc::format!("{:?}", ex_header); } @@ -184,8 +154,8 @@ mod tests { #[test] fn dec_header() { let header = gen_header(); - let (encrypted, nonce) = header.encrypt(&[0; 32], &[0]); - let decrypted = Header::decrypt(&Some([1_u8; 32]), &encrypted, &nonce); + let encrypted = header.encrypt(&[0; 32], &[0]); + let decrypted = encrypted.decrypt(&Some([1u8; 32])); assert_eq!(None, decrypted) } -} \ No newline at end of file +} diff --git a/src/kdf_chain.rs b/src/kdf_chain.rs index d240beb..d63c068 100644 --- a/src/kdf_chain.rs +++ b/src/kdf_chain.rs @@ -1,8 +1,6 @@ -use hmac::{Hmac, Mac}; - -use sha2::Sha512; - use core::convert::TryInto; +use hmac::{Hmac, Mac}; +use sha2::Sha512; #[cfg(test)] use crate::kdf_root::gen_ck; @@ -10,14 +8,14 @@ use crate::kdf_root::gen_ck; type HmacSha512 = Hmac; pub fn kdf_ck(ck: &[u8; 32]) -> ([u8; 32], [u8; 32]) { - let mac = HmacSha512::new_from_slice(ck) - .expect("Invalid Key Length"); + let mac = HmacSha512::new_from_slice(ck).expect("Invalid Key Length"); let result = mac.finalize().into_bytes(); let (a, b) = result.split_at(32); - (a.try_into() - .expect("Incorrect Length"), - b.try_into() - .expect("Incorrect Length")) + + ( + a.try_into().expect("Incorrect Length"), + b.try_into().expect("Incorrect Length"), + ) } #[cfg(test)] @@ -29,8 +27,8 @@ pub fn gen_mk() -> [u8; 32] { #[cfg(test)] mod tests { - use crate::kdf_root::gen_ck; use crate::kdf_chain::kdf_ck; + use crate::kdf_root::gen_ck; #[test] fn kdf_chain_ratchet() { let ck = gen_ck(); @@ -38,4 +36,4 @@ mod tests { let (_, mk2) = kdf_ck(&ck); assert_ne!(mk1, mk2) } -} \ No newline at end of file +} diff --git a/src/kdf_root.rs b/src/kdf_root.rs index 0640959..f19b1f9 100644 --- a/src/kdf_root.rs +++ b/src/kdf_root.rs @@ -1,14 +1,10 @@ - -use hkdf::Hkdf; - - -use sha2::Sha512; - use core::convert::TryInto; +use hkdf::Hkdf; +use sha2::Sha512; #[cfg(test)] use crate::dh::gen_shared_secret; -use p256::ecdh::SharedSecret; +use x25519_dalek::SharedSecret; pub fn kdf_rk(rk: &[u8; 32], dh_out: &SharedSecret) -> ([u8; 32], [u8; 32]) { let h = Hkdf::::new(Some(rk), dh_out.as_bytes()); @@ -16,10 +12,10 @@ pub fn kdf_rk(rk: &[u8; 32], dh_out: &SharedSecret) -> ([u8; 32], [u8; 32]) { let info = b"Root Key Info"; h.expand(info, &mut okm).unwrap(); let (a, b) = okm.split_at(32); - (a.try_into() - .expect("Incorrect length"), - b.try_into() - .expect("Incorrect length")) + ( + a.try_into().expect("Incorrect length"), + b.try_into().expect("Incorrect length"), + ) } pub fn kdf_rk_he(rk: &[u8; 32], dh_out: &SharedSecret) -> ([u8; 32], [u8; 32], [u8; 32]) { @@ -32,7 +28,7 @@ pub fn kdf_rk_he(rk: &[u8; 32], dh_out: &SharedSecret) -> ([u8; 32], [u8; 32], [ ( rk.try_into().expect("Wrong length"), ck.try_into().expect("Wrong length"), - nhk.try_into().expect("Wrong length") + nhk.try_into().expect("Wrong length"), ) } @@ -57,4 +53,4 @@ mod tests { let (rk2, _) = kdf_rk(&rk1, &shared_secret); assert_ne!(rk1, rk2) } -} \ No newline at end of file +} diff --git a/src/lib.rs b/src/lib.rs index 9209fe8..1254ec6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,64 +1,85 @@ -//! Implementation of the double ratchet system/encryption as specified by [Signal][1]. +//! A pure Rust implementation of the Double Ratchet Algorithm as specified by [Signal][1]. //! -//! **WARNING! This implementation uses P-256 NOT Curve25519 as specified by Signal!** -//! -//! The implementation follows the cryptographic recommendations provided by [Signal][2]. +//! This implementation follows the cryptographic recommendations provided by [Signal][2]. //! The AEAD Algorithm uses a constant Nonce. This might be changed in the future. //! -//! # Example Usage: +//! Fork of [double-ratchet-2](https://github.com/Dione-Software/double-ratchet-2). +//! +//! ## Examples +//! +//! ### Standard Usage +//! +//! Alice encrypts a message which is then decrypted by Bob. //! -//! ## Standard: //! ``` -//! use double_ratchet_2::ratchet::Ratchet; +//! use double_ratchet_rs::Ratchet; //! -//! let sk = [1; 32]; // Initial Key created by a symmetric key agreement protocol -//! let (mut bob_ratchet, public_key) = Ratchet::init_bob(sk); // Creating Bobs Ratchet (returns Bobs PublicKey) -//! let mut alice_ratchet = Ratchet::init_alice(sk, public_key); // Creating Alice Ratchet with Bobs PublicKey -//! let data = b"Hello World".to_vec(); // Data to be encrypted -//! let ad = b"Associated Data"; // Associated Data +//! let sk = [1; 32]; // Shared key created by a symmetric key agreement protocol +//! +//! let (mut bob_ratchet, public_key) = Ratchet::init_bob(sk); // Creating Bob's Ratchet (returns Bob's PublicKey) +//! let mut alice_ratchet = Ratchet::init_alice(sk, public_key); // Creating Alice's Ratchet with Bob's PublicKey +//! +//! let data = b"Hello World".to_vec(); // Data to be encrypted +//! let ad = b"Associated Data"; // Associated data +//! +//! let (header, encrypted, nonce) = alice_ratchet.encrypt(&data, ad); // Encrypting message with Alice's Ratchet (Alice always needs to send the first message) +//! let decrypted = bob_ratchet.decrypt(&header, &encrypted, &nonce, ad); // Decrypt message with Bob's Ratchet //! -//! let (header, encrypted, nonce) = alice_ratchet.ratchet_encrypt(&data, ad); // Encrypting message with Alice Ratchet (Alice always needs to send the first message) -//! let decrypted = bob_ratchet.ratchet_decrypt(&header, &encrypted, &nonce, ad); // Decrypt message with Bobs Ratchet //! assert_eq!(data, decrypted) //! ``` //! -//! ## With lost message: +//! ### Recovering a Lost Message +//! +//! Alice encrypts 2 messages for Bob. +//! The latest message must be decrypted first. +//! //! ``` -//! # use double_ratchet_2::ratchet::Ratchet; +//! use double_ratchet_rs::Ratchet; //! -//! let sk = [1; 32]; // Initial Key created by a symmetric key agreement protocol -//! let (mut bob_ratchet, public_key) = Ratchet::init_bob(sk); // Creating Bobs Ratchet (returns Bobs PublicKey) -//! let mut alice_ratchet = Ratchet::init_alice(sk, public_key); // Creating Alice Ratchet with Bobs PublicKey -//! let data = b"Hello World".to_vec(); // Data to be encrypted -//! let ad = b"Associated Data"; // Associated Data +//! let sk = [1; 32]; // Shared key created by a symmetric key agreement protocol //! -//! let (header1, encrypted1, nonce1) = alice_ratchet.ratchet_encrypt(&data, ad); // Lost message -//! let (header2, encrypted2, nonce2) = alice_ratchet.ratchet_encrypt(&data, ad); // Successful message +//! let (mut bob_ratchet, public_key) = Ratchet::init_bob(sk); // Creating Bob's Ratchet (returns Bob's PublicKey) +//! let mut alice_ratchet = Ratchet::init_alice(sk, public_key); // Creating Alice's Ratchet with Bob's PublicKey //! -//! let decrypted2 = bob_ratchet.ratchet_decrypt(&header2, &encrypted2, &nonce2, ad); // Decrypting second message first -//! let decrypted1 = bob_ratchet.ratchet_decrypt(&header1, &encrypted1, &nonce1, ad); // Decrypting latter message +//! let data = b"Hello World".to_vec(); // Data to be encrypted +//! let ad = b"Associated Data"; // Associated data //! -//! let comp = decrypted1 == data && decrypted2 == data; -//! assert!(comp); +//! let (header1, encrypted1, nonce1) = alice_ratchet.encrypt(&data, ad); // Lost message +//! let (header2, encrypted2, nonce2) = alice_ratchet.encrypt(&data, ad); // Successful message +//! +//! let decrypted2 = bob_ratchet.decrypt(&header2, &encrypted2, &nonce2, ad); // Decrypting second message first +//! let decrypted1 = bob_ratchet.decrypt(&header1, &encrypted1, &nonce1, ad); // Decrypting latter message +//! +//! assert_eq!(data, decrypted1); +//! assert_eq!(data, decrypted2); //! ``` //! -//! ## Encryption before recieving inital message +//! ### Encryption Before Decrypting First Message +//! +//! Bob encrypts a message before decrypting one from Alice. +//! This will result in a panic. //! //! ```should_panic -//! use double_ratchet_2::ratchet::Ratchet; +//! use double_ratchet_rs::Ratchet; +//! //! let sk = [1; 32]; -//! let ad = b"Associated Data"; +//! //! let (mut bob_ratchet, _) = Ratchet::init_bob(sk); +//! //! let data = b"Hello World".to_vec(); +//! let ad = b"Associated Data"; //! -//! let (_, _, _) = bob_ratchet.ratchet_encrypt(&data, ad); +//! let (_, _, _) = bob_ratchet.encrypt(&data, ad); //! ``` //! -//! ## Encryption after recieving initial message -//! However bob can (of course) also encrypt messages. This is possible, after decrypting the first message from alice. +//! ### Encryption After Decrypting First Message +//! +//! Bob *can* also encrypt messages. +//! This is only possible after decrypting one from Alice first though. //! //! ``` -//! use double_ratchet_2::ratchet::Ratchet; +//! use double_ratchet_rs::Ratchet; +//! //! let sk = [1; 32]; //! //! let (mut bob_ratchet, public_key) = Ratchet::init_bob(sk); @@ -67,71 +88,81 @@ //! let data = b"Hello World".to_vec(); //! let ad = b"Associated Data"; //! -//! let (header1, encrypted1, nonce1) = alice_ratchet.ratchet_encrypt(&data, ad); -//! let _decrypted1 = bob_ratchet.ratchet_decrypt(&header1, &encrypted1, &nonce1, ad); +//! let (header1, encrypted1, nonce1) = alice_ratchet.encrypt(&data, ad); +//! let _decrypted1 = bob_ratchet.decrypt(&header1, &encrypted1, &nonce1, ad); //! -//! let (header2, encrypted2, nonce2) = bob_ratchet.ratchet_encrypt(&data, ad); -//! let decrypted2 = alice_ratchet.ratchet_decrypt(&header2, &encrypted2, &nonce2, ad); +//! let (header2, encrypted2, nonce2) = bob_ratchet.encrypt(&data, ad); +//! let decrypted2 = alice_ratchet.decrypt(&header2, &encrypted2, &nonce2, ad); //! //! assert_eq!(data, decrypted2); //! ``` -//! ## Constructing and Deconstructing Headers +//! +//! ### Constructing and Deconstructing Headers //! //! ``` -//! # use double_ratchet_2::ratchet::Ratchet; -//! # use double_ratchet_2::header::Header; -//! # let sk = [1; 32]; -//! # let (mut bob_ratchet, public_key) = Ratchet::init_bob(sk); -//! # let mut alice_ratchet = Ratchet::init_alice(sk, public_key); -//! # let data = b"hello World".to_vec(); -//! # let ad = b"Associated Data"; -//! # let (header, _, _) = alice_ratchet.ratchet_encrypt(&data, ad); +//! use double_ratchet_rs::{Header, Ratchet}; +//! +//! let sk = [1; 32]; +//! +//! let (mut bob_ratchet, public_key) = Ratchet::init_bob(sk); +//! let mut alice_ratchet = Ratchet::init_alice(sk, public_key); +//! +//! let data = b"hello World".to_vec(); +//! let ad = b"Associated Data"; +//! +//! let (header, _, _) = alice_ratchet.encrypt(&data, ad); //! let header_bytes: Vec = header.clone().into(); //! let header_const = Header::from(header_bytes); +//! //! assert_eq!(header, header_const); //! ``` //! -//! # Example Ratchet with encrypted headers +//! ### Encrypted Headers //! //! ``` -//! use double_ratchet_2::ratchet::RatchetEncHeader; +//! use double_ratchet_rs::RatchetEncHeader; +//! //! let sk = [0; 32]; //! let shared_hka = [1; 32]; //! let shared_nhkb = [2; 32]; //! //! let (mut bob_ratchet, public_key) = RatchetEncHeader::init_bob(sk, shared_hka, shared_nhkb); //! let mut alice_ratchet = RatchetEncHeader::init_alice(sk, public_key, shared_hka, shared_nhkb); +//! //! let data = b"Hello World".to_vec(); //! let ad = b"Associated Data"; //! -//! let (header, encrypted, nonce) = alice_ratchet.ratchet_encrypt(&data, ad); -//! let decrypted = bob_ratchet.ratchet_decrypt(&header, &encrypted, &nonce, ad); +//! let (header, encrypted, nonce) = alice_ratchet.encrypt(&data, ad); +//! let decrypted = bob_ratchet.decrypt(&header, &encrypted, &nonce, ad); +//! //! assert_eq!(data, decrypted) //! ``` //! -//! # Export / Import Ratchet with encrypted headers -//! This ratchet implements import and export functionality. This works over a bincode backend and -//! maybe useful for saving Ratchets to and loading from a file. +//! ### Exporting / Importing Ratchet w/ Encrypted Headers +//! +//! This can be used for storing and using ratchets in a file. +//! //! ``` -//! # use double_ratchet_2::ratchet::RatchetEncHeader; -//! # let sk = [0; 32]; -//! # let shared_hka = [1; 32]; -//! # let shared_nhkb = [2; 32]; +//! use double_ratchet_rs::RatchetEncHeader; +//! +//! let sk = [0; 32]; +//! let shared_hka = [1; 32]; +//! let shared_nhkb = [2; 32]; +//! //! let (bob_ratchet, public_key) = RatchetEncHeader::init_bob(sk, shared_hka, shared_nhkb); //! let ex_ratchet = bob_ratchet.export(); //! let im_ratchet = RatchetEncHeader::import(&ex_ratchet).unwrap(); +//! //! assert_eq!(im_ratchet, bob_ratchet) //! ``` //! -//! # Features +//! ## **M**inimum **S**upported **R**ust **V**ersion (MSRV) //! -//! Currently the crate only supports one feature: ring. If feature is enabled the crate switches -//! to ring-compat and uses ring as backend for Sha512 Hashing. May result in slightly better performance. +//! The current MSRV is 1.61.0. //! +//! ## License //! -//! TODO: -//! - [x] Standard Double Ratchet -//! - [x] [Double Ratchet with encrypted headers][3] +//! This project is licensed under the [MIT license](https://github.com/magnetite-dev/double-ratchet-rs/blob/main/LICENSE). //! //! [1]: https://signal.org/docs/specifications/doubleratchet/ //! [2]: https://signal.org/docs/specifications/doubleratchet/#recommended-cryptographic-algorithms @@ -142,15 +173,14 @@ extern crate alloc; -pub use p256::PublicKey; +pub use x25519_dalek::PublicKey; mod aead; mod dh; -mod kdf_root; mod kdf_chain; +mod kdf_root; +mod ratchet; +mod header; -pub mod ratchet; - -/// Message Header -pub mod header; - +pub use ratchet::*; +pub use header::*; diff --git a/src/ratchet.rs b/src/ratchet.rs index 28ff7c5..4fa5eab 100644 --- a/src/ratchet.rs +++ b/src/ratchet.rs @@ -1,24 +1,20 @@ -//! Encryption with encrypted Headers -//! +//! Ratchet providing encryption and decryption. +use crate::aead::{decrypt, encrypt}; use crate::dh::DhKeyPair; -use p256::{PublicKey, SecretKey}; -use hashbrown::HashMap; -use crate::kdf_root::{kdf_rk, kdf_rk_he}; -use crate::header::Header; -use alloc::vec::Vec; +use crate::header::{Header, EncryptedHeader}; use crate::kdf_chain::kdf_ck; -use crate::aead::{encrypt, decrypt}; -use alloc::string::{ToString, String}; -use zeroize::Zeroize; -use rand_core::OsRng; +use crate::kdf_root::{kdf_rk, kdf_rk_he}; +use alloc::vec::Vec; +use hashbrown::HashMap; use serde::{Deserialize, Serialize}; +use x25519_dalek::PublicKey; +use zeroize::Zeroize; const MAX_SKIP: usize = 100; -type HeaderNonceCipherNonce = ((Vec, [u8; 12]), Vec, [u8; 12]); - -/// Object Representing Ratchet +/// A standard ratchet. +#[derive(Deserialize, Serialize, PartialEq, Debug)] pub struct Ratchet { dhs: DhKeyPair, dhr: Option, @@ -28,18 +24,14 @@ pub struct Ratchet { ns: usize, nr: usize, pn: usize, - mkskipped: HashMap<(Vec, usize), [u8; 32]>, + mkskipped: HashMap<([u8; 32], usize), [u8; 32]>, } -impl Drop for Ratchet { - fn drop(&mut self) { - if let Some(mut _d) = self.dhr { - let sk = SecretKey::random(&mut OsRng); - _d = sk.public_key() - } +impl Zeroize for Ratchet { + fn zeroize(&mut self) { self.rk.zeroize(); - self.ckr.zeroize(); self.cks.zeroize(); + self.ckr.zeroize(); self.ns.zeroize(); self.nr.zeroize(); self.pn.zeroize(); @@ -47,12 +39,19 @@ impl Drop for Ratchet { } } +impl Drop for Ratchet { + fn drop(&mut self) { + self.zeroize(); + } +} + impl Ratchet { - /// Init Ratchet with other [PublicKey]. Initialized second. + /// Initialize a [Ratchet] with a remote [PublicKey]. Initialized second. + /// Requires a shared key and a [PublicKey]. + /// Returns a [Ratchet]. pub fn init_alice(sk: [u8; 32], bob_dh_public_key: PublicKey) -> Self { let dhs = DhKeyPair::new(); - let (rk, cks) = kdf_rk(&sk, - &dhs.key_agreement(&bob_dh_public_key)); + let (rk, cks) = kdf_rk(&sk, &dhs.key_agreement(&bob_dh_public_key)); Ratchet { dhs, dhr: Some(bob_dh_public_key), @@ -66,7 +65,9 @@ impl Ratchet { } } - /// Init Ratchet without other [PublicKey]. Initialized first. Returns [Ratchet] and [PublicKey]. + /// Initialize a [Ratchet] without a remote [PublicKey]. Initialized first. + /// Requires a shared key. + /// Returns a [Ratchet] and a [PublicKey]. pub fn init_bob(sk: [u8; 32]) -> (Self, PublicKey) { let dhs = DhKeyPair::new(); let public_key = dhs.public_key; @@ -84,22 +85,37 @@ impl Ratchet { (ratchet, public_key) } - /// Encrypt Plaintext with [Ratchet]. Returns Message [Header] and ciphertext. - pub fn ratchet_encrypt(&mut self, plaintext: &[u8], ad: &[u8]) -> (Header, Vec, [u8; 12]) { + /// Encrypt bytes with a [Ratchet]. + /// Requires bytes and associated bytes. + /// Returns a [Header], encrypted bytes, and a nonce. + pub fn encrypt(&mut self, data: &[u8], associated_data: &[u8]) -> (Header, Vec, [u8; 12]) { let (cks, mk) = kdf_ck(&self.cks.unwrap()); self.cks = Some(cks); let header = Header::new(&self.dhs, self.pn, self.ns); self.ns += 1; - let (encrypted_data, nonce) = encrypt(&mk, plaintext, &header.concat(ad)); + let (encrypted_data, nonce) = encrypt(&mk, data, &header.concat(associated_data)); (header, encrypted_data, nonce) } - fn try_skipped_message_keys(&mut self, header: &Header, ciphertext: &[u8], nonce: &[u8; 12], ad: &[u8]) -> Option> { - if self.mkskipped.contains_key(&(header.ex_public_key_bytes(), header.n)) { - let mk = *self.mkskipped.get(&(header.ex_public_key_bytes(), header.n)) + fn try_skipped_message_keys( + &mut self, + header: &Header, + enc_data: &[u8], + nonce: &[u8; 12], + associated_data: &[u8], + ) -> Option> { + if self + .mkskipped + .contains_key(&(header.public_key.to_bytes(), header.n)) + { + let mk = *self + .mkskipped + .get(&(header.public_key.to_bytes(), header.n)) .unwrap(); - self.mkskipped.remove(&(header.ex_public_key_bytes(), header.n)).unwrap(); - Some(decrypt(&mk, ciphertext, &header.concat(ad), nonce)) + self.mkskipped + .remove(&(header.public_key.to_bytes(), header.n)) + .unwrap(); + Some(decrypt(&mk, enc_data, &header.concat(associated_data), nonce)) } else { None } @@ -115,19 +131,28 @@ impl Ratchet { let (ckr, mk) = kdf_ck(&d); self.ckr = Some(ckr); d = ckr; - self.mkskipped.insert((self.dhr.unwrap().to_string().as_bytes().to_vec(), self.nr), mk); + self.mkskipped + .insert((self.dhr.unwrap().to_bytes(), self.nr), mk); self.nr += 1 } Ok(()) - }, - None => { Err("No Ckr set") } + } + None => Err("No Ckr set"), } } - /// Decrypt ciphertext with ratchet. Requires Header. Returns plaintext. - pub fn ratchet_decrypt(&mut self, header: &Header, ciphertext: &[u8], nonce: &[u8; 12], ad: &[u8]) -> Vec { - let plaintext = self.try_skipped_message_keys(header, ciphertext, nonce, ad); - match plaintext { + /// Decrypt encrypted bytes with a [Ratchet]. + /// Requires a [Header], encrypted bytes, a nonce, and associated bytes. + /// Returns decrypted bytes. + pub fn decrypt( + &mut self, + header: &Header, + enc_data: &[u8], + nonce: &[u8; 12], + associated_data: &[u8], + ) -> Vec { + let data = self.try_skipped_message_keys(header, enc_data, nonce, associated_data); + match data { Some(d) => d, None => { if Some(header.public_key) != self.dhr { @@ -140,7 +165,7 @@ impl Ratchet { let (ckr, mk) = kdf_ck(&self.ckr.unwrap()); self.ckr = Some(ckr); self.nr += 1; - decrypt(&mk, ciphertext, &header.concat(ad), nonce) + decrypt(&mk, enc_data, &header.concat(associated_data), nonce) } } } @@ -150,19 +175,31 @@ impl Ratchet { self.ns = 0; self.nr = 0; self.dhr = Some(header.public_key); - let (rk, ckr) = kdf_rk(&self.rk, - &self.dhs.key_agreement(&self.dhr.unwrap())); + let (rk, ckr) = kdf_rk(&self.rk, &self.dhs.key_agreement(&self.dhr.unwrap())); self.rk = rk; self.ckr = Some(ckr); self.dhs = DhKeyPair::new(); - let (rk, cks) = kdf_rk(&self.rk, - &self.dhs.key_agreement(&self.dhr.unwrap())); + let (rk, cks) = kdf_rk(&self.rk, &self.dhs.key_agreement(&self.dhr.unwrap())); self.rk = rk; self.cks = Some(cks); } + + /// Export a [Ratchet]. + /// Returns bytes. + pub fn export(&self) -> Vec { + postcard::to_allocvec(&self).unwrap() + } + + /// Import a previously exported [Ratchet]. + /// Requires bytes. + /// Returns a [Ratchet], or nothing if invalid data is provided. + pub fn import(data: &[u8]) -> Option { + postcard::from_bytes(data).ok() + } } -#[derive(PartialEq, Debug)] +/// A [Ratchet], but with header encryption. +#[derive(Deserialize, Serialize, PartialEq, Debug)] pub struct RatchetEncHeader { dhs: DhKeyPair, dhr: Option, @@ -176,7 +213,7 @@ pub struct RatchetEncHeader { hkr: Option<[u8; 32]>, nhks: Option<[u8; 32]>, nhkr: Option<[u8; 32]>, - mkskipped: HashMap<(Option<[u8; 32]>, usize), [u8; 32]> + mkskipped: HashMap<(Option<[u8; 32]>, usize), [u8; 32]>, } impl Zeroize for RatchetEncHeader { @@ -192,7 +229,6 @@ impl Zeroize for RatchetEncHeader { self.nhks.zeroize(); self.nhkr.zeroize(); self.mkskipped.clear(); - } } @@ -202,90 +238,16 @@ impl Drop for RatchetEncHeader { } } -#[derive(Serialize, Deserialize)] -struct ExRatchetEncHeader { - dhs: (String, String), - dhr: Option, - rk: [u8; 32], - cks: Option<[u8; 32]>, - ckr: Option<[u8; 32]>, - ns: usize, - nr: usize, - pn: usize, - hks: Option<[u8; 32]>, - hkr: Option<[u8; 32]>, - nhks: Option<[u8; 32]>, - nhkr: Option<[u8; 32]>, - mkskipped: HashMap<(Option<[u8; 32]>, usize), [u8; 32]> -} - -impl From<&RatchetEncHeader> for ExRatchetEncHeader { - fn from(reh: &RatchetEncHeader) -> Self { - let private_dhs = reh.dhs.private_key.to_jwk_string(); - let public_dhs = reh.dhs.public_key.to_jwk_string(); - let dhs = (private_dhs.to_string(), public_dhs); - let dhr = reh.dhr.map(|e| e.to_jwk_string()); - let rk = reh.rk; - let cks = reh.cks; - let ckr = reh.ckr; - let ns = reh.ns; - let nr = reh.nr; - let pn = reh.pn; - let hks = reh.hks; - let hkr = reh.hkr; - let nhks = reh.nhks; - let nhkr = reh.nhkr; - let mkskipped = reh.mkskipped.clone(); - Self { - dhs, - dhr, - rk, - cks, - ckr, - ns, - nr, - pn, - hks, - hkr, - nhks, - nhkr, - mkskipped - } - } -} - -impl From<&ExRatchetEncHeader> for RatchetEncHeader { - fn from(ex_reh: &ExRatchetEncHeader) -> Self { - let private_dhs = SecretKey::from_jwk_str(&ex_reh.dhs.0).unwrap(); - let public_dhs = PublicKey::from_jwk_str(&ex_reh.dhs.1).unwrap(); - let dhs = DhKeyPair { - private_key: private_dhs, - public_key: public_dhs - }; - let dhr = ex_reh.dhr.as_ref().map(|e| PublicKey::from_jwk_str(e).unwrap()); - Self { - dhs, - dhr, - rk: ex_reh.rk, - cks: ex_reh.cks, - ckr: ex_reh.ckr, - ns: ex_reh.ns, - nr: ex_reh.nr, - pn: ex_reh.pn, - hks: ex_reh.hks, - hkr: ex_reh.hkr, - nhks: ex_reh.nhks, - nhkr: ex_reh.nhkr, - mkskipped: ex_reh.mkskipped.clone() - } - } -} - impl RatchetEncHeader { - pub fn init_alice(sk: [u8; 32], - bob_dh_public_key: PublicKey, - shared_hka: [u8; 32], - shared_nhkb: [u8; 32]) -> Self { + /// Initialize a [RatchetEncHeader] with a remote [PublicKey]. Initialized second. + /// Requires a shared key, a [PublicKey], a shared HKA, and a shared NHKB. + /// Returns a [RatchetEncHeader]. + pub fn init_alice( + sk: [u8; 32], + bob_dh_public_key: PublicKey, + shared_hka: [u8; 32], + shared_nhkb: [u8; 32], + ) -> Self { let dhs = DhKeyPair::new(); let (rk, cks, nhks) = kdf_rk_he(&sk, &dhs.key_agreement(&bob_dh_public_key)); RatchetEncHeader { @@ -305,7 +267,14 @@ impl RatchetEncHeader { } } - pub fn init_bob(sk: [u8; 32], shared_hka: [u8; 32], shared_nhkb: [u8; 32]) -> (Self, PublicKey) { + /// Initialize a [RatchetEncHeader] without a remote [PublicKey]. Initialized first. + /// Requires a shared key, a shared HKA, and a shared NHKB. + /// Returns a [RatchetEncHeader] and a [PublicKey]. + pub fn init_bob( + sk: [u8; 32], + shared_hka: [u8; 32], + shared_nhkb: [u8; 32], + ) -> (Self, PublicKey) { let dhs = DhKeyPair::new(); let public_key = dhs.public_key; let ratchet = Self { @@ -326,50 +295,70 @@ impl RatchetEncHeader { (ratchet, public_key) } - pub fn ratchet_encrypt(&mut self, plaintext: &[u8], ad: &[u8]) -> HeaderNonceCipherNonce { + /// Encrypt bytes with a [RatchetEncHeader]. + /// Requires bytes and associated bytes. + /// Returns an [EncryptedHeader], encrypted bytes, and a nonce. + pub fn encrypt(&mut self, data: &[u8], associated_data: &[u8]) -> (EncryptedHeader, Vec, [u8; 12]) { let (cks, mk) = kdf_ck(&self.cks.unwrap()); self.cks = Some(cks); let header = Header::new(&self.dhs, self.pn, self.ns); - let enc_header = header.encrypt(&self.hks.unwrap(), ad); + let enc_header = header.encrypt(&self.hks.unwrap(), associated_data); self.ns += 1; - let encrypted = encrypt(&mk, plaintext, &header.concat(ad)); + let encrypted = encrypt(&mk, data, &header.concat(associated_data)); (enc_header, encrypted.0, encrypted.1) } - fn try_skipped_message_keys(&mut self, enc_header: &(Vec, [u8; 12]), - ciphertext: &[u8], nonce: &[u8; 12], ad: &[u8]) -> (Option>, Option
) { - + fn try_skipped_message_keys( + &mut self, + enc_header: &EncryptedHeader, + enc_data: &[u8], + nonce: &[u8; 12], + associated_data: &[u8], + ) -> (Option>, Option
) { let ret_data = self.mkskipped.clone().into_iter().find(|e| { - let header = Header::decrypt(&e.0.0, &enc_header.0, &enc_header.1); + let header = enc_header.decrypt(&e.0.0); match header { None => false, - Some(h) => h.n == e.0.1 + Some(h) => h.n == e.0 .1, } }); match ret_data { - None => { (None, None) }, + None => (None, None), Some(data) => { - let header = Header::decrypt(&data.0.0, &enc_header.0, &enc_header.1); + let header = enc_header.decrypt(&data.0.0); let mk = data.1; - self.mkskipped.remove(&(data.0.0, data.0.1)); - (Some(decrypt(&mk, ciphertext, &header.clone().unwrap().concat(ad), nonce)), header) + self.mkskipped.remove(&(data.0 .0, data.0 .1)); + ( + Some(decrypt( + &mk, + enc_data, + &header.clone().unwrap().concat(associated_data), + nonce, + )), + header, + ) } } } - fn decrypt_header(&mut self, enc_header: &(Vec, [u8; 12])) -> Result<(Header, bool), &str> { - let header = Header::decrypt(&self.hkr, &enc_header.0, &enc_header.1); - if let Some(h) = header { return Ok((h, false)) }; - let header = Header::decrypt(&self.nhkr, &enc_header.0, &enc_header.1); + /// Decrypt an [EncryptedHeader] with a [RatchetEncHeader]. + /// Requires an [EncryptedHeader]. + /// Returns a decrypted [Header] and boolean, if decryption was successful. + fn decrypt_header(&mut self, enc_header: &EncryptedHeader) -> Result<(Header, bool), &str> { + let header = enc_header.decrypt(&self.hkr); + if let Some(h) = header { + return Ok((h, false)); + }; + let header = enc_header.decrypt(&self.nhkr); match header { Some(h) => Ok((h, true)), - None => Err("Header is unencryptable!") + None => Err("Header is unencryptable!"), } } fn skip_message_keys(&mut self, until: usize) -> Result<(), &str> { if self.nr + MAX_SKIP < until { - return Err("Skipping went wrong") + return Err("Skipping went wrong"); } if let Some(d) = &mut self.ckr { while self.nr < until { @@ -389,22 +378,31 @@ impl RatchetEncHeader { self.hks = self.nhks; self.hkr = self.nhkr; self.dhr = Some(header.public_key); - let (rk, ckr, nhkr) = kdf_rk_he(&self.rk, - &self.dhs.key_agreement(&self.dhr.unwrap())); + let (rk, ckr, nhkr) = kdf_rk_he(&self.rk, &self.dhs.key_agreement(&self.dhr.unwrap())); self.rk = rk; self.ckr = Some(ckr); self.nhkr = Some(nhkr); self.dhs = DhKeyPair::new(); - let (rk, cks, nhks) = kdf_rk_he(&self.rk, - &self.dhs.key_agreement(&self.dhr.unwrap())); + let (rk, cks, nhks) = kdf_rk_he(&self.rk, &self.dhs.key_agreement(&self.dhr.unwrap())); self.rk = rk; self.cks = Some(cks); self.nhks = Some(nhks); } - pub fn ratchet_decrypt(&mut self, enc_header: &(Vec, [u8; 12]), ciphertext: &[u8], nonce: &[u8; 12], ad: &[u8]) -> Vec { - let (plaintext, _) = self.try_skipped_message_keys(enc_header, ciphertext, nonce, ad); - if let Some(d) = plaintext { return d }; + /// Decrypt encrypted bytes with a [RatchetEncHeader]. + /// Requires an [EncryptedHeader], encrypted bytes, a nonce, and associated bytes. + /// Returns decrypted bytes. + pub fn decrypt( + &mut self, + enc_header: &EncryptedHeader, + enc_data: &[u8], + nonce: &[u8; 12], + associated_data: &[u8], + ) -> Vec { + let (data, _) = self.try_skipped_message_keys(enc_header, enc_data, nonce, associated_data); + if let Some(d) = data { + return d; + }; let (header, dh_ratchet) = self.decrypt_header(enc_header).unwrap(); if dh_ratchet { self.skip_message_keys(header.pn).unwrap(); @@ -414,12 +412,23 @@ impl RatchetEncHeader { let (ckr, mk) = kdf_ck(&self.ckr.unwrap()); self.ckr = Some(ckr); self.nr += 1; - decrypt(&mk, ciphertext, &header.concat(ad), nonce) + decrypt(&mk, enc_data, &header.concat(associated_data), nonce) } - pub fn ratchet_decrypt_w_header(&mut self, enc_header: &(Vec, [u8; 12]), ciphertext: &[u8], nonce: &[u8; 12], ad: &[u8]) -> (Vec, Header) { - let (plaintext, header) = self.try_skipped_message_keys(enc_header, ciphertext, nonce, ad); - if let Some(d) = plaintext { return (d, header.unwrap()) }; + /// Decrypt encrypted bytes and an [EncryptedHeader] with a [RatchetEncHeader]. + /// Requires an [EncryptedHeader], encrypted bytes, a nonce, and associated bytes. + /// Returns decrypted bytes and a [Header]. + pub fn decrypt_with_header( + &mut self, + enc_header: &EncryptedHeader, + enc_data: &[u8], + nonce: &[u8; 12], + associated_data: &[u8], + ) -> (Vec, Header) { + let (data, header) = self.try_skipped_message_keys(enc_header, enc_data, nonce, associated_data); + if let Some(d) = data { + return (d, header.unwrap()); + }; let (header, dh_ratchet) = self.decrypt_header(enc_header).unwrap(); if dh_ratchet { self.skip_message_keys(header.pn).unwrap(); @@ -429,18 +438,22 @@ impl RatchetEncHeader { let (ckr, mk) = kdf_ck(&self.ckr.unwrap()); self.ckr = Some(ckr); self.nr += 1; - (decrypt(&mk, ciphertext, &header.concat(ad), nonce), header) + ( + decrypt(&mk, enc_data, &header.concat(associated_data), nonce), + header, + ) } - /// Export the ratchet to Binary data + /// Export a [RatchetEncHeader]. + /// Returns bytes. pub fn export(&self) -> Vec { - let ex: ExRatchetEncHeader = self.into(); - bincode::serialize(&ex).unwrap() + postcard::to_allocvec(&self).unwrap() } - /// Import the ratchet from Binary data. Panics when binary data is invalid. - pub fn import(inp: &[u8]) -> Option { - let ex: ExRatchetEncHeader = bincode::deserialize(inp).ok()?; - Some(RatchetEncHeader::from(&ex)) + /// Import a previously exported [RatchetEncHeader]. + /// Requires bytes. + /// Returns a [RatchetEncHeader], or nothing if invalid data is provided. + pub fn import(data: &[u8]) -> Option { + postcard::from_bytes(data).ok() } } diff --git a/tests/mod.rs b/tests/mod.rs index b9713c8..234d8f3 100644 --- a/tests/mod.rs +++ b/tests/mod.rs @@ -1,167 +1,145 @@ -use double_ratchet_2::ratchet::{Ratchet, RatchetEncHeader}; +use double_ratchet_rs::{Ratchet, RatchetEncHeader}; extern crate alloc; #[test] -fn ratchet_init() { +fn init() { let sk = [1; 32]; let (_bob_ratchet, public_key) = Ratchet::init_bob(sk); let _alice_ratchet = Ratchet::init_alice(sk, public_key); } #[test] -fn ratchet_enc_single() { +fn enc_single() { let sk = [1; 32]; let (mut bob_ratchet, public_key) = Ratchet::init_bob(sk); let mut alice_ratchet = Ratchet::init_alice(sk, public_key); let data = include_bytes!("../src/header.rs").to_vec(); - let (header, encrypted, nonce) = alice_ratchet.ratchet_encrypt(&data, b""); - let decrypted = bob_ratchet.ratchet_decrypt(&header, &encrypted, &nonce, b""); + let (header, encrypted, nonce) = alice_ratchet.encrypt(&data, b""); + let decrypted = bob_ratchet.decrypt(&header, &encrypted, &nonce, b""); assert_eq!(data, decrypted) } #[test] -fn ratchet_enc_skip() { +fn enc_skip() { let sk = [1; 32]; let (mut bob_ratchet, public_key) = Ratchet::init_bob(sk); let mut alice_ratchet = Ratchet::init_alice(sk, public_key); let data = include_bytes!("../src/header.rs").to_vec(); - let (header1, encrypted1, nonce1) = alice_ratchet.ratchet_encrypt(&data, b""); - let (header2, encrypted2, nonce2) = alice_ratchet.ratchet_encrypt(&data, b""); - let (header3, encrypted3, nonce3) = alice_ratchet.ratchet_encrypt(&data, b""); - let decrypted3 = bob_ratchet.ratchet_decrypt(&header3, &encrypted3, &nonce3, b""); - let decrypted2 = bob_ratchet.ratchet_decrypt(&header2, &encrypted2, &nonce2, b""); - let decrypted1 = bob_ratchet.ratchet_decrypt(&header1, &encrypted1, &nonce1, b""); + let (header1, encrypted1, nonce1) = alice_ratchet.encrypt(&data, b""); + let (header2, encrypted2, nonce2) = alice_ratchet.encrypt(&data, b""); + let (header3, encrypted3, nonce3) = alice_ratchet.encrypt(&data, b""); + let decrypted3 = bob_ratchet.decrypt(&header3, &encrypted3, &nonce3, b""); + let decrypted2 = bob_ratchet.decrypt(&header2, &encrypted2, &nonce2, b""); + let decrypted1 = bob_ratchet.decrypt(&header1, &encrypted1, &nonce1, b""); let comp_res = decrypted1 == data && decrypted2 == data && decrypted3 == data; assert!(comp_res) } #[test] #[should_panic] -fn ratchet_panic_bob() { +fn panic_bob() { let sk = [1; 32]; let (mut bob_ratchet, _) = Ratchet::init_bob(sk); let data = include_bytes!("../src/header.rs").to_vec(); - let (_, _, _) = bob_ratchet.ratchet_encrypt(&data, b""); + let (_, _, _) = bob_ratchet.encrypt(&data, b""); } #[test] -fn ratchet_encryt_decrypt_four() { +fn encryt_decrypt_four() { let sk = [1; 32]; let data = include_bytes!("../src/dh.rs").to_vec(); let (mut bob_ratchet, public_key) = Ratchet::init_bob(sk); let mut alice_ratchet = Ratchet::init_alice(sk, public_key); - let (header1, encrypted1, nonce1) = alice_ratchet.ratchet_encrypt(&data, b""); - let decrypted1 = bob_ratchet.ratchet_decrypt(&header1, &encrypted1, &nonce1, b""); - let (header2, encrypted2, nonce2) = bob_ratchet.ratchet_encrypt(&data, b""); - let decrypted2 = alice_ratchet.ratchet_decrypt(&header2, &encrypted2, &nonce2, b""); + let (header1, encrypted1, nonce1) = alice_ratchet.encrypt(&data, b""); + let decrypted1 = bob_ratchet.decrypt(&header1, &encrypted1, &nonce1, b""); + let (header2, encrypted2, nonce2) = bob_ratchet.encrypt(&data, b""); + let decrypted2 = alice_ratchet.decrypt(&header2, &encrypted2, &nonce2, b""); let comp_res = decrypted1 == data && decrypted2 == data; assert!(comp_res) } #[test] -fn ratchet_ench_init() { +fn ench_init() { let sk = [1; 32]; let shared_hka = [2; 32]; let shared_nhkb = [3; 32]; - let (_bob_ratchet, public_key) = RatchetEncHeader::init_bob(sk, - shared_hka, - shared_nhkb); - let _alice_ratchet = RatchetEncHeader::init_alice(sk, public_key, - shared_hka, shared_nhkb); + let (_bob_ratchet, public_key) = RatchetEncHeader::init_bob(sk, shared_hka, shared_nhkb); + let _alice_ratchet = RatchetEncHeader::init_alice(sk, public_key, shared_hka, shared_nhkb); } #[test] -fn ratchet_ench_enc_single() { +fn ench_enc_single() { let sk = [1; 32]; let shared_hka = [2; 32]; let shared_nhkb = [3; 32]; - let (mut bob_ratchet, public_key) = RatchetEncHeader::init_bob(sk, - shared_hka, - shared_nhkb); - let mut alice_ratchet = RatchetEncHeader::init_alice(sk, - public_key, - shared_hka, - shared_nhkb); + let (mut bob_ratchet, public_key) = RatchetEncHeader::init_bob(sk, shared_hka, shared_nhkb); + let mut alice_ratchet = RatchetEncHeader::init_alice(sk, public_key, shared_hka, shared_nhkb); let data = include_bytes!("../src/header.rs").to_vec(); - let (header, encrypted, nonce) = alice_ratchet.ratchet_encrypt(&data, b""); - let decrypted = bob_ratchet.ratchet_decrypt(&header, &encrypted, &nonce, b""); + let (header, encrypted, nonce) = alice_ratchet.encrypt(&data, b""); + let decrypted = bob_ratchet.decrypt(&header, &encrypted, &nonce, b""); assert_eq!(data, decrypted) } #[test] -fn ratchet_ench_enc_skip() { +fn ench_enc_skip() { let sk = [1; 32]; let shared_hka = [2; 32]; let shared_nhkb = [3; 32]; - let (mut bob_ratchet, public_key) = RatchetEncHeader::init_bob(sk, - shared_hka, - shared_nhkb); - let mut alice_ratchet = RatchetEncHeader::init_alice(sk, - public_key, - shared_hka, - shared_nhkb); + let (mut bob_ratchet, public_key) = RatchetEncHeader::init_bob(sk, shared_hka, shared_nhkb); + let mut alice_ratchet = RatchetEncHeader::init_alice(sk, public_key, shared_hka, shared_nhkb); let data = include_bytes!("../src/header.rs").to_vec(); - let (header1, encrypted1, nonce1) = alice_ratchet.ratchet_encrypt(&data, b""); - let (header2, encrypted2, nonce2) = alice_ratchet.ratchet_encrypt(&data, b""); - let (header3, encrypted3, nonce3) = alice_ratchet.ratchet_encrypt(&data, b""); - let decrypted3 = bob_ratchet.ratchet_decrypt(&header3, &encrypted3, &nonce3, b""); - let decrypted2 = bob_ratchet.ratchet_decrypt(&header2, &encrypted2, &nonce2, b""); - let decrypted1 = bob_ratchet.ratchet_decrypt(&header1, &encrypted1, &nonce1, b""); + let (header1, encrypted1, nonce1) = alice_ratchet.encrypt(&data, b""); + let (header2, encrypted2, nonce2) = alice_ratchet.encrypt(&data, b""); + let (header3, encrypted3, nonce3) = alice_ratchet.encrypt(&data, b""); + let decrypted3 = bob_ratchet.decrypt(&header3, &encrypted3, &nonce3, b""); + let decrypted2 = bob_ratchet.decrypt(&header2, &encrypted2, &nonce2, b""); + let decrypted1 = bob_ratchet.decrypt(&header1, &encrypted1, &nonce1, b""); let comp_res = decrypted1 == data && decrypted2 == data && decrypted3 == data; assert!(comp_res) } #[test] #[should_panic] -fn ratchet_ench_panic_bob() { +fn ench_panic_bob() { let sk = [1; 32]; let shared_hka = [2; 32]; let shared_nhkb = [3; 32]; - let (mut bob_ratchet, _) = RatchetEncHeader::init_bob(sk, - shared_hka, - shared_nhkb); + let (mut bob_ratchet, _) = RatchetEncHeader::init_bob(sk, shared_hka, shared_nhkb); let data = include_bytes!("../src/header.rs").to_vec(); - let (_, _, _) = bob_ratchet.ratchet_encrypt(&data, b""); + let (_, _, _) = bob_ratchet.encrypt(&data, b""); } #[test] -fn ratchet_ench_decrypt_four() { +fn ench_decrypt_four() { let sk = [1; 32]; let shared_hka = [2; 32]; let shared_nhkb = [3; 32]; - let (mut bob_ratchet, public_key) = RatchetEncHeader::init_bob(sk, - shared_hka, - shared_nhkb); + let (mut bob_ratchet, public_key) = RatchetEncHeader::init_bob(sk, shared_hka, shared_nhkb); let mut alice_ratchet = RatchetEncHeader::init_alice(sk, public_key, shared_hka, shared_nhkb); let data = include_bytes!("../src/dh.rs").to_vec(); - let (header1, encrypted1, nonce1) = alice_ratchet.ratchet_encrypt(&data, b""); - let decrypted1 = bob_ratchet.ratchet_decrypt(&header1, &encrypted1, &nonce1, b""); - let (header2, encrypted2, nonce2) = bob_ratchet.ratchet_encrypt(&data, b""); - let decrypted2 = alice_ratchet.ratchet_decrypt(&header2, &encrypted2, &nonce2, b""); + let (header1, encrypted1, nonce1) = alice_ratchet.encrypt(&data, b""); + let decrypted1 = bob_ratchet.decrypt(&header1, &encrypted1, &nonce1, b""); + let (header2, encrypted2, nonce2) = bob_ratchet.encrypt(&data, b""); + let decrypted2 = alice_ratchet.decrypt(&header2, &encrypted2, &nonce2, b""); let comp_res = decrypted1 == data && decrypted2 == data; assert!(comp_res) } #[test] #[should_panic] -fn ratchet_ench_enc_skip_panic() { +fn ench_enc_skip_panic() { let sk = [1; 32]; let shared_hka = [2; 32]; let shared_nhkb = [3; 32]; - let (mut bob_ratchet, public_key) = RatchetEncHeader::init_bob(sk, - shared_hka, - shared_nhkb); - let mut alice_ratchet = RatchetEncHeader::init_alice(sk, - public_key, - shared_hka, - shared_nhkb); + let (mut bob_ratchet, public_key) = RatchetEncHeader::init_bob(sk, shared_hka, shared_nhkb); + let mut alice_ratchet = RatchetEncHeader::init_alice(sk, public_key, shared_hka, shared_nhkb); let data = include_bytes!("../src/header.rs").to_vec(); let mut headers = alloc::vec![]; let mut encrypteds = alloc::vec![]; let mut nonces = alloc::vec![]; let mut decrypteds = alloc::vec![]; for _ in 0..200 { - let (header, encrypted, nonce) = alice_ratchet.ratchet_encrypt(&data, b""); + let (header, encrypted, nonce) = alice_ratchet.encrypt(&data, b""); headers.push(header); encrypteds.push(encrypted); nonces.push(nonce); @@ -173,7 +151,7 @@ fn ratchet_ench_enc_skip_panic() { let header = headers.get(idx).unwrap(); let encrypted = encrypteds.get(idx).unwrap(); let nonce = nonces.get(idx).unwrap(); - let decrypted = bob_ratchet.ratchet_decrypt(header, encrypted, nonce, b""); + let decrypted = bob_ratchet.decrypt(header, encrypted, nonce, b""); decrypteds.push(decrypted); } } @@ -183,9 +161,7 @@ fn import_export() { let sk = [1; 32]; let shared_hka = [2; 32]; let shared_nhkb = [3; 32]; - let (bob_ratchet, public_key) = RatchetEncHeader::init_bob(sk, - shared_hka, - shared_nhkb); + let (bob_ratchet, public_key) = RatchetEncHeader::init_bob(sk, shared_hka, shared_nhkb); let alice_ratchet = RatchetEncHeader::init_alice(sk, public_key, shared_hka, shared_nhkb); let ex_bob_ratchet = bob_ratchet.export();