Skip to content

Commit f15bb75

Browse files
parfeonXavraxjosh-lubliner
authored
Add crypto module (#175)
feat(crypto): add crypto module Add crypto module that allows to configure SDK to encrypt and decrypt messages. fix(crypto): fix legacy cryptor Improved security of crypto implementation by adding enhanced AES-CBC cryptor. --------- Co-authored-by: Mateusz Dahlke <[email protected]> Co-authored-by: Xavrax <[email protected]> Co-authored-by: josh-lubliner <[email protected]>
1 parent d917aec commit f15bb75

27 files changed

+1741
-247
lines changed

.pubnub.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
name: rust
2-
version: 0.3.0
2+
version: 0.4.0
33
schema: 1
44
scm: github.com/pubnub/rust
55
files: []
66
changelog:
7+
- date: 2023-10-16
8+
version: 0.4.0
9+
changes:
10+
- type: feature
11+
text: "Update the crypto module structure and add enhanced AES-CBC cryptor."
712
- date: 2023-08-30
813
version: 0.3.0
914
changes:

Cargo.toml

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,24 @@
11
[package]
22
name = "pubnub"
3-
version = "0.3.0"
3+
version = "0.4.0"
44
edition = "2021"
55
license = "MIT"
6+
license-file = "LICENSE"
67
authors = ["PubNub <[email protected]>"]
78
description = "PubNub SDK for Rust"
89
repository = "https://github.com/pubnub/rust"
9-
documentation = "https://docs.rs/pubnub/latest/pubnub"
10+
documentation = "https://docs.rs/pubnub/latest/pubnub"
1011
homepage = "https://www.pubnub.com"
1112
categories = ["api-bindings", "asynchronous", "network-programming", "wasm"]
1213
build = "build.rs"
1314

1415
[features]
1516

1617
# Enables all non-conflicting features
17-
full = ["publish", "subscribe", "presence", "access", "serde", "reqwest", "aescbc", "parse_token", "blocking", "std", "tokio"]
18+
full = ["publish", "subscribe", "presence", "access", "serde", "reqwest", "crypto", "parse_token", "blocking", "std", "tokio"]
1819

1920
# Enables all default features
20-
default = ["publish", "subscribe", "serde", "reqwest", "aescbc", "std", "blocking", "tokio"]
21+
default = ["publish", "subscribe", "serde", "reqwest", "std", "blocking", "tokio"]
2122

2223
# [PubNub features]
2324

@@ -27,8 +28,8 @@ publish = []
2728
## Enables access manager feature
2829
access = []
2930

30-
## Enables AES-CBC encryption
31-
aescbc = ["dep:aes", "dep:cbc", "getrandom"]
31+
## Enables crypto module
32+
crypto = ["dep:aes", "dep:cbc", "getrandom"]
3233

3334
## Enables token parsing
3435
parse_token = ["dep:ciborium"]
@@ -48,7 +49,7 @@ tokio = ["dep:tokio"]
4849
blocking = ["reqwest?/blocking"]
4950

5051
## Enables std library
51-
std = ["derive_builder/std", "log/std", "uuid/std", "base64/std", "spin/std", "snafu/std", "hmac/std", "sha2/std", "time/std", "bytes?/std", "getrandom/std", "rand/default", "serde?/std", "serde_json?/std", "ciborium?/std", "futures?/std", "futures?/async-await", "dep:async-channel"]
52+
std = ["derive_builder/std", "log/std", "uuid/std", "base64/std", "spin/std", "snafu/std", "hmac/std", "sha2/std", "time/std", "bytes?/std", "getrandom/std", "rand/default", "serde?/std", "serde_json?/std", "ciborium?/std", "futures?/std", "futures?/async-await", "dep:async-channel"]
5253

5354
## Enables very specific implementations for different platforms.
5455
##
@@ -60,13 +61,13 @@ std = ["derive_builder/std", "log/std", "uuid/std", "base64/std", "spin/std", "s
6061
## https://docs.rs/portable_atomic
6162
## and
6263
## https://docs.rs/critical-section/latest/critical_section/
63-
extra_platforms = ["spin/portable_atomic", "dep:portable-atomic"]
64+
extra_platforms = ["spin/portable_atomic", "dep:portable-atomic"]
6465

6566
# [Internal features] (not intended for use outside of the library)
66-
contract_test = ["parse_token", "publish", "access"]
67-
full_no_std = ["serde", "reqwest", "aescbc", "parse_token", "blocking", "publish", "access", "subscribe", "tokio", "presence"]
68-
full_no_std_platform_independent = ["serde", "aescbc", "parse_token", "blocking", "publish", "access", "subscribe", "presence"]
69-
pubnub_only = ["aescbc", "parse_token", "blocking", "publish", "access", "subscribe", "presence"]
67+
contract_test = ["parse_token", "publish", "access", "crypto"]
68+
full_no_std = ["serde", "reqwest", "crypto", "parse_token", "blocking", "publish", "access", "subscribe", "tokio", "presence"]
69+
full_no_std_platform_independent = ["serde", "crypto", "parse_token", "blocking", "publish", "access", "subscribe", "presence"]
70+
pubnub_only = ["crypto", "parse_token", "blocking", "publish", "access", "subscribe", "presence"]
7071
mock_getrandom = ["getrandom/custom"]
7172
# TODO: temporary treated as internal until we officially release it
7273
subscribe = ["dep:futures"]
@@ -139,6 +140,10 @@ name = "contract_test"
139140
harness = false
140141
required-features = ["contract_test"]
141142

143+
[[example]]
144+
name = "crypto"
145+
required-features = ["default", "crypto"]
146+
142147
[[example]]
143148
name = "publish"
144149
required-features = ["default"]
@@ -194,4 +199,3 @@ required-features = ["default", "presence"]
194199
[[example]]
195200
name = "presence_state_blocking"
196201
required-features = ["default", "blocking", "presence"]
197-

LICENSE

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,29 @@
1-
The MIT License (MIT)
1+
PubNub Software Development Kit License Agreement
2+
Copyright © 2023 PubNub Inc. All rights reserved.
23

3-
Copyright (c) 2023 PubNub Inc.
4+
Subject to the terms and conditions of the license, you are hereby granted
5+
a non-exclusive, worldwide, royalty-free license to (a) copy and modify
6+
the software in source code or binary form for use with the software services
7+
and interfaces provided by PubNub, and (b) redistribute unmodified copies
8+
of the software to third parties. The software may not be incorporated in
9+
or used to provide any product or service competitive with the products
10+
and services of PubNub.
411

5-
Permission is hereby granted, free of charge, to any person obtaining a copy
6-
of this software and associated documentation files (the "Software"), to deal
7-
in the Software without restriction, including without limitation the rights
8-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9-
copies of the Software, and to permit persons to whom the Software is
10-
furnished to do so, subject to the following conditions:
12+
The above copyright notice and this license shall be included
13+
in or with all copies or substantial portions of the software.
1114

12-
The above copyright notice and this permission notice shall be included in all
13-
copies or substantial portions of the Software.
15+
This license does not grant you permission to use the trade names, trademarks,
16+
service marks, or product names of PubNub, except as required for reasonable
17+
and customary use in describing the origin of the software and reproducing
18+
the content of this license.
1419

15-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21-
SOFTWARE.
20+
THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF
21+
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
23+
EVENT SHALL PUBNUB OR THE AUTHORS OR COPYRIGHT HOLDERS OF THE SOFTWARE BE
24+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
25+
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2227

28+
https://www.pubnub.com/
29+
https://www.pubnub.com/terms

README.md

Lines changed: 37 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@
1717
This is the official PubNub Rust SDK repository.
1818

1919
[PubNub](https://www.pubnub.com/) takes care of the infrastructure and APIs needed for the realtime
20-
communication layer of your application. Work on your app's logic and let PubNub handle sending and receiving
21-
data across the world in less than 100ms.
20+
communication layer of your application. Work on your app's logic and let
21+
PubNub handle sending and receiving data across the world in less than
22+
100ms.
2223

2324
## Getting started
2425

@@ -35,11 +36,11 @@ Add `pubnub` to your Rust project in the `Cargo.toml` file:
3536
```toml
3637
# default features
3738
[dependencies]
38-
pubnub = "0.3.0"
39+
pubnub = "0.4.0"
3940

4041
# all features
4142
[dependencies]
42-
pubnub = { version = "0.3.0", features = ["full"] }
43+
pubnub = { version = "0.4.0", features = ["full"] }
4344
```
4445

4546
### Example
@@ -125,24 +126,25 @@ You can find more examples in our [examples](https://github.com/pubnub/rust/tree
125126

126127
## Features
127128

128-
The `pubnub` crate is split into multiple features. You can enable or disable them in the `Cargo.toml` file, like so:
129+
The `pubnub` crate is split into multiple features. You can enable or
130+
disable them in the `Cargo.toml` file, like so:
129131

130132
```toml
131133
# only blocking and access + default features
132134
[dependencies]
133-
pubnub = { version = "0.3.0", features = ["blocking", "access"] }
135+
pubnub = { version = "0.4.0", features = ["blocking", "access"] }
134136

135137
# only parse_token + default features
136138
[dependencies]
137-
pubnub = { version = "0.3.0", features = ["parse_token"] }
139+
pubnub = { version = "0.4.0", features = ["parse_token"] }
138140
```
139141

140142
### Available features
141143

142144
| Feature name | Description | Available PubNub APIs |
143145
| :------------ | :---------- | :------------- |
144-
| `full` | Enables all non-conflicting features | Configuration, Publish, Subscribe, Access Manager, Parse Token, Presence |
145-
| `default` | Enables default features: `publish`, `subscribe`, `serde`, `reqwest`, `aescbc`, `std` | Configuration, Publish, Subscribe |
146+
| `full` | Enables all non-conflicting features | Configuration, Publish, Subscribe, Access Manager, Parse Token, Presence, Crypto Module |
147+
| `default` | Enables default features: `publish`, `subscribe`, `serde`, `reqwest`, `std` | Configuration, Publish, Subscribe |
146148
| `publish` | Enables Publish API | Configuration, Publish |
147149
| `access` | Enables Access Manager API | Configuration, Access Manager |
148150
| `parse_token` | Enables parsing Access Manager tokens | Configuration, Parse Token |
@@ -152,7 +154,7 @@ pubnub = { version = "0.3.0", features = ["parse_token"] }
152154
| `serde` | Uses [serde](https://github.com/serde-rs/serde) for serialization | n/a |
153155
| `reqwest` | Uses [reqwest](https://github.com/seanmonstar/reqwest) as a transport layer | n/a |
154156
| `blocking` | Enables blocking executions of APIs | n/a |
155-
| `aescbc` | Enables AES-CBC encryption | n/a |
157+
| `crypto` | Enables crypto module for data encryption and decryption | n/a |
156158
| `std` | Enables `std` library | n/a |
157159

158160
## Documentation
@@ -162,52 +164,61 @@ pubnub = { version = "0.3.0", features = ["parse_token"] }
162164

163165
## Wasm support
164166

165-
The `pubnub` crate is compatible with WebAssembly. You can use it in your Wasm project.
167+
The `pubnub` crate is compatible with WebAssembly. You can use it in your
168+
Wasm project.
166169

167170
## `no_std` support
168171

169-
The `pubnub` crate is `no_std` compatible. To use it in a `no_std` environment, you have to disable the default
170-
features and enable the ones you need, for example:
172+
The `pubnub` crate is `no_std` compatible. To use it in a `no_std`
173+
environment, you have to disable the default features and enable the ones
174+
you need, for example:
171175

172176
```toml
173177
[dependencies]
174-
pubnub = { version = "0.3.0", default-features = false, features = ["serde", "publish",
178+
pubnub = { version = "0.4.0", default-features = false, features = ["serde", "publish",
175179
"blocking"] }
176180
```
177181

178182
### Limitations
179183

180184
The `no_std` support is limited by the implementation details of the SDK.
181185

182-
The SDK uses the `alloc` crate to allocate memory for some operations, which means that
183-
certain targets aren't supported. Additionally, as we provide a synchronous API, we use
184-
some parts of the `alloc::sync` module, which is also not supported in certain `no_std` environments.
186+
The SDK uses the `alloc` crate to allocate memory for some operations, which
187+
means that certain targets aren't supported. Additionally, as we provide a
188+
synchronous API, we use some parts of the `alloc::sync` module, which is
189+
also not supported in certain `no_std` environments.
185190

186191
Some SDK features aren't supported in a `no_std` environment:
187192

188193
* partially `access` module (because of lack of timestamp support)
189-
* partially `reqwest` transport (because of the reqwest implementation details)
190-
* partially `subscribe` module (because of the spawning tasks and time dependence)
191-
* partially `presence` module (because of the spawning tasks and time dependence)
194+
* partially `reqwest` transport (because of the reqwest implementation
195+
details)
196+
* partially `subscribe` module (because of the spawning tasks and time
197+
dependence)
198+
* partially `presence` module (because of the spawning tasks and time
199+
dependence)
192200
* `std` feature (because of the `std` library)
193201

194-
We depend on a random number generator to generate data for debugging purposes.
195-
If you want to use the SDK in a `no_std` environment, you'll have to provide
196-
your own random number generator implementation for certain targets.
202+
We depend on a random number generator to generate data for debugging
203+
purposes. If you want to use the SDK in a `no_std` environment, you'll have
204+
to provide your own random number generator implementation for certain
205+
targets.
197206

198207
See more:
199208

200209
* [`getrandom` crate](https://docs.rs/getrandom/latest/getrandom/)
201210
* [no_std examples](https://github.com/pubnub/rust/tree/master/examples/no_std/)
202211

203-
If you're having problems compiling this crate for more exotic targets, you can try to use the
204-
`extra_platforms` feature. Be aware that this feature is **not supported** and we do not recommend using it.
212+
If you're having problems compiling this crate for more exotic targets, you
213+
can try to use the `extra_platforms` feature. Be aware that this feature is
214+
**not supported** and we do not recommend using it.
205215

206216
For more information about this feature. refer to [Cargo.toml](https://github.com/pubnub/rust/blob/master/Cargo.toml) in the `[features]` section.
207217

208218
## Support
209219

210-
If you **need help** or have a **general question**, contact [email protected].
220+
If you **need help** or have a **general question**, contact
221+
211222

212223
## License
213224

examples/crypto.rs

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
use pubnub::core::CryptoProvider;
2+
use pubnub::providers::crypto::CryptoModule;
3+
use pubnub::{Keyset, PubNubClientBuilder};
4+
use std::env;
5+
6+
/// This example demonstrates how data can be manually encrypted or
7+
/// automatically as part of PubNubClient instance when publish / subscribe is
8+
/// used.
9+
///
10+
/// The following example consists of two parts: a manual _encryption_ and
11+
/// _decryption_ demonstration, and an automated _encryption_ and _decryption_
12+
/// demonstration, as part of a configured `PubNubClientInstance`.
13+
14+
#[tokio::main]
15+
async fn main() -> Result<(), Box<dyn snafu::Error>> {
16+
let source_data: Vec<u8> = "Hello world!".into();
17+
let use_random_iv = true;
18+
let cipher = "enigma";
19+
20+
// -----------------------------------------
21+
// Manual encryption and decryption example.
22+
//
23+
24+
// Crypto module with legacy AES-CBC cryptor (with enhanced AES-CBC decrypt
25+
// support).
26+
let legacy_crypto_module = CryptoModule::new_legacy_module(cipher, use_random_iv)?;
27+
let legacy_encrypt_result = legacy_crypto_module.encrypt(source_data.clone());
28+
29+
println!("encrypt with legacy AES-CBC result: {legacy_encrypt_result:?}");
30+
31+
// Crypto module with enhanced AES-CBC cryptor (with legacy AES-CBC decrypt
32+
// support).
33+
let crypto_module = CryptoModule::new_aes_cbc_module(cipher, use_random_iv)?;
34+
let encrypt_result = crypto_module.encrypt(source_data.clone());
35+
36+
println!("encrypt with enhanced AES-CBC result: {encrypt_result:?}");
37+
38+
// Decrypt data created with legacy AES-CBC crypto module.
39+
let legacy_decrypt_result = crypto_module.decrypt(legacy_encrypt_result.ok().unwrap())?;
40+
assert_eq!(legacy_decrypt_result, source_data);
41+
42+
// Decrypt data created with enhanced AES-CBC crypto module.
43+
let decrypt_result = legacy_crypto_module.decrypt(encrypt_result.ok().unwrap())?;
44+
assert_eq!(decrypt_result, source_data);
45+
46+
// --------------------------------------------
47+
// Automated encryption and decryption example.
48+
//
49+
50+
// Setup client with crypto module
51+
let publish_key = env::var("SDK_PUB_KEY")?;
52+
let subscribe_key = env::var("SDK_SUB_KEY")?;
53+
54+
let client = PubNubClientBuilder::with_reqwest_transport()
55+
.with_keyset(Keyset {
56+
subscribe_key,
57+
publish_key: Some(publish_key),
58+
secret_key: None,
59+
})
60+
.with_user_id("user_id")
61+
.with_cryptor(crypto_module)
62+
.build()?;
63+
64+
// publish encrypted string
65+
let result = client
66+
.publish_message("hello world!")
67+
.channel("my_channel")
68+
.r#type("text-message")
69+
.execute()
70+
.await?;
71+
72+
println!("publish result: {:?}", result);
73+
74+
Ok(())
75+
}

src/core/crypto_provider.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//! # Crypto provider module
2+
//!
3+
//! This module contains the [`CryptoProvider`] trait, which is used to
4+
//! implement a module that can be used to configure [`PubNubClientInstance`] or
5+
//! for manual data encryption and decryption.
6+
7+
use crate::{
8+
core::PubNubError,
9+
lib::{alloc::vec::Vec, core::fmt::Debug},
10+
};
11+
12+
/// Crypto provider trait.
13+
pub trait CryptoProvider: Debug + Send + Sync {
14+
/// Encrypt provided data.
15+
///
16+
/// # Errors
17+
/// Should return an [`PubNubError::Encryption`] if provided data can't be
18+
/// _encrypted_ or underlying cryptor misconfigured.
19+
fn encrypt(&self, data: Vec<u8>) -> Result<Vec<u8>, PubNubError>;
20+
21+
/// Decrypt provided data.
22+
///
23+
/// # Errors
24+
/// Should return an [`PubNubError::Decryption`] if provided data can't be
25+
/// _decrypted_ or underlying cryptor misconfigured.
26+
fn decrypt(&self, data: Vec<u8>) -> Result<Vec<u8>, PubNubError>;
27+
}

0 commit comments

Comments
 (0)