mirror of
https://github.com/logos-messaging/libchat.git
synced 2026-02-09 16:33:10 +00:00
Double ratchet FFI usage in Nim (#14)
* feat: ffi * feat: ffi interface and header generation * feat: nim ffi example * chore: doc * fix: encrypt state clean * chore: zeroize when drop
This commit is contained in:
parent
fc76453f4c
commit
58392841cd
3
.gitignore
vendored
3
.gitignore
vendored
@ -21,3 +21,6 @@ target
|
||||
#.idea/
|
||||
|
||||
*/.DS_Store
|
||||
|
||||
# Compiled binary
|
||||
**/ffi_nim_example
|
||||
|
||||
295
Cargo.lock
generated
295
Cargo.lock
generated
@ -114,7 +114,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.111",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -137,10 +137,53 @@ dependencies = [
|
||||
"hkdf",
|
||||
"rand",
|
||||
"rand_core",
|
||||
"safer-ffi",
|
||||
"thiserror",
|
||||
"x25519-dalek",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||
|
||||
[[package]]
|
||||
name = "ext-trait"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d772df1c1a777963712fb68e014235e80863d6a91a85c4e06ba2d16243a310e5"
|
||||
dependencies = [
|
||||
"ext-trait-proc_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ext-trait-proc_macros"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ab7934152eaf26aa5aa9f7371408ad5af4c31357073c9e84c3b9d7f11ad639a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "extension-traits"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a296e5a895621edf9fa8329c83aa1cb69a964643e36cf54d8d7a69b789089537"
|
||||
dependencies = [
|
||||
"ext-trait",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "extern-c"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "320bea982e85d42441eb25c49b41218e7eaa2657e8f90bc4eca7437376751e23"
|
||||
|
||||
[[package]]
|
||||
name = "fiat-crypto"
|
||||
version = "0.2.9"
|
||||
@ -168,6 +211,12 @@ dependencies = [
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.16.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
|
||||
|
||||
[[package]]
|
||||
name = "hkdf"
|
||||
version = "0.12.4"
|
||||
@ -186,6 +235,16 @@ dependencies = [
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inout"
|
||||
version = "0.1.4"
|
||||
@ -195,6 +254,15 @@ dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inventory"
|
||||
version = "0.3.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc61209c082fbeb19919bee74b176221b27223e27b65d781eb91af24eb1fb46e"
|
||||
dependencies = [
|
||||
"rustversion",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.178"
|
||||
@ -208,12 +276,40 @@ dependencies = [
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "macro_rules_attribute"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf0c9b980bf4f3a37fd7b1c066941dd1b1d0152ce6ee6e8fe8c49b9f6810d862"
|
||||
dependencies = [
|
||||
"macro_rules_attribute-proc_macro",
|
||||
"paste",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "macro_rules_attribute-proc_macro"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "58093314a45e00c77d5c508f76e77c3396afbbc0d01506e7fae47b018bac2b1d"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
|
||||
|
||||
[[package]]
|
||||
name = "opaque-debug"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
||||
|
||||
[[package]]
|
||||
name = "poly1305"
|
||||
version = "0.8.0"
|
||||
@ -234,6 +330,25 @@ dependencies = [
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prettyplease"
|
||||
version = "0.1.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-crate"
|
||||
version = "3.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983"
|
||||
dependencies = [
|
||||
"toml_edit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.103"
|
||||
@ -291,6 +406,50 @@ dependencies = [
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
|
||||
|
||||
[[package]]
|
||||
name = "safer-ffi"
|
||||
version = "0.1.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "435fdd58b61a6f1d8545274c1dfa458e905ff68c166e65e294a0130ef5e675bd"
|
||||
dependencies = [
|
||||
"extern-c",
|
||||
"inventory",
|
||||
"libc",
|
||||
"macro_rules_attribute",
|
||||
"paste",
|
||||
"safer_ffi-proc_macros",
|
||||
"scopeguard",
|
||||
"stabby",
|
||||
"uninit",
|
||||
"unwind_safe",
|
||||
"with_builtin_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "safer_ffi-proc_macros"
|
||||
version = "0.1.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0f25be5ba5f319542edb31925517e0380245ae37df50a9752cdbc05ef948156"
|
||||
dependencies = [
|
||||
"macro_rules_attribute",
|
||||
"prettyplease",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.27"
|
||||
@ -324,7 +483,48 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.111",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2-const-stable"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f179d4e11094a893b82fff208f74d448a7512f99f5a0acbd5c679b705f83ed9"
|
||||
|
||||
[[package]]
|
||||
name = "stabby"
|
||||
version = "36.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89b7e94eaf470c2e76b5f15fb2fb49714471a36cc512df5ee231e62e82ec79f8"
|
||||
dependencies = [
|
||||
"rustversion",
|
||||
"stabby-abi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stabby-abi"
|
||||
version = "36.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0dc7a63b8276b54e51bfffe3d85da56e7906b2dcfcb29018a8ab666c06734c1a"
|
||||
dependencies = [
|
||||
"rustc_version",
|
||||
"rustversion",
|
||||
"sha2-const-stable",
|
||||
"stabby-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stabby-macros"
|
||||
version = "36.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eecb7ec5611ec93ec79d120fbe55f31bea234dc1bed1001d4a071bb688651615"
|
||||
dependencies = [
|
||||
"proc-macro-crate",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rand",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -333,6 +533,17 @@ version = "2.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.109"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.111"
|
||||
@ -361,7 +572,37 @@ checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.111",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.7.5+spec-1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.23.10+spec-1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"toml_datetime",
|
||||
"toml_parser",
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_parser"
|
||||
version = "1.0.6+spec-1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44"
|
||||
dependencies = [
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -376,6 +617,15 @@ version = "1.0.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
|
||||
|
||||
[[package]]
|
||||
name = "uninit"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3e130f2ed46ca5d8ec13c7ff95836827f92f5f5f37fd2b2bf16f33c408d98bb6"
|
||||
dependencies = [
|
||||
"extension-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "universal-hash"
|
||||
version = "0.5.1"
|
||||
@ -386,6 +636,12 @@ dependencies = [
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unwind_safe"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0976c77def3f1f75c4ef892a292c31c0bbe9e3d0702c63044d7c76db298171a3"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.5"
|
||||
@ -398,6 +654,35 @@ version = "0.11.1+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.7.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "with_builtin_macros"
|
||||
version = "0.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a59d55032495429b87f9d69954c6c8602e4d3f3e0a747a12dea6b0b23de685da"
|
||||
dependencies = [
|
||||
"with_builtin_macros-proc_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "with_builtin_macros-proc_macros"
|
||||
version = "0.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "15bd7679c15e22924f53aee34d4e448c45b674feb6129689af88593e129f8f42"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "x25519-dalek"
|
||||
version = "2.0.1"
|
||||
@ -427,7 +712,7 @@ checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.111",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -447,5 +732,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.111",
|
||||
]
|
||||
|
||||
@ -3,6 +3,13 @@ name = "double-ratchets"
|
||||
version = "0.0.1"
|
||||
edition = "2024"
|
||||
|
||||
[lib]
|
||||
crate-type = ["rlib", "cdylib"]
|
||||
|
||||
[[bin]]
|
||||
name = "generate-headers"
|
||||
required-features = ["headers"]
|
||||
|
||||
[dependencies]
|
||||
x25519-dalek = { version="2.0.1", features=["static_secrets"] }
|
||||
chacha20poly1305 = "0.10.1"
|
||||
@ -11,3 +18,8 @@ rand = "0.8.5"
|
||||
hkdf = "0.12.4"
|
||||
thiserror = "2"
|
||||
blake2 = "0.10.6"
|
||||
safer-ffi = "0.1.13"
|
||||
zeroize = "1.8.2"
|
||||
|
||||
[features]
|
||||
headers = ["safer-ffi/headers"]
|
||||
|
||||
@ -20,3 +20,12 @@ Run examples,
|
||||
```
|
||||
cargo run --example double_ratchet_basic
|
||||
```
|
||||
|
||||
Run Nim FFI example,
|
||||
|
||||
```bash
|
||||
# In the root folder (libchat)
|
||||
cargo build --release
|
||||
# In ffi-nim-example folder
|
||||
nimble run
|
||||
```
|
||||
|
||||
13
double-ratchets/ffi-nim-example/ffi_nim_example.nimble
Normal file
13
double-ratchets/ffi-nim-example/ffi_nim_example.nimble
Normal file
@ -0,0 +1,13 @@
|
||||
# Package
|
||||
|
||||
version = "0.1.0"
|
||||
author = "kaichaosun"
|
||||
description = "A new awesome nimble package"
|
||||
license = "MIT"
|
||||
srcDir = "src"
|
||||
bin = @["ffi_nim_example"]
|
||||
|
||||
|
||||
# Dependencies
|
||||
|
||||
requires "nim >= 2.2.4"
|
||||
144
double-ratchets/ffi-nim-example/src/ffi_nim_example.nim
Normal file
144
double-ratchets/ffi-nim-example/src/ffi_nim_example.nim
Normal file
@ -0,0 +1,144 @@
|
||||
when defined(macosx):
|
||||
{.passL: "-Wl,-rpath,@executable_path/../../target/release".}
|
||||
when defined(linux):
|
||||
{.passL: "-Wl,-rpath,'$ORIGIN/../../target/release'".}
|
||||
|
||||
# Portable dynlib name with override capability (-d:RLN_LIB:"...")
|
||||
when defined(macosx):
|
||||
const DR_LIB* {.strdefine.} = "libdouble_ratchets.dylib"
|
||||
elif defined(linux):
|
||||
const DR_LIB* {.strdefine.} = "libdouble_ratchets.so"
|
||||
elif defined(windows):
|
||||
const DR_LIB* {.strdefine.} = "double_ratchets.dll"
|
||||
else:
|
||||
const DR_LIB* {.strdefine.} = "double_ratchets"
|
||||
|
||||
type FFIRatchetState* = object
|
||||
|
||||
type FFIEncryptResult* = object
|
||||
|
||||
type FFIInstallationKeyPair* = object
|
||||
|
||||
type CSize* = csize_t
|
||||
|
||||
type Vec_uint8* = object
|
||||
dataPtr*: ptr uint8
|
||||
len*: CSize
|
||||
cap*: CSize
|
||||
|
||||
type Array_uint8_32* {.bycopy.} = object
|
||||
idx*: array[32, uint8]
|
||||
|
||||
type CResult_Vec_uint8_Vec_uint8* {.bycopy.} = object ## <No documentation available>
|
||||
ok*: Vec_uint8
|
||||
err*: Vec_uint8
|
||||
|
||||
proc double_ratchet_init_receiver*(
|
||||
shared_secret: Array_uint8_32, keypair: ptr FFIInstallationKeyPair
|
||||
): ptr FFIRatchetState {.importc, dynlib: DR_LIB.}
|
||||
|
||||
proc double_ratchet_init_sender*(
|
||||
shared_secret: Array_uint8_32, remote_pub: Array_uint8_32
|
||||
): ptr FFIRatchetState {.importc, dynlib: DR_LIB.}
|
||||
|
||||
proc double_ratchet_encrypt_message*(
|
||||
state: ptr FFIRatchetState, plaintext: ptr Vec_uint8
|
||||
): ptr FFIEncryptResult {.importc, dynlib: DR_LIB.}
|
||||
|
||||
proc double_ratchet_descrypt_message*(
|
||||
state: ptr FFIRatchetState, encrypted: ptr FFIEncryptResult
|
||||
): CResult_Vec_uint8_Vec_uint8 {.importc, dynlib: DR_LIB.}
|
||||
|
||||
proc ratchet_state_destroy*(state: ptr FFIRatchetState) {.importc, dynlib: DR_LIB.}
|
||||
|
||||
proc encrypt_result_destroy*(result: ptr FFIEncryptResult) {.importc, dynlib: DR_LIB.}
|
||||
|
||||
proc installation_key_pair_generate*(): ptr FFIInstallationKeyPair {.
|
||||
importc, dynlib: DR_LIB
|
||||
.}
|
||||
|
||||
proc installation_key_pair_public*(
|
||||
keypair: ptr FFIInstallationKeyPair
|
||||
): Array_uint8_32 {.importc, dynlib: DR_LIB.}
|
||||
|
||||
proc installation_key_pair_destroy*(
|
||||
keypair: ptr FFIInstallationKeyPair
|
||||
) {.importc, dynlib: DR_LIB.}
|
||||
|
||||
proc ffi_c_string_free*(s: Vec_uint8) {.importc, cdecl, dynlib: DR_LIB.}
|
||||
|
||||
proc asString*(v: Vec_uint8): string =
|
||||
if v.dataPtr.isNil or v.len == 0:
|
||||
return ""
|
||||
result = newString(v.len.int)
|
||||
copyMem(addr result[0], v.dataPtr, v.len.int)
|
||||
|
||||
when isMainModule:
|
||||
echo("start run")
|
||||
|
||||
# === Shared secret (like X3DH) ===
|
||||
var sharedSecret: Array_uint8_32
|
||||
for i in 0 .. 31:
|
||||
sharedSecret.idx[i] = 42'u8
|
||||
|
||||
# === Bob generates DH keypair ===
|
||||
let bobKey = installation_key_pair_generate()
|
||||
let bobPub = installation_key_pair_public(bobKey)
|
||||
echo("bob public key:", bobPub)
|
||||
|
||||
# === Alice initializes as sender ===
|
||||
let alice = double_ratchet_init_sender(sharedSecret, bobPub)
|
||||
# # === Bob initializes as receiver ===
|
||||
let bob = double_ratchet_init_receiver(sharedSecret, bobKey)
|
||||
|
||||
# # === Alice sends message to Bob ===
|
||||
var msg1: array[3, uint8] = [11'u8, 12, 13]
|
||||
var msg1Vec = Vec_uint8(
|
||||
dataPtr: cast[ptr uint8](addr msg1[0]), len: CSize(msg1.len), cap: CSize(msg1.len)
|
||||
)
|
||||
|
||||
let enc1 = double_ratchet_encrypt_message(alice, addr msg1Vec)
|
||||
let dec1 = double_ratchet_descrypt_message(bob, enc1)
|
||||
|
||||
encrypt_result_destroy(enc1)
|
||||
|
||||
if dec1.err.dataPtr != nil:
|
||||
echo "Bob failed to decrypt: ", asString(dec1.err)
|
||||
ffi_c_string_free(dec1.err)
|
||||
ratchet_state_destroy(alice)
|
||||
ratchet_state_destroy(bob)
|
||||
installation_key_pair_destroy(bobKey)
|
||||
quit 1
|
||||
let res1 = dec1.ok
|
||||
var plaintext1: array[3, uint8]
|
||||
copyMem(addr plaintext1[0], res1.dataPtr, res1.len.int)
|
||||
echo "Bob received: ", plaintext1
|
||||
|
||||
# # === Bob replies (triggers DH ratchet) ===
|
||||
var msg2: array[3, uint8] = [1'u8, 2, 3]
|
||||
var msg2Vec = Vec_uint8(
|
||||
dataPtr: cast[ptr uint8](addr msg2[0]), len: CSize(msg1.len), cap: CSize(msg1.len)
|
||||
)
|
||||
let enc2 = double_ratchet_encrypt_message(bob, addr msg2Vec)
|
||||
let dec2 = double_ratchet_descrypt_message(alice, enc2)
|
||||
|
||||
encrypt_result_destroy(enc2)
|
||||
|
||||
if dec2.err.dataPtr != nil:
|
||||
echo "Alice failed to decrypt: ", asString(dec2.err)
|
||||
ffi_c_string_free(dec2.err)
|
||||
ratchet_state_destroy(alice)
|
||||
ratchet_state_destroy(bob)
|
||||
installation_key_pair_destroy(bobKey)
|
||||
quit 1
|
||||
let res2 = dec2.ok
|
||||
var plaintext2: array[3, uint8]
|
||||
copyMem(addr plaintext2[0], res2.dataPtr, res2.len.int)
|
||||
echo "Alice received: ", plaintext2
|
||||
|
||||
# # === Cleanup ===
|
||||
ratchet_state_destroy(alice)
|
||||
ratchet_state_destroy(bob)
|
||||
installation_key_pair_destroy(bobKey)
|
||||
|
||||
echo("==end==\n")
|
||||
5
double-ratchets/src/bin/generate-headers.rs
Normal file
5
double-ratchets/src/bin/generate-headers.rs
Normal file
@ -0,0 +1,5 @@
|
||||
use double_ratchets::ffi;
|
||||
|
||||
fn main() -> std::io::Result<()> {
|
||||
ffi::generate_headers()
|
||||
}
|
||||
81
double-ratchets/src/ffi/doubleratchet.rs
Normal file
81
double-ratchets/src/ffi/doubleratchet.rs
Normal file
@ -0,0 +1,81 @@
|
||||
use safer_ffi::prelude::*;
|
||||
use x25519_dalek::PublicKey;
|
||||
|
||||
use crate::{
|
||||
Header, RatchetState,
|
||||
ffi::{key::FFIInstallationKeyPair, utils::CResult},
|
||||
};
|
||||
|
||||
#[derive_ReprC]
|
||||
#[repr(opaque)]
|
||||
pub struct FFIRatchetState(pub(crate) RatchetState);
|
||||
|
||||
#[derive_ReprC]
|
||||
#[repr(opaque)]
|
||||
pub struct FFIEncryptResult {
|
||||
pub ciphertext: Vec<u8>,
|
||||
pub header: Header,
|
||||
}
|
||||
|
||||
#[ffi_export]
|
||||
fn double_ratchet_init_sender(
|
||||
shared_secret: [u8; 32],
|
||||
remote_pub: [u8; 32],
|
||||
) -> repr_c::Box<FFIRatchetState> {
|
||||
let state = RatchetState::init_sender(shared_secret, PublicKey::from(remote_pub));
|
||||
Box::new(FFIRatchetState(state)).into()
|
||||
}
|
||||
|
||||
#[ffi_export]
|
||||
fn double_ratchet_init_receiver(
|
||||
shared_secret: [u8; 32],
|
||||
keypair: &FFIInstallationKeyPair,
|
||||
) -> repr_c::Box<FFIRatchetState> {
|
||||
let state = RatchetState::init_receiver(shared_secret, keypair.0.clone());
|
||||
Box::new(FFIRatchetState(state)).into()
|
||||
}
|
||||
|
||||
#[ffi_export]
|
||||
fn double_ratchet_encrypt_message(
|
||||
state: &mut FFIRatchetState,
|
||||
plaintext: &repr_c::Vec<u8>,
|
||||
) -> repr_c::Box<FFIEncryptResult> {
|
||||
let encrypted = state.0.encrypt_message(plaintext);
|
||||
let result = FFIEncryptResult {
|
||||
ciphertext: encrypted.0,
|
||||
header: encrypted.1,
|
||||
};
|
||||
Box::new(result).into()
|
||||
}
|
||||
|
||||
//TODO rename decrypt
|
||||
#[ffi_export]
|
||||
fn double_ratchet_descrypt_message(
|
||||
state: &mut FFIRatchetState,
|
||||
encrypted: &FFIEncryptResult,
|
||||
) -> CResult<repr_c::Vec<u8>, repr_c::String> {
|
||||
let decrypted = state
|
||||
.0
|
||||
.decrypt_message(&encrypted.ciphertext, encrypted.header.clone());
|
||||
|
||||
match decrypted {
|
||||
Ok(plaintext) => CResult {
|
||||
ok: Some(plaintext.into()),
|
||||
err: None,
|
||||
},
|
||||
Err(err) => CResult {
|
||||
ok: None,
|
||||
err: Some(err.to_string().into()),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[ffi_export]
|
||||
fn ratchet_state_destroy(state: repr_c::Box<FFIRatchetState>) {
|
||||
drop(state)
|
||||
}
|
||||
|
||||
#[ffi_export]
|
||||
fn encrypt_result_destroy(result: repr_c::Box<FFIEncryptResult>) {
|
||||
drop(result)
|
||||
}
|
||||
22
double-ratchets/src/ffi/key.rs
Normal file
22
double-ratchets/src/ffi/key.rs
Normal file
@ -0,0 +1,22 @@
|
||||
use safer_ffi::prelude::*;
|
||||
|
||||
use crate::InstallationKeyPair;
|
||||
|
||||
#[derive_ReprC]
|
||||
#[repr(opaque)]
|
||||
pub struct FFIInstallationKeyPair(pub(crate) InstallationKeyPair);
|
||||
|
||||
#[ffi_export]
|
||||
fn installation_key_pair_generate() -> repr_c::Box<FFIInstallationKeyPair> {
|
||||
Box::new(FFIInstallationKeyPair(InstallationKeyPair::generate())).into()
|
||||
}
|
||||
|
||||
#[ffi_export]
|
||||
fn installation_key_pair_public(keypair: &FFIInstallationKeyPair) -> [u8; 32] {
|
||||
keypair.0.public().clone().to_bytes()
|
||||
}
|
||||
|
||||
#[ffi_export]
|
||||
fn installation_key_pair_destroy(keypair: repr_c::Box<FFIInstallationKeyPair>) {
|
||||
drop(keypair)
|
||||
}
|
||||
10
double-ratchets/src/ffi/mod.rs
Normal file
10
double-ratchets/src/ffi/mod.rs
Normal file
@ -0,0 +1,10 @@
|
||||
pub mod doubleratchet;
|
||||
pub mod key;
|
||||
pub mod utils;
|
||||
|
||||
#[cfg(feature = "headers")]
|
||||
pub fn generate_headers() -> std::io::Result<()> {
|
||||
safer_ffi::headers::builder()
|
||||
.to_file("double_ratchet.h")?
|
||||
.generate()
|
||||
}
|
||||
13
double-ratchets/src/ffi/utils.rs
Normal file
13
double-ratchets/src/ffi/utils.rs
Normal file
@ -0,0 +1,13 @@
|
||||
use safer_ffi::prelude::*;
|
||||
|
||||
#[derive_ReprC]
|
||||
#[repr(C)]
|
||||
pub struct CResult<T: ReprC, Err: ReprC> {
|
||||
pub ok: Option<T>,
|
||||
pub err: Option<Err>,
|
||||
}
|
||||
|
||||
#[ffi_export]
|
||||
pub fn ffi_c_string_free(s: repr_c::String) {
|
||||
drop(s);
|
||||
}
|
||||
@ -1,9 +1,10 @@
|
||||
use rand_core::OsRng;
|
||||
use x25519_dalek::{PublicKey, StaticSecret};
|
||||
use zeroize::{Zeroize, ZeroizeOnDrop};
|
||||
|
||||
use crate::types::SharedSecret;
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Zeroize, ZeroizeOnDrop)]
|
||||
pub struct InstallationKeyPair {
|
||||
secret: StaticSecret,
|
||||
public: PublicKey,
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
pub mod aead;
|
||||
pub mod errors;
|
||||
pub mod ffi;
|
||||
pub mod hkdf;
|
||||
pub mod keypair;
|
||||
pub mod state;
|
||||
|
||||
@ -35,7 +35,7 @@ pub struct RatchetState<D: HkdfInfo = DefaultDomain> {
|
||||
}
|
||||
|
||||
/// Public header attached to every encrypted message (unencrypted but authenticated).
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Header {
|
||||
pub dh_pub: PublicKey,
|
||||
pub msg_num: u32,
|
||||
|
||||
114
double_ratchet.h
Normal file
114
double_ratchet.h
Normal file
@ -0,0 +1,114 @@
|
||||
/*! \file */
|
||||
/*******************************************
|
||||
* *
|
||||
* File auto-generated by `::safer_ffi`. *
|
||||
* *
|
||||
* Do not manually edit this file. *
|
||||
* *
|
||||
*******************************************/
|
||||
|
||||
#ifndef __RUST_DOUBLE_RATCHETS__
|
||||
#define __RUST_DOUBLE_RATCHETS__
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** <No documentation available> */
|
||||
typedef struct FFIRatchetState FFIRatchetState_t;
|
||||
|
||||
/** <No documentation available> */
|
||||
typedef struct FFIEncryptResult FFIEncryptResult_t;
|
||||
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/** \brief
|
||||
* Same as [`Vec<T>`][`rust::Vec`], but with guaranteed `#[repr(C)]` layout
|
||||
*/
|
||||
typedef struct Vec_uint8 {
|
||||
/** <No documentation available> */
|
||||
uint8_t * ptr;
|
||||
|
||||
/** <No documentation available> */
|
||||
size_t len;
|
||||
|
||||
/** <No documentation available> */
|
||||
size_t cap;
|
||||
} Vec_uint8_t;
|
||||
|
||||
/** <No documentation available> */
|
||||
typedef struct CResult_Vec_uint8_Vec_uint8 {
|
||||
/** <No documentation available> */
|
||||
Vec_uint8_t ok;
|
||||
|
||||
/** <No documentation available> */
|
||||
Vec_uint8_t err;
|
||||
} CResult_Vec_uint8_Vec_uint8_t;
|
||||
|
||||
/** <No documentation available> */
|
||||
CResult_Vec_uint8_Vec_uint8_t
|
||||
double_ratchet_descrypt_message (
|
||||
FFIRatchetState_t * state,
|
||||
FFIEncryptResult_t const * encrypted);
|
||||
|
||||
/** <No documentation available> */
|
||||
FFIEncryptResult_t *
|
||||
double_ratchet_encrypt_message (
|
||||
FFIRatchetState_t * state,
|
||||
Vec_uint8_t const * plaintext);
|
||||
|
||||
typedef struct {
|
||||
uint8_t idx[32];
|
||||
} uint8_32_array_t;
|
||||
|
||||
/** <No documentation available> */
|
||||
typedef struct FFIInstallationKeyPair FFIInstallationKeyPair_t;
|
||||
|
||||
/** <No documentation available> */
|
||||
FFIRatchetState_t *
|
||||
double_ratchet_init_receiver (
|
||||
uint8_32_array_t shared_secret,
|
||||
FFIInstallationKeyPair_t const * keypair);
|
||||
|
||||
/** <No documentation available> */
|
||||
FFIRatchetState_t *
|
||||
double_ratchet_init_sender (
|
||||
uint8_32_array_t shared_secret,
|
||||
uint8_32_array_t remote_pub);
|
||||
|
||||
/** <No documentation available> */
|
||||
void
|
||||
encrypt_result_destroy (
|
||||
FFIEncryptResult_t * result);
|
||||
|
||||
/** <No documentation available> */
|
||||
void
|
||||
ffi_c_string_free (
|
||||
Vec_uint8_t s);
|
||||
|
||||
/** <No documentation available> */
|
||||
void
|
||||
installation_key_pair_destroy (
|
||||
FFIInstallationKeyPair_t * keypair);
|
||||
|
||||
/** <No documentation available> */
|
||||
FFIInstallationKeyPair_t *
|
||||
installation_key_pair_generate (void);
|
||||
|
||||
/** <No documentation available> */
|
||||
uint8_32_array_t
|
||||
installation_key_pair_public (
|
||||
FFIInstallationKeyPair_t const * keypair);
|
||||
|
||||
/** <No documentation available> */
|
||||
void
|
||||
ratchet_state_destroy (
|
||||
FFIRatchetState_t * state);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern \"C\" */
|
||||
#endif
|
||||
|
||||
#endif /* __RUST_DOUBLE_RATCHETS__ */
|
||||
Loading…
x
Reference in New Issue
Block a user