Skip to content

Commit

Permalink
feat: xchacha20 encryption/decryption (#11)
Browse files Browse the repository at this point in the history
  • Loading branch information
ivan770 authored Feb 22, 2024
1 parent fb10bce commit 0b12a7f
Show file tree
Hide file tree
Showing 5 changed files with 192 additions and 99 deletions.
33 changes: 33 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

46 changes: 35 additions & 11 deletions crates/teddybear-js/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,23 +61,23 @@
//! Additionally, you can convert Ed25519 keys to X25519 keys, allowing you to publish just a single DID value for both signing and encryption purposes.
//!
//! ```ignore
//! import { PrivateEd25519, PublicEd25519, encrypt } from "@vaultie/teddybear";
//! import { PrivateEd25519, PublicEd25519, encryptAES } from "@vaultie/teddybear";
//!
//! const firstKey = await PrivateEd25519.generate();
//! const secondKey = await PublicEd25519.fromDID(
//! "did:key:z6MkmpNwNTy4ATx87tZWHqSwNf1ZdeQrBHFWyhtvUwqrt32R"
//! );
//!
//! // Encrypt using recipient public keys.
//! const jwe = encrypt(new Uint8Array([0, 1, 2, 3], [
//! const jwe = encryptAES(new Uint8Array([0, 1, 2, 3], [
//! firstKey.toX25519PublicJWK(),
//! secondKey.toX25519PublicJWK(),
//! ]));
//!
//! console.log(jwe);
//!
//! // Decrypt using any suitable recipient private key.
//! console.log(firstKey.decrypt(jwe));
//! console.log(firstKey.decryptAES(jwe));
//! ```
//!
//! ## Revocation/status list
Expand Down Expand Up @@ -127,7 +127,7 @@ use serde::Serialize;
use serde_json::json;
use serde_wasm_bindgen::Serializer;
use teddybear_crypto::{Ed25519, Private, Public, JWK as InnerJWK};
use teddybear_jwe::decrypt;
use teddybear_jwe::{decrypt, A256Gcm, XC20P};
use teddybear_status_list::{
credential::{BitstringStatusListCredentialSubject, StatusPurpose},
StatusList,
Expand Down Expand Up @@ -214,10 +214,19 @@ impl PrivateEd25519 {
self.0.x25519_did().to_string()
}

/// Decrypt the provided JWE object using the X25519 key.
pub fn decrypt(&self, jwe: Object) -> Result<Uint8Array, JsError> {
/// Decrypt the provided JWE object using the X25519 key and the A256GCM algorithm.
#[wasm_bindgen(js_name = "decryptAES")]
pub fn decrypt_aes(&self, jwe: Object) -> Result<Uint8Array, JsError> {
let jwe = serde_wasm_bindgen::from_value(jwe.into())?;
let payload = &*decrypt(&jwe, self.0.as_x25519_private_jwk())?;
let payload = &*decrypt::<A256Gcm>(&jwe, self.0.as_x25519_private_jwk())?;
Ok(payload.into())
}

/// Decrypt the provided JWE object using the X25519 key and the XC20P algorithm.
#[wasm_bindgen(js_name = "decryptChaCha20")]
pub fn decrypt_chacha20(&self, jwe: Object) -> Result<Uint8Array, JsError> {
let jwe = serde_wasm_bindgen::from_value(jwe.into())?;
let payload = &*decrypt::<XC20P>(&jwe, self.0.as_x25519_private_jwk())?;
Ok(payload.into())
}

Expand Down Expand Up @@ -468,14 +477,29 @@ impl Constraint {
}
}

/// Encrypt the provided payload for the provided recipient array.
/// Encrypt the provided payload for the provided recipient array using A256GCM algorithm.
///
/// The provided recipients array must contain only wrapped X25519 JWK values.
///
/// You may acquire X25519 JWK values using the `toX25519PublicJWK` method on the keypair structs.
#[wasm_bindgen]
pub fn encrypt(payload: Uint8Array, recipients: Vec<JWK>) -> Result<Object, JsError> {
let jwe = teddybear_jwe::encrypt(
#[wasm_bindgen(js_name = "encryptAES")]
pub fn encrypt_aes(payload: Uint8Array, recipients: Vec<JWK>) -> Result<Object, JsError> {
let jwe = teddybear_jwe::encrypt::<A256Gcm>(
&payload.to_vec(),
&recipients.iter().map(|val| &val.0).collect::<Vec<_>>(),
)?;

Ok(jwe.serialize(&OBJECT_SERIALIZER)?.into())
}

/// Encrypt the provided payload for the provided recipient array using XC20P algorithm.
///
/// The provided recipients array must contain only wrapped X25519 JWK values.
///
/// You may acquire X25519 JWK values using the `toX25519PublicJWK` method on the keypair structs.
#[wasm_bindgen(js_name = "encryptChaCha20")]
pub fn encrypt_chacha20(payload: Uint8Array, recipients: Vec<JWK>) -> Result<Object, JsError> {
let jwe = teddybear_jwe::encrypt::<XC20P>(
&payload.to_vec(),
&recipients.iter().map(|val| &val.0).collect::<Vec<_>>(),
)?;
Expand Down
3 changes: 2 additions & 1 deletion crates/teddybear-jwe/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ repository.workspace = true
categories.workspace = true

[dependencies]
askar-crypto = { version = "0.3.0", default-features = false, features = ["aes", "ed25519", "std"] }
askar-crypto = { version = "0.3.0", default-features = false, features = ["aes", "chacha", "ed25519", "std"] }
base64 = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
ssi-jwk = { workspace = true }

[dev-dependencies]
paste = "1.0.14"
teddybear-crypto = { workspace = true }
tokio = { workspace = true, features = ["test-util"] }
Loading

0 comments on commit 0b12a7f

Please sign in to comment.