hdk/
x_salsa20_poly1305.rs

1use crate::prelude::*;
2pub use hdi::x_salsa20_poly1305::*;
3
4// -- secretbox encryption -- //
5
6/// Generate a new secure random shared secret suitable for encrypting and
7/// decrypting using x_salsa20_poly1305_{en,de}crypt.
8/// If key_ref is `None` an opaque reference will be auto-generated.
9/// If key_ref is `Some` and that key already exists in the store,
10/// this function will return an error.
11/// If `Ok`, this function will return the KeyRef by which the shared
12/// secret may be accessed.
13pub fn x_salsa20_poly1305_shared_secret_create_random(
14    key_ref: Option<XSalsa20Poly1305KeyRef>,
15) -> ExternResult<XSalsa20Poly1305KeyRef> {
16    HDK.with(|h| {
17        h.borrow()
18            .x_salsa20_poly1305_shared_secret_create_random(key_ref)
19    })
20}
21
22/// Using the Libsodium box algorithm, encrypt a shared secret so that it
23/// may be forwarded to another specific peer.
24pub fn x_salsa20_poly1305_shared_secret_export(
25    sender: X25519PubKey,
26    recipient: X25519PubKey,
27    key_ref: XSalsa20Poly1305KeyRef,
28) -> ExternResult<XSalsa20Poly1305EncryptedData> {
29    HDK.with(|h| {
30        h.borrow()
31            .x_salsa20_poly1305_shared_secret_export(XSalsa20Poly1305SharedSecretExport::new(
32                sender, recipient, key_ref,
33            ))
34    })
35}
36
37/// Using the Libsodium box algorithm, decrypt a shared secret, storing it
38/// in the keystore so that it may be used in `x_salsa20_poly1305_decrypt`.
39/// This method may be co-opted to ingest shared secrets generated by other
40/// custom means. Just be careful, as WASM memory is not a very secure
41/// environment for cryptographic secrets.
42/// If key_ref is `None` an opaque reference string will be auto-generated.
43/// If key_ref is `Some` and that key already exists in the store,
44/// this function will return an error.
45/// If `Ok`, this function will return the KeyRef by which the shared
46/// secret may be accessed.
47pub fn x_salsa20_poly1305_shared_secret_ingest(
48    recipient: X25519PubKey,
49    sender: X25519PubKey,
50    encrypted_data: XSalsa20Poly1305EncryptedData,
51    key_ref: Option<XSalsa20Poly1305KeyRef>,
52) -> ExternResult<XSalsa20Poly1305KeyRef> {
53    HDK.with(|h| {
54        h.borrow()
55            .x_salsa20_poly1305_shared_secret_ingest(XSalsa20Poly1305SharedSecretIngest::new(
56                recipient,
57                sender,
58                encrypted_data,
59                key_ref,
60            ))
61    })
62}
63
64/// Libsodium secret-key authenticated encryption: secretbox.
65///
66/// Libsodium symmetric encryption (a shared key to encrypt/decrypt) is called secretbox.
67/// Secretbox can be used directly to hide data and is part of cryptographic systems such as
68/// [saltpack](https://saltpack.org/).
69///
70/// Important information about secretbox:
71///  - Wasm memory is NOT secure, a compromised host can steal the key.
72///  - The key is SECRET, anyone with the key and nonce can read the encrypted message.
73///  - The nonce is PUBLIC and UNIQUE, it must NEVER be re-used (so we don't allow it to be set).
74///  - Secretbox is designed for 'small' data, break large data into chunks with unique nonces.
75///  - Secretbox is NOT quantum resistant.
76///
77// @todo shift all the secret handling into lair so that we only work with opaque key references.
78///
79/// If you want to hide data:
80///  - Consider using capability tokens and/or dedicated DHT networks to control access.
81///  - Consider how the shared key is being distributed, e.g. maybe use a key exchange protocol.
82///  - Consider that a hybrid approach between network access + encryption might be best.
83///  - Consider that encrypted data cannot be validated effectively by the public DHT.
84///
85/// The main use-case is to control access to data that may be broadcast across a semi-trusted or
86/// untrusted context, where the intended recipients have all negotiated or shared a key outside
87/// that context.
88///
89/// If you want to encrypt content so that a _specific_ recipient (i.e. public key) can decrypt it
90/// then see the libsodium `box` algorithm or similar.
91///
92/// See <https://doc.libsodium.org/secret-key_cryptography/secretbox>
93/// See <https://nacl.cr.yp.to/secretbox.html>
94pub fn x_salsa20_poly1305_encrypt(
95    key_ref: XSalsa20Poly1305KeyRef,
96    data: XSalsa20Poly1305Data,
97) -> ExternResult<XSalsa20Poly1305EncryptedData> {
98    HDK.with(|h| {
99        h.borrow()
100            .x_salsa20_poly1305_encrypt(XSalsa20Poly1305Encrypt::new(key_ref, data))
101    })
102}
103
104// -- curve25519 box encryption -- //
105
106/// Generate a new x25519 keypair in lair from entropy.
107/// Only the pubkey is returned from lair because the secret key never leaves lair.
108pub fn create_x25519_keypair() -> ExternResult<X25519PubKey> {
109    HDK.with(|h| h.borrow().create_x25519_keypair(()))
110}
111
112/// Libsodium keypair based authenticated encryption: box.
113///
114/// Libsodium asymmetric encryption (two keypairs to encrypt/decrypt) is called box.
115/// Box can be used directly to hide data and is part of cryptographic systems such as
116/// [saltpack](https://saltpack.org/).
117///
118/// Important information about box:
119///  - The secret half of the keypair is generated in and remains in lair.
120///  - The nonce is randomly generated in lair for every call to encrypt.
121///  - The nonce is PUBLIC and UNIQUE, it must NEVER be re-used (currently can't be set directly).
122///  - Box is the same encryption as secretbox using ECDH off the keypairs for the shared key.
123///  - Box is repudible. Either keypair can create any message to be read by the other party. Each
124///    party knows they did not create a certain message so they know it came from the counterpary
125///    but neither can prove to a third party that any message wasn't forged. Note that if you want
126///    the opposite it is not enough to simply layer signatures and encryption.
127///    See <https://theworld.com/~dtd/sign_encrypt/sign_encrypt7.html>
128///  - To encrypt something potentially large for potentially many recipients efficiently it may be
129///    worth chunking the large data, secret boxing it with a unique key for each chunk, then
130///    boxing the _keys_ for each recipient alongside the chunks, to avoid encrypting the large
131///    data repeatedly for every recipient.
132///  - Box is NOT quantum resistant.
133///
134/// If you want to hide data:
135///  - Consider using capability tokens and/or dedicated DHT networks to control access.
136///  - Consider how the keypairs are being generated and pubkeys distributed.
137///  - Consider that a hybrid approach between network access + encryption might be best.
138///  - Consider that encrypted data cannot be validated effectively by the public DHT.
139///
140/// The main use-case is to control access to data that may be broadcast across a semi-trusted or
141/// untrusted context, where the intended recipients have all negotiated or shared a key outside
142/// that context.
143///
144/// If you want to encrypt content so that _any_ recipient with a shared secret can decrypt it
145/// then see the libsodium `secretbox` algorithm or similar.
146///
147/// See <https://doc.libsodium.org/public-key_cryptography/authenticated_encryption>
148/// See <https://nacl.cr.yp.to/box.html>
149pub fn x_25519_x_salsa20_poly1305_encrypt(
150    sender: X25519PubKey,
151    recipient: X25519PubKey,
152    data: XSalsa20Poly1305Data,
153) -> ExternResult<XSalsa20Poly1305EncryptedData> {
154    HDK.with(|h| {
155        h.borrow()
156            .x_25519_x_salsa20_poly1305_encrypt(X25519XSalsa20Poly1305Encrypt::new(
157                sender, recipient, data,
158            ))
159    })
160}
161
162/// Libsodium crypto_box encryption, but converts ed25519 *signing*
163/// keys into x25519 encryption keys.
164/// WARNING: Please first understand the downsides of using this function:
165/// <https://doc.libsodium.org/advanced/ed25519-curve25519>
166pub fn ed_25519_x_salsa20_poly1305_encrypt(
167    sender: AgentPubKey,
168    recipient: AgentPubKey,
169    data: XSalsa20Poly1305Data,
170) -> ExternResult<XSalsa20Poly1305EncryptedData> {
171    HDK.with(|h| {
172        h.borrow()
173            .ed_25519_x_salsa20_poly1305_encrypt(Ed25519XSalsa20Poly1305Encrypt::new(
174                sender, recipient, data,
175            ))
176    })
177}