mirror of
https://github.com/QuilibriumNetwork/ceremonyclient.git
synced 2026-02-21 10:27:26 +08:00
more tweaks
This commit is contained in:
parent
a9666a9058
commit
5ccd96e47b
64
Cargo.lock
generated
64
Cargo.lock
generated
@ -231,12 +231,22 @@ version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b"
|
||||
dependencies = [
|
||||
"block-padding",
|
||||
"block-padding 0.1.5",
|
||||
"byte-tools",
|
||||
"byteorder",
|
||||
"generic-array 0.12.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
|
||||
dependencies = [
|
||||
"block-padding 0.2.1",
|
||||
"generic-array 0.14.7",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.10.4"
|
||||
@ -255,6 +265,12 @@ dependencies = [
|
||||
"byte-tools",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-padding"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae"
|
||||
|
||||
[[package]]
|
||||
name = "bls48581"
|
||||
version = "0.1.0"
|
||||
@ -358,10 +374,17 @@ dependencies = [
|
||||
name = "channelwasm"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"aes-gcm",
|
||||
"base64",
|
||||
"channel",
|
||||
"ed448-goldilocks-plus",
|
||||
"ed448-rust",
|
||||
"getrandom",
|
||||
"hkdf",
|
||||
"rand",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2 0.10.8",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
@ -664,6 +687,15 @@ dependencies = [
|
||||
"generic-array 0.12.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
|
||||
dependencies = [
|
||||
"generic-array 0.14.7",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.7"
|
||||
@ -685,11 +717,27 @@ dependencies = [
|
||||
"hex 0.4.3",
|
||||
"rand_core",
|
||||
"serde",
|
||||
"sha3",
|
||||
"sha3 0.10.8",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ed448-rust"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5428b9b8138c483798ceb6a21004de0f24e3a2311195f13829ce1d059037d703"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"num-bigint",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
"opaque-debug 0.3.1",
|
||||
"rand_core",
|
||||
"sha3 0.9.1",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.12.0"
|
||||
@ -1464,6 +1512,18 @@ dependencies = [
|
||||
"digest 0.10.7",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha3"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809"
|
||||
dependencies = [
|
||||
"block-buffer 0.9.0",
|
||||
"digest 0.9.0",
|
||||
"keccak",
|
||||
"opaque-debug 0.3.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha3"
|
||||
version = "0.10.8"
|
||||
|
||||
@ -13,3 +13,10 @@ channel = { path = "../channel", version = "^0.1.0" }
|
||||
getrandom = { version = "0.2", features = ["js"] }
|
||||
serde = "1.0.208"
|
||||
serde_json = "1.0.117"
|
||||
base64 = "0.22.1"
|
||||
ed448-goldilocks-plus = "0.11.2"
|
||||
ed448-rust = "0.1.1"
|
||||
rand = "0.8.5"
|
||||
sha2 = "0.10.8"
|
||||
hkdf = "0.12.4"
|
||||
aes-gcm = "0.10.3"
|
||||
@ -1,6 +1,14 @@
|
||||
use aes_gcm::{Aes256Gcm, Nonce};
|
||||
use aes_gcm::aead::{Aead, Payload};
|
||||
use ed448_rust::Ed448Error;
|
||||
use hkdf::Hkdf;
|
||||
use rand::{rngs::OsRng, RngCore};
|
||||
use sha2::Sha512;
|
||||
use wasm_bindgen::prelude::*;
|
||||
use base64::prelude::*;
|
||||
use channel::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ed448_goldilocks_plus::{elliptic_curve::Group, CompressedEdwardsY, EdwardsPoint, Scalar};
|
||||
|
||||
#[derive(Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct NewDoubleRatchetParameters {
|
||||
@ -22,6 +30,418 @@ pub struct NewTripleRatchetParameters {
|
||||
pub async_dkg_ratchet: bool
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct EncryptionKeyPair {
|
||||
pub public_key: Vec<u8>,
|
||||
pub private_key: Vec<u8>,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct SigningKeyPair {
|
||||
pub public_key: Vec<u8>,
|
||||
pub private_key: Vec<u8>,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct SenderX3DH {
|
||||
pub sending_identity_private_key: Vec<u8>,
|
||||
pub sending_ephemeral_private_key: Vec<u8>,
|
||||
pub receiving_identity_key: Vec<u8>,
|
||||
pub receiving_signed_pre_key: Vec<u8>,
|
||||
pub session_key_length: usize,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct ReceiverX3DH {
|
||||
pub sending_identity_private_key: Vec<u8>,
|
||||
pub sending_signed_private_key: Vec<u8>,
|
||||
pub receiving_identity_key: Vec<u8>,
|
||||
pub receiving_ephemeral_key: Vec<u8>,
|
||||
pub session_key_length: usize,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Serialize, Deserialize, Debug)]
|
||||
pub struct MessageCiphertext {
|
||||
pub ciphertext: String,
|
||||
pub initialization_vector: String,
|
||||
pub associated_data: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct SealedInboxMessageDecryptRequest {
|
||||
pub inbox_private_key: Vec<u8>,
|
||||
pub ephemeral_public_key: Vec<u8>,
|
||||
pub ciphertext: MessageCiphertext,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct SealedInboxMessageEncryptRequest {
|
||||
pub inbox_public_key: Vec<u8>,
|
||||
pub ephemeral_private_key: Vec<u8>,
|
||||
pub plaintext: Vec<u8>,
|
||||
}
|
||||
|
||||
fn encrypt(plaintext: &[u8], key: &[u8])
|
||||
-> Result<MessageCiphertext, Box<dyn std::error::Error>> {
|
||||
use aes_gcm::KeyInit;
|
||||
let mut iv = [0u8; 12];
|
||||
OsRng.fill_bytes(&mut iv);
|
||||
|
||||
let cipher = Aes256Gcm::new_from_slice(key).unwrap();
|
||||
let nonce = Nonce::from_slice(&iv);
|
||||
|
||||
let mut aad = [0u8; 32];
|
||||
OsRng.fill_bytes(&mut aad);
|
||||
|
||||
let ciphertext = cipher.encrypt(nonce, Payload{
|
||||
msg: plaintext,
|
||||
aad: &aad,
|
||||
}).map_err(|e| format!("Encryption failed: {}", e))?;
|
||||
|
||||
Ok(MessageCiphertext {
|
||||
ciphertext: BASE64_STANDARD.encode(ciphertext),
|
||||
initialization_vector: BASE64_STANDARD.encode(iv.to_vec()),
|
||||
associated_data: Some(BASE64_STANDARD.encode(aad.to_vec())),
|
||||
})
|
||||
}
|
||||
|
||||
fn decrypt(ciphertext: &MessageCiphertext, key: &[u8])
|
||||
-> Result<Vec<u8>, Box<dyn std::error::Error>> {
|
||||
use aes_gcm::KeyInit;
|
||||
if key.len() != 32 {
|
||||
return Err(format!("Invalid key length").into());
|
||||
}
|
||||
let cipher = Aes256Gcm::new_from_slice(key).unwrap();
|
||||
let maybe_iv = BASE64_STANDARD.decode(&ciphertext.initialization_vector);
|
||||
if maybe_iv.is_err() {
|
||||
return Err(format!("Decryption failed: {}", maybe_iv.unwrap_err()).into());
|
||||
}
|
||||
|
||||
let iv = maybe_iv.unwrap();
|
||||
let nonce = Nonce::from_slice(&iv);
|
||||
|
||||
let ad = &ciphertext.associated_data;
|
||||
let mut associated_data = Vec::<u8>::new();
|
||||
if ad.is_some() {
|
||||
let aad = BASE64_STANDARD.decode(&ad.clone().unwrap());
|
||||
if aad.is_err() {
|
||||
return Err(format!("Decryption failed: {}", aad.unwrap_err()).into());
|
||||
}
|
||||
|
||||
associated_data = aad.unwrap();
|
||||
}
|
||||
|
||||
let ciphertext = BASE64_STANDARD.decode(&ciphertext.ciphertext);
|
||||
if ciphertext.is_err() {
|
||||
return Err(format!("Decryption failed: {}", ciphertext.unwrap_err()).into());
|
||||
}
|
||||
|
||||
cipher.decrypt(nonce, Payload{
|
||||
msg: &ciphertext.unwrap(),
|
||||
aad: &associated_data,
|
||||
}).map_err(|e| format!("Decryption failed: {}", e).into())
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn js_decrypt_inbox_message(input: &str) -> String {
|
||||
let json: Result<SealedInboxMessageDecryptRequest, serde_json::Error> = serde_json::from_str(input);
|
||||
match json {
|
||||
Ok(params) => {
|
||||
let ephemeral_key = params.ephemeral_public_key;
|
||||
if ephemeral_key.len() != 57 {
|
||||
return "invalid ephemeral key length".to_string();
|
||||
}
|
||||
|
||||
let inbox_key = params.inbox_private_key;
|
||||
if inbox_key.len() != 56 {
|
||||
return "invalid inbox key length".to_string();
|
||||
}
|
||||
|
||||
let ephemeral_key_bytes: [u8; 57] = ephemeral_key.try_into().unwrap();
|
||||
let inbox_key_bytes: [u8; 56] = inbox_key.try_into().unwrap();
|
||||
let priv_key = Scalar::from_bytes(&inbox_key_bytes);
|
||||
let maybe_eph_key = CompressedEdwardsY(ephemeral_key_bytes).decompress();
|
||||
|
||||
if maybe_eph_key.is_none().into() {
|
||||
return "invalid ephemeral key".to_string();
|
||||
}
|
||||
|
||||
let dh_output = priv_key * maybe_eph_key.unwrap();
|
||||
// TODO: To support authorized inbox sending, change None to Some when an authorization_key is present.
|
||||
let hkdf = Hkdf::<Sha512>::new(None, &dh_output.compress().to_bytes());
|
||||
let mut derived = [0u8; 32];
|
||||
let err = hkdf.expand(b"quilibrium-sealed-sender", &mut derived);
|
||||
if err.is_err() {
|
||||
return "invalid length".into();
|
||||
}
|
||||
|
||||
let result = decrypt(¶ms.ciphertext, &derived);
|
||||
if result.is_err() {
|
||||
return result.unwrap_err().to_string();
|
||||
}
|
||||
|
||||
match serde_json::to_string(&result.unwrap()) {
|
||||
Ok(result) => result,
|
||||
Err(e) => e.to_string(),
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
return e.to_string();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn js_encrypt_inbox_message(input: &str) -> String {
|
||||
let json: Result<SealedInboxMessageEncryptRequest, serde_json::Error> = serde_json::from_str(input);
|
||||
match json {
|
||||
Ok(params) => {
|
||||
let key = params.ephemeral_private_key;
|
||||
if key.len() != 56 {
|
||||
return "invalid ephemeral key length".to_string();
|
||||
}
|
||||
|
||||
let inbox_key = params.inbox_public_key;
|
||||
if inbox_key.len() != 57 {
|
||||
return "invalid inbox key length".to_string();
|
||||
}
|
||||
|
||||
let key_bytes: [u8; 56] = key.try_into().unwrap();
|
||||
let inbox_key_bytes: [u8; 57] = inbox_key.try_into().unwrap();
|
||||
let priv_key = Scalar::from_bytes(&key_bytes);
|
||||
let maybe_pub_key = CompressedEdwardsY(inbox_key_bytes).decompress();
|
||||
|
||||
if maybe_pub_key.is_none().into() {
|
||||
return "invalid inbox key".to_string();
|
||||
}
|
||||
|
||||
let dh_output = priv_key * maybe_pub_key.unwrap();
|
||||
// TODO: To support authorized inbox sending, change None to Some when an authorization_key is present.
|
||||
let hkdf = Hkdf::<Sha512>::new(None, &dh_output.compress().to_bytes());
|
||||
let mut derived = [0u8; 32];
|
||||
let err = hkdf.expand(b"quilibrium-sealed-sender", &mut derived);
|
||||
if err.is_err() {
|
||||
return "invalid length".into();
|
||||
}
|
||||
|
||||
let result = encrypt(¶ms.plaintext, &derived);
|
||||
if result.is_err() {
|
||||
return result.unwrap_err().to_string();
|
||||
}
|
||||
|
||||
match serde_json::to_string(&result.unwrap()) {
|
||||
Ok(result) => result,
|
||||
Err(e) => e.to_string(),
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
return e.to_string();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn js_sender_x3dh(input: &str) -> String {
|
||||
let json: Result<SenderX3DH, serde_json::Error> = serde_json::from_str(input);
|
||||
match json {
|
||||
Ok(params) => {
|
||||
return sender_x3dh(¶ms.sending_identity_private_key, ¶ms.sending_ephemeral_private_key, ¶ms.receiving_identity_key, ¶ms.receiving_signed_pre_key, params.session_key_length);
|
||||
}
|
||||
Err(e) => {
|
||||
return e.to_string();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn js_receiver_x3dh(input: &str) -> String {
|
||||
let json: Result<ReceiverX3DH, serde_json::Error> = serde_json::from_str(input);
|
||||
match json {
|
||||
Ok(params) => {
|
||||
return receiver_x3dh(¶ms.sending_identity_private_key, ¶ms.sending_signed_private_key, ¶ms.receiving_identity_key, ¶ms.receiving_ephemeral_key, params.session_key_length);
|
||||
}
|
||||
Err(e) => {
|
||||
return e.to_string();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn js_generate_x448() -> String {
|
||||
let priv_key = Scalar::random(&mut rand::thread_rng());
|
||||
let pub_key = EdwardsPoint::generator() * priv_key;
|
||||
let output = serde_json::to_string(&EncryptionKeyPair{
|
||||
public_key: pub_key.compress().to_bytes().to_vec(),
|
||||
private_key: priv_key.to_bytes().to_vec(),
|
||||
});
|
||||
|
||||
match output {
|
||||
Ok(result) => {
|
||||
result
|
||||
}
|
||||
Err(e) => {
|
||||
e.to_string()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn js_generate_ed448() -> String {
|
||||
let priv_key = ed448_rust::PrivateKey::new(&mut rand::thread_rng());
|
||||
let pub_key = ed448_rust::PublicKey::from(&priv_key);
|
||||
let output = serde_json::to_string(&EncryptionKeyPair{
|
||||
public_key: pub_key.as_byte().to_vec(),
|
||||
private_key: priv_key.as_bytes().to_vec(),
|
||||
});
|
||||
|
||||
match output {
|
||||
Ok(result) => {
|
||||
result
|
||||
}
|
||||
Err(e) => {
|
||||
e.to_string()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn js_get_pubkey_ed448(key: &str) -> String {
|
||||
let maybe_key = BASE64_STANDARD.decode(key);
|
||||
if maybe_key.is_err() {
|
||||
return maybe_key.unwrap_err().to_string();
|
||||
}
|
||||
|
||||
let key = maybe_key.unwrap();
|
||||
if key.len() != 57 {
|
||||
return "invalid key length".to_string();
|
||||
}
|
||||
|
||||
let key_bytes: [u8; 57] = key.try_into().unwrap();
|
||||
let priv_key = ed448_rust::PrivateKey::from(key_bytes);
|
||||
let pub_key = ed448_rust::PublicKey::from(&priv_key);
|
||||
|
||||
return format!("\"{}\"", BASE64_STANDARD.encode(pub_key.as_byte()));
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn js_get_pubkey_x448(key: &str) -> String {
|
||||
let maybe_key = BASE64_STANDARD.decode(key);
|
||||
if maybe_key.is_err() {
|
||||
return maybe_key.unwrap_err().to_string();
|
||||
}
|
||||
|
||||
let key = maybe_key.unwrap();
|
||||
if key.len() != 56 {
|
||||
return "invalid key length".to_string();
|
||||
}
|
||||
|
||||
let mut priv_key_bytes = [0u8; 56];
|
||||
priv_key_bytes.copy_from_slice(&key);
|
||||
|
||||
let priv_key = Scalar::from_bytes(&priv_key_bytes);
|
||||
let pub_key = EdwardsPoint::generator() * priv_key;
|
||||
|
||||
return format!("\"{}\"", BASE64_STANDARD.encode(pub_key.compress().to_bytes().to_vec()));
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn js_sign_ed448(key: &str, message: &str) -> String {
|
||||
let maybe_key = BASE64_STANDARD.decode(key);
|
||||
if maybe_key.is_err() {
|
||||
return maybe_key.unwrap_err().to_string();
|
||||
}
|
||||
|
||||
let maybe_message = BASE64_STANDARD.decode(message);
|
||||
if maybe_message.is_err() {
|
||||
return maybe_message.unwrap_err().to_string();
|
||||
}
|
||||
|
||||
let key = maybe_key.unwrap();
|
||||
if key.len() != 57 {
|
||||
return "invalid key length".to_string();
|
||||
}
|
||||
|
||||
let key_bytes: [u8; 57] = key.try_into().unwrap();
|
||||
let priv_key = ed448_rust::PrivateKey::from(key_bytes);
|
||||
let signature = priv_key.sign(&maybe_message.unwrap(), None);
|
||||
|
||||
match signature {
|
||||
Ok(output) => {
|
||||
return format!("\"{}\"", BASE64_STANDARD.encode(output));
|
||||
}
|
||||
Err(Ed448Error::WrongKeyLength) => {
|
||||
return "invalid key length".to_string();
|
||||
}
|
||||
Err(Ed448Error::WrongPublicKeyLength) => {
|
||||
return "invalid public key length".to_string();
|
||||
}
|
||||
Err(Ed448Error::WrongSignatureLength) => {
|
||||
return "invalid signature length".to_string();
|
||||
}
|
||||
Err(Ed448Error::InvalidPoint) => {
|
||||
return "invalid point".to_string();
|
||||
}
|
||||
Err(Ed448Error::InvalidSignature) => {
|
||||
return "invalid signature".to_string();
|
||||
}
|
||||
Err(Ed448Error::ContextTooLong) => {
|
||||
return "context too long".to_string();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn js_verify_ed448(public_key: &str, message: &str, signature: &str) -> String {
|
||||
let maybe_key = BASE64_STANDARD.decode(public_key);
|
||||
if maybe_key.is_err() {
|
||||
return maybe_key.unwrap_err().to_string();
|
||||
}
|
||||
|
||||
let maybe_message = BASE64_STANDARD.decode(message);
|
||||
if maybe_message.is_err() {
|
||||
return maybe_message.unwrap_err().to_string();
|
||||
}
|
||||
|
||||
let maybe_signature = BASE64_STANDARD.decode(signature);
|
||||
if maybe_signature.is_err() {
|
||||
return maybe_signature.unwrap_err().to_string();
|
||||
}
|
||||
|
||||
let key = maybe_key.unwrap();
|
||||
if key.len() != 57 {
|
||||
return "invalid key length".to_string();
|
||||
}
|
||||
|
||||
let pub_bytes: [u8; 57] = key.try_into().unwrap();
|
||||
|
||||
let pub_key = ed448_rust::PublicKey::from(pub_bytes);
|
||||
let signature = pub_key.verify(&maybe_message.unwrap(), &maybe_signature.unwrap(), None);
|
||||
|
||||
match signature {
|
||||
Ok(()) => {
|
||||
return "true".to_string();
|
||||
}
|
||||
Err(Ed448Error::WrongKeyLength) => {
|
||||
return "invalid key length".to_string();
|
||||
}
|
||||
Err(Ed448Error::WrongPublicKeyLength) => {
|
||||
return "invalid public key length".to_string();
|
||||
}
|
||||
Err(Ed448Error::WrongSignatureLength) => {
|
||||
return "invalid signature length".to_string();
|
||||
}
|
||||
Err(Ed448Error::InvalidPoint) => {
|
||||
return "invalid point".to_string();
|
||||
}
|
||||
Err(Ed448Error::InvalidSignature) => {
|
||||
return "invalid signature".to_string();
|
||||
}
|
||||
Err(Ed448Error::ContextTooLong) => {
|
||||
return "context too long".to_string();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn js_new_double_ratchet(params: &str) -> String {
|
||||
let json: Result<NewDoubleRatchetParameters, serde_json::Error> = serde_json::from_str(params);
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
use base64::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use std::{collections::HashMap, io::Read};
|
||||
|
||||
use ed448_goldilocks_plus::{elliptic_curve::group::GroupEncoding, EdwardsPoint, Scalar};
|
||||
use protocols::{doubleratchet::{DoubleRatchetParticipant, P2PChannelEnvelope}, tripleratchet::{PeerInfo, TripleRatchetParticipant}};
|
||||
use ed448_goldilocks_plus::{elliptic_curve::group::GroupEncoding, CompressedEdwardsY, EdwardsPoint, Scalar};
|
||||
use protocols::{doubleratchet::{DoubleRatchetParticipant, P2PChannelEnvelope}, tripleratchet::{PeerInfo, TripleRatchetParticipant}, x3dh};
|
||||
|
||||
pub(crate) mod protocols;
|
||||
|
||||
@ -39,6 +39,86 @@ pub struct TripleRatchetStateAndMessage {
|
||||
pub message: Vec<u8>,
|
||||
}
|
||||
|
||||
pub fn sender_x3dh(sending_identity_private_key: &Vec<u8>, sending_ephemeral_private_key: &Vec<u8>, receiving_identity_key: &Vec<u8>, receiving_signed_pre_key: &Vec<u8>, session_key_length: usize) -> String {
|
||||
if sending_identity_private_key.len() != 56 {
|
||||
return "invalid sending identity private key length".to_string();
|
||||
}
|
||||
|
||||
if sending_ephemeral_private_key.len() != 56 {
|
||||
return "invalid sending ephemeral private key length".to_string();
|
||||
}
|
||||
|
||||
if receiving_identity_key.len() != 57 {
|
||||
return "invalid receiving identity public key length".to_string();
|
||||
}
|
||||
|
||||
if receiving_signed_pre_key.len() != 57 {
|
||||
return "invalid receiving signed public key length".to_string();
|
||||
}
|
||||
|
||||
let sidk = Scalar::from_bytes(sending_identity_private_key.as_slice().try_into().unwrap());
|
||||
let sepk = Scalar::from_bytes(sending_ephemeral_private_key.as_slice().try_into().unwrap());
|
||||
let ridk = CompressedEdwardsY(receiving_identity_key.as_slice().try_into().unwrap()).decompress();
|
||||
let rspk = CompressedEdwardsY(receiving_signed_pre_key.as_slice().try_into().unwrap()).decompress();
|
||||
|
||||
if ridk.is_none().into() {
|
||||
return "invalid receiving identity public key".to_string();
|
||||
}
|
||||
|
||||
if rspk.is_none().into() {
|
||||
return "invalid receiving signed public key".to_string();
|
||||
}
|
||||
|
||||
match x3dh::sender_x3dh(&sidk, &sepk, &ridk.unwrap(), &rspk.unwrap(), session_key_length) {
|
||||
Some(result) => {
|
||||
return format!("\"{}\"", BASE64_STANDARD.encode(result));
|
||||
}
|
||||
None => {
|
||||
return "could not perform key agreement".to_string();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn receiver_x3dh(sending_identity_private_key: &Vec<u8>, sending_signed_private_key: &Vec<u8>, receiving_identity_key: &Vec<u8>, receiving_ephemeral_key: &Vec<u8>, session_key_length: usize) -> String {
|
||||
if sending_identity_private_key.len() != 56 {
|
||||
return "invalid sending identity private key length".to_string();
|
||||
}
|
||||
|
||||
if sending_signed_private_key.len() != 56 {
|
||||
return "invalid sending signed private key length".to_string();
|
||||
}
|
||||
|
||||
if receiving_identity_key.len() != 57 {
|
||||
return "invalid receiving identity public key length".to_string();
|
||||
}
|
||||
|
||||
if receiving_ephemeral_key.len() != 57 {
|
||||
return "invalid receiving ephemeral public key length".to_string();
|
||||
}
|
||||
|
||||
let sidk = Scalar::from_bytes(sending_identity_private_key.as_slice().try_into().unwrap());
|
||||
let sspk = Scalar::from_bytes(sending_signed_private_key.as_slice().try_into().unwrap());
|
||||
let ridk = CompressedEdwardsY(receiving_identity_key.as_slice().try_into().unwrap()).decompress();
|
||||
let repk = CompressedEdwardsY(receiving_ephemeral_key.as_slice().try_into().unwrap()).decompress();
|
||||
|
||||
if ridk.is_none().into() {
|
||||
return "invalid receiving identity public key".to_string();
|
||||
}
|
||||
|
||||
if repk.is_none().into() {
|
||||
return "invalid receiving signed public key".to_string();
|
||||
}
|
||||
|
||||
match x3dh::receiver_x3dh(&sidk, &sspk, &ridk.unwrap(), &repk.unwrap(), session_key_length) {
|
||||
Some(result) => {
|
||||
return format!("\"{}\"", BASE64_STANDARD.encode(result));
|
||||
}
|
||||
None => {
|
||||
return "could not perform key agreement".to_string();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_double_ratchet(session_key: &Vec<u8>, sending_header_key: &Vec<u8>, next_receiving_header_key: &Vec<u8>, is_sender: bool, sending_ephemeral_private_key: &Vec<u8>, receiving_ephemeral_key: &Vec<u8>) -> String {
|
||||
if sending_ephemeral_private_key.len() != 56 {
|
||||
return "invalid private key length".to_string();
|
||||
@ -64,7 +144,7 @@ pub fn new_double_ratchet(session_key: &Vec<u8>, sending_header_key: &Vec<u8>, n
|
||||
&session_key,
|
||||
&sending_header_key,
|
||||
&next_receiving_header_key,
|
||||
true,
|
||||
is_sender,
|
||||
sending_key,
|
||||
receiving_key.unwrap(),
|
||||
);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user