16 个不稳定版本 (5 个破坏性更新)
0.7.2 | 2022年3月23日 |
---|---|
0.6.7 | 2022年1月26日 |
0.6.3 | 2021年12月3日 |
0.6.2 | 2021年11月19日 |
0.1.0 | 2020年11月9日 |
#584 in 异步
170KB
3K SLoC
didcomm-rs
Rust 实现 DIDComm v2 规范
许可证
使用示例
1. 准备发送和接收的原始消息
前往: 完整测试
// Message construction
let m = Message::new()
// setting `from` header (sender) - Optional
.from("did:xyz:ulapcuhsatnpuhza930hpu34n_")
// setting `to` header (recipients) - Optional
.to(&[
"did::xyz:34r3cu403hnth03r49g03",
"did:xyz:30489jnutnjqhiu0uh540u8hunoe",
])
// populating body with some data - `Vec<bytes>`
.body(TEST_DID);
// Serialize message into JWM json (SENDER action)
let ready_to_send = m.clone().as_raw_json().unwrap();
// ... transport is happening here ...
// On receival deserialize from json into Message (RECEIVER action)
// Error handling recommended here
let received = Message::receive(&ready_to_send, None, None, None);
2. 准备直接发送的 JWE 消息
前往: 完整测试
// sender key as bytes
let ek = [130, 110, 93, 113, 105, 127, 4, 210, 65, 234, 112, 90, 150, 120, 189, 252, 212, 165, 30, 209, 194, 213, 81, 38, 250, 187, 216, 14, 246, 250, 166, 92];
// Message construction
let message = Message::new()
.from("did:key:z6MkiTBz1ymuepAQ4HEHYSF1H8quG5GLVVQR3djdX3mDooWp")
.to(&[
"did:key:z6MkiTBz1ymuepAQ4HEHYSF1H8quG5GLVVQR3djdX3mDooWp",
"did:key:z6MkjchhfUsD6mmvni8mCdXHw216Xrm9bQe2mBH1P5RDjVJG",
])
// packing in some payload (can be anything really)
.body(TEST_DID)
// decide which [Algorithm](crypto::encryptor::CryptoAlgorithm) is used (based on key)
.as_jwe(
&CryptoAlgorithm::XC20P,
Some(&bobs_public),
)
// add some custom app/protocol related headers to didcomm header portion
// these are not included into JOSE header
.add_header_field("my_custom_key".into(), "my_custom_value".into())
.add_header_field("another_key".into(), "another_value".into())
// set `kid` property
.kid(r#"#z6LShs9GGnqk85isEBzzshkuVWrVKsRp24GnDuHk8QWkARMW"#);
// recipient public key is automatically resolved
let ready_to_send = message.seal(
&ek,
Some(vec![Some(&bobs_public), Some(&carol_public)]),
).unwrap();
//... transport is happening here ...
3. 准备 JWS 消息 -> 发送 -> 接收
- 在这里
Message
已签名但未加密。 - 在这种情况下,需要显式使用
.sign(...)
和Message::verify(...)
。
// Message construction an JWS wrapping
let message = Message::new() // creating message
.from("did:xyz:ulapcuhsatnpuhza930hpu34n_") // setting from
.to(&["did::xyz:34r3cu403hnth03r49g03", "did:xyz:30489jnutnjqhiu0uh540u8hunoe"]) // setting to
.body(TEST_DID) // packing in some payload
.as_jws(&SignatureAlgorithm::EdDsa)
.sign(SignatureAlgorithm::EdDsa.signer(), &sign_keypair.to_bytes()).unwrap();
//... transport is happening here ...
// Receiving JWS
let received = Message::verify(&message.as_bytes(), &sign_keypair.public.to_bytes());
4. 准备要调解的 JWE 消息 -> 调解 -> 接收
- 消息应首先在
.routed_by()
方法调用中使用接收者的密钥加密。 - 然后应使用调解者的密钥在
.seal()
方法调用中加密 - 这可以多次进行 - 一次对应链中的每个调解者,但应严格顺序进行,以匹配链中的调解者顺序。 - 方法调用
.seal()
必须 在.as_jwe(CryptoAlgorithm)
前面,因为中介可能使用与目的地不同的算法和密钥类型,这不是自动预测或填充的。 - 用于加密的密钥应按反向顺序使用 - 最终目的地 - 最后一个中介 - 第二到最后的中介 - 等等。洋葱式。
转到: 完整测试
let mediated = Message::new()
// setting from
.from("did:key:z6MkiTBz1ymuepAQ4HEHYSF1H8quG5GLVVQR3djdX3mDooWp")
// setting to
.to(&["did:key:z6MkjchhfUsD6mmvni8mCdXHw216Xrm9bQe2mBH1P5RDjVJG"])
// packing in some payload
.body(r#"{"foo":"bar"}"#)
// set JOSE header for XC20P algorithm
.as_jwe(&CryptoAlgorithm::XC20P, Some(&bobs_public))
// custom header
.add_header_field("my_custom_key".into(), "my_custom_value".into())
// another custom header
.add_header_field("another_key".into(), "another_value".into())
// set kid header
.kid(&"Ef1sFuyOozYm3CEY4iCdwqxiSyXZ5Br-eUDdQXk6jaQ")
// here we use destination key to bob and `to` header of mediator -
//**THIS MUST BE LAST IN THE CHAIN** - after this call you'll get new instance of envelope `Message` destined to the mediator.
.routed_by(
&alice_private,
Some(vec![Some(&bobs_public)]),
"did:key:z6MknGc3ocHs3zdPiJbnaaqDi58NGb4pk1Sp9WxWufuXSdxf",
Some(&mediators_public),
);
assert!(mediated.is_ok());
//... transport to mediator is happening here ...
// Received by mediator
let mediator_received = Message::receive(
&mediated.unwrap(),
Some(&mediators_private),
Some(&alice_public),
None,
);
assert!(mediator_received.is_ok());
// Get inner JWE as string from message
let mediator_received_unwrapped = mediator_received.unwrap().get_body().unwrap();
let pl_string = String::from_utf8_lossy(mediator_received_unwrapped.as_ref());
let message_to_forward: Mediated = serde_json::from_str(&pl_string).unwrap();
let attached_jwe = serde_json::from_slice::<Jwe>(&message_to_forward.payload);
assert!(attached_jwe.is_ok());
let str_jwe = serde_json::to_string(&attached_jwe.unwrap());
assert!(str_jwe.is_ok());
//... transport to destination is happening here ...
// Received by Bob
let bob_received = Message::receive(
&String::from_utf8_lossy(&message_to_forward.payload),
Some(&bobs_private),
Some(&alice_public),
None,
);
assert!(bob_received.is_ok());
5. 准备包含在JWE中的JWS信封 -> 签名 -> 打包 -> 接收
- JWS头根据签名算法类型自动设置。
- 消息形成和加密与其他JWE示例中的方式相同。
- 本例中使用ED25519-dalek签名,使用密钥对进行签名,使用公钥进行验证。
转到: 完整测试
let KeyPairSet {
alice_public,
alice_private,
bobs_private,
bobs_public,
..
} = get_keypair_set();
// Message construction
let message = Message::new() // creating message
.from("did:xyz:ulapcuhsatnpuhza930hpu34n_") // setting from
.to(&["did::xyz:34r3cu403hnth03r49g03"]) // setting to
.body(TEST_DID) // packing in some payload
.as_jwe(&CryptoAlgorithm::XC20P, Some(&bobs_public)) // set JOSE header for XC20P algorithm
.add_header_field("my_custom_key".into(), "my_custom_value".into()) // custom header
.add_header_field("another_key".into(), "another_value".into()) // another custom header
.kid(r#"Ef1sFuyOozYm3CEY4iCdwqxiSyXZ5Br-eUDdQXk6jaQ"#); // set kid header
// Send as signed and encrypted JWS wrapped into JWE
let ready_to_send = message.seal_signed(
&alice_private,
Some(vec![Some(&bobs_public)]),
SignatureAlgorithm::EdDsa,
&sign_keypair.to_bytes(),
).unwrap();
//... transport to destination is happening here ...
// Receive - same method to receive for JWE or JWS wrapped into JWE but with pub verifying key
let received = Message::receive(
&ready_to_send,
Some(&bobs_private),
Some(&alice_public),
None,
); // and now we parse received
6. 多个接收者,每个接收者使用共享密钥进行静态密钥封装
- ! 仅与
resolve
功能一起工作 - 需要为每个接收者解析公钥以生成共享密钥。 - 静态密钥在后台随机生成(
to
字段有 >1 个接收者)。
转到: 完整测试
// Creating message with multiple recipients.
let m = Message::new()
.from("did:key:z6MkiTBz1ymuepAQ4HEHYSF1H8quG5GLVVQR3djdX3mDooWp")
.to(&[
"did:key:z6MkjchhfUsD6mmvni8mCdXHw216Xrm9bQe2mBH1P5RDjVJG",
"did:key:z6MknGc3ocHs3zdPiJbnaaqDi58NGb4pk1Sp9WxWufuXSdxf",
])
.as_jwe(&CryptoAlgorithm::XC20P, None);
let jwe = m.seal(&alice_private, None);
// Packing was ok?
assert!(jwe.is_ok());
let jwe = jwe.unwrap();
// Each of the recipients receive it in same way as before (direct with single recipient)
let received_first = Message::receive(&jwe, Some(&bobs_private), None, None);
let received_second = Message::receive(&jwe, Some(&carol_private), None, None);
// All good without any extra inputs
assert!(received_first.is_ok());
assert!(received_second.is_ok());
7. 与 attachments
一起工作
7.1 添加 Attachment
use didcomm_rs::{Message, AttachmentBuilder, AttachmentDataBuilder};
let payload = b"some usefull data";
let mut m = Message:new();
m.append_attachment(
AttachmentBuilder::new(true)
.with_id("best attachment")
.with_data(
AttachmentDataBuilder::new()
.with_raw_payload(payload)
)
);
或
use didcomm_rs::{Message, AttachmentBuilder, AttachmentDataBuilder};
let attachments: Vec<AttachmentBuilder>; // instantiate properly
let mut m = Message:new();
for attachment in attachments {
m.append_attachment(attachment);
}
7.2 解析 Attachment
的
// `m` is `receive()`'d instance of a `Message`
let something_im_looking_for = m.get_attachments().filter(|single| single.id == "id I'm looking for");
assert!(something_im_looking_for.next().is_some());
for found in something_im_looking_for {
// process attachments
}
8. 线程
默认情况下,所有新消息都使用随机UUID作为 thid
标头值,并使用空的 pthid
值。
要回复线程中的消息并复制 thid
和 pthid
,请使用 reply_to
方法
let m = Message::new()
.reply_to(&received)
// - other methods to form a message
;
要设置父线程ID(或 pthid
标头),请使用 with_parent
方法
let m = Message::new()
.with_parent(&receievd)
// - other methods to form a message
;
9. 其他应用级标头和装饰器
为了满足任何其他标头值,存在一个通用方法:Message::add_header_field' 此方法由一个
HashMap` 的 <String, String> 支持。如果存在键,则更新其值。
let m = Message::new()
.add_header_field("key", "value")
.add_header_field("~decorator", "value")
// - other methods to form a message
;
要查找特定应用级标头是否存在并获取其值,应使用 get_application_params
方法。
let m: Message; // proprely instantiated received message
if let Some((my_key, my_value)) = m.get_application_params().filter(|(key, _)| key == "my_key").first();
可插入的加密
为了使用自己的消息加密和/或签名算法的实现,实现这些特质
不要使用 default
功能 - 可能在未来更改。
实现后 - 使用它们而不是上面的示例中的 CryptoAlgorithm
和 SignatureAlgorithm
。
强类型消息有效负载(主体)
转到: 完整测试
在大多数情况下,应用程序实现更喜欢有强类型消息主体而不是原始 Vec<u8>
。对于此场景,应为目标类型实现 Shape
特质。
- 首先,让我们定义我们的目标类型。本例中的JSON。
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct DesiredShape {
num_field: usize,
string_field: String,
}
- 接下来,为目标类型实现
Shape
特质
impl Shape for DesiredShape {
type Err = Error;
fn shape(m: &Message) -> Result<DesiredShape, Error> {
serde_json::from_str(&m.get_body().unwrap())
.map_err(|e| Error::SerdeError(e))
}
}
- 现在我们可以在我们的
Message
上调用shape()
并将其塑形。 - 在这个例子中,我们期望JSON有效负载并使用其反序列化器来获取我们的数据,但您的实现可以与任何序列化一起工作。
let body = r#"{"num_field":123,"string_field":"foobar"}"#.to_string();
let message = Message::new() // creating message
.from("did:xyz:ulapcuhsatnpuhza930hpu34n_") // setting from
.to(&["did::xyz:34r3cu403hnth03r49g03"]) // setting to
.body(&body); // packing in some payload
let received_typed_body = DesiredShape::shape(&message).unwrap(); // Where m = Message
免责声明
这是DIDComm V2规范的示例实现。DIDComm V2规范仍在DIF的DIDComm工作组中积极开发,因此可能会发生变化。
依赖关系
~7–21MB
~291K SLoC