Skip to content

Commit 8b2e0eb

Browse files
authored
srp: add getrandom and rand_core features (#249)
Also adds an `EphemeralSecret` type alias. Updates the docs to use the `Generate` trait to generate an `EphemeralSecret`, instead of the example using all zeros with a comment that you should probably fill that zero array using an RNG somehow.
1 parent 5c3357d commit 8b2e0eb

File tree

10 files changed

+69
-78
lines changed

10 files changed

+69
-78
lines changed

.github/workflows/srp.yml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ jobs:
3535
with:
3636
toolchain: ${{ matrix.rust }}
3737
targets: ${{ matrix.target }}
38-
- run: cargo build --target ${{ matrix.target }} --release --no-default-features
38+
- run: cargo build --target ${{ matrix.target }} --no-default-features
3939

4040
test:
4141
runs-on: ubuntu-latest
@@ -49,4 +49,7 @@ jobs:
4949
- uses: dtolnay/rust-toolchain@master
5050
with:
5151
toolchain: ${{ matrix.rust }}
52-
- run: cargo test --release
52+
- run: cargo test --no-default-features
53+
- run: cargo test
54+
- run: cargo test --all-features
55+
- run: cargo test --all-features --release

Cargo.lock

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

srp/Cargo.toml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ edition = "2024"
1717
rust-version = "1.85"
1818

1919
[dependencies]
20-
crypto-bigint = { version = "0.7.0-rc.17", features = ["alloc"] }
20+
bigint = { package = "crypto-bigint", version = "0.7.0-rc.17", features = ["alloc"] }
21+
common = { package = "crypto-common", version = "0.2.0-rc.9" }
2122
digest = "0.11.0-rc.5"
2223
subtle = { version = "2.4", default-features = false }
2324

@@ -26,3 +27,11 @@ getrandom = { version = "0.4.0-rc.0", features = ["sys_rng"] }
2627
hex-literal = "1"
2728
sha1 = "0.11.0-rc.3"
2829
sha2 = "0.11.0-rc.3"
30+
31+
[features]
32+
default = ["getrandom"]
33+
getrandom = ["rand_core", "bigint/getrandom", "common/getrandom"]
34+
rand_core = ["common/rand_core"]
35+
36+
[package.metadata.docs.rs]
37+
all-features = true

srp/src/client.rs

Lines changed: 12 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::{errors::AuthError, groups::*, utils::*};
22
use alloc::vec::Vec;
3+
use bigint::{BoxedUint, ConcatenatingMul, Odd, Resize, modular::BoxedMontyForm};
34
use core::marker::PhantomData;
4-
use crypto_bigint::{BoxedUint, ConcatenatingMul, Odd, Resize, modular::BoxedMontyForm};
55
use digest::{Digest, Output};
66
use subtle::ConstantTimeEq;
77

@@ -38,12 +38,15 @@ pub type ClientG4096<D> = Client<G4096, D>;
3838
/// Next send handshake data (username and `a_pub`) to the server and receive
3939
/// `salt` and `b_pub`:
4040
///
41-
/// ```rust
41+
#[cfg_attr(feature = "getrandom", doc = "```")]
42+
#[cfg_attr(not(feature = "getrandom"), doc = "```ignore")]
4243
/// # let client = srp::ClientG2048::<sha2::Sha256>::new();
4344
/// # fn server_response()-> (Vec<u8>, Vec<u8>) { (vec![], vec![]) }
45+
/// // NOTE: requires `getrandom` crate feature is enabled
46+
///
47+
/// use srp::{EphemeralSecret, Generate};
4448
///
45-
/// let mut a = [0u8; 64];
46-
/// // rng.fill_bytes(&mut a);
49+
/// let mut a = EphemeralSecret::generate();
4750
/// let a_pub = client.compute_public_ephemeral(&a);
4851
/// let (salt, b_pub) = server_response();
4952
/// ```
@@ -58,9 +61,8 @@ pub type ClientG4096<D> = Client<G4096, D>;
5861
/// # let password = b"password";
5962
/// # let salt = b"salt";
6063
/// # let b_pub = b"b_pub";
61-
///
6264
/// let private_key = (username, password, salt);
63-
/// let verifier = client.process_reply_legacy(&a, username, password, salt, b_pub);
65+
/// let verifier = client.process_reply(&a, username, password, salt, b_pub);
6466
/// ```
6567
///
6668
/// Finally verify the server: first generate user proof,
@@ -71,7 +73,6 @@ pub type ClientG4096<D> = Client<G4096, D>;
7173
/// # let client = srp::ClientG2048::<sha2::Sha256>::new();
7274
/// # let verifier = client.process_reply(b"", b"", b"", b"", b"1").unwrap();
7375
/// # fn send_proof(_: &[u8]) -> Vec<u8> { vec![173, 202, 13, 26, 207, 73, 0, 46, 121, 238, 48, 170, 96, 146, 60, 49, 88, 76, 12, 184, 152, 76, 207, 220, 140, 205, 190, 189, 117, 6, 131, 63] }
74-
///
7576
/// let client_proof = verifier.proof();
7677
/// let server_proof = send_proof(client_proof);
7778
/// verifier.verify_server(&server_proof).unwrap();
@@ -81,40 +82,21 @@ pub type ClientG4096<D> = Client<G4096, D>;
8182
/// key using `key()` method.
8283
/// ```rust
8384
/// # let client = srp::ClientG2048::<sha2::Sha256>::new();
84-
/// # let verifier = client.process_reply_legacy(b"", b"", b"", b"", b"1").unwrap();
85-
///
85+
/// # let verifier = client.process_reply(b"", b"", b"", b"", b"1").unwrap();
8686
/// verifier.key();
8787
/// ```
8888
///
89-
///
90-
/// Alternatively, you can use `process_reply_rfc5054` method to process parameters
91-
/// according to RFC 5054 if the server is using it. This way, it generates M1 and
92-
/// M2 differently and also the `verify_server` method will return a shared session
93-
/// key in case of correct server data.
94-
///
95-
/// ```ignore
96-
/// # let client = srp::ClientG2048::<sha2::Sha256>::new();
97-
/// # let verifier = client.process_reply_rfc5054(b"", b"", b"", b"", b"1").unwrap();
98-
/// # fn send_proof(_: &[u8]) -> Vec<u8> { vec![10, 215, 214, 40, 136, 200, 122, 121, 68, 160, 38, 32, 85, 82, 128, 30, 199, 194, 126, 222, 61, 55, 2, 28, 120, 181, 155, 102, 141, 65, 17, 64] }
99-
///
100-
/// let client_proof = verifier.proof();
101-
/// let server_proof = send_proof(client_proof);
102-
/// let session_key = verifier.verify_server(&server_proof).unwrap();
103-
/// ```
104-
///
105-
///
10689
/// For user registration on the server first generate salt (e.g. 32 bytes long)
10790
/// and get password verifier which depends on private key. Send username, salt
108-
/// and password verifier over protected channel to protect against
109-
/// Man-in-the-middle (MITM) attack for registration.
91+
/// and password verifier over a protected channel to protect against Man-in-the-middle
92+
/// (MITM) attack for registration.
11093
///
11194
/// ```rust
11295
/// # let client = srp::ClientG2048::<sha2::Sha256>::new();
11396
/// # let username = b"username";
11497
/// # let password = b"password";
11598
/// # let salt = b"salt";
11699
/// # fn send_registration_data(_: &[u8], _: &[u8], _: &[u8]) {}
117-
///
118100
/// let pwd_verifier = client.compute_verifier(username, password, salt);
119101
/// send_registration_data(username, salt, &pwd_verifier);
120102
/// ```
@@ -272,10 +254,7 @@ impl<G: Group, D: Digest> Client<G, D> {
272254
/// - `a` is a random value,
273255
/// - `username`, `password` is supplied by the user
274256
/// - `salt` and `b_pub` come from the server
275-
#[deprecated(
276-
since = "0.7.0",
277-
note = "please switch to `Client::process_reply_rfc5054`"
278-
)]
257+
#[deprecated(since = "0.7.0", note = "please use `Client::process_reply` (RFC5054)")]
279258
#[allow(deprecated)]
280259
pub fn process_reply_legacy(
281260
&self,

srp/src/groups.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@
77
//!
88
//! [RFC5054]: https://tools.ietf.org/html/rfc5054
99
10+
use bigint::{
11+
BoxedUint, Odd, Resize,
12+
modular::{BoxedMontyForm, BoxedMontyParams},
13+
};
1014
use core::{
1115
any,
1216
fmt::{self, Debug},
1317
};
14-
use crypto_bigint::{
15-
BoxedUint, Odd, Resize,
16-
modular::{BoxedMontyForm, BoxedMontyParams},
17-
};
1818

1919
/// Group used for SRP computations.
2020
pub trait Group {

srp/src/lib.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#![no_std]
2+
#![cfg_attr(docsrs, feature(doc_cfg))]
23
#![doc = include_str!("../README.md")]
34
#![doc(
45
html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg",
@@ -78,7 +79,9 @@ mod client;
7879
mod errors;
7980
mod server;
8081

82+
pub use bigint;
8183
pub use client::{Client, ClientG2048, ClientG3072, ClientG4096, ClientVerifier};
84+
pub use common;
8285
pub use errors::AuthError;
8386
pub use groups::Group;
8487
pub use server::{Server, ServerG2048, ServerG3072, ServerG4096, ServerVerifier};
@@ -88,3 +91,16 @@ pub use {
8891
client::{ClientG1024, ClientG1536, LegacyClientVerifier},
8992
server::{LegacyServerVerifier, ServerG1024, ServerG1536},
9093
};
94+
95+
#[cfg(feature = "rand_core")]
96+
pub use common::Generate;
97+
#[cfg(feature = "rand_core")]
98+
pub use common::rand_core;
99+
100+
/// 384-bit ephemeral secret (usable as `a` or `b`).
101+
///
102+
/// Should be large enough for use with any of the groups defined in this crate.
103+
pub type EphemeralSecret = [u8; 48];
104+
105+
/// 256-bit salt value.
106+
pub type Salt = [u8; 16];

srp/src/server.rs

Lines changed: 15 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::{errors::AuthError, groups::*, utils::*};
22
use alloc::vec::Vec;
3+
use bigint::{BoxedUint, Odd, Resize, modular::BoxedMontyForm};
34
use core::marker::PhantomData;
4-
use crypto_bigint::{BoxedUint, Odd, Resize, modular::BoxedMontyForm};
55
use digest::{Digest, Output};
66
use subtle::ConstantTimeEq;
77

@@ -25,18 +25,20 @@ pub type ServerG4096<D> = Server<G4096, D>;
2525
/// # Usage
2626
/// First receive user's username and public value `a_pub`, retrieve from a
2727
/// database the salt and verifier for a given username. Generate `b` and public value `b_pub`.
28+
//
29+
#[cfg_attr(feature = "getrandom", doc = "```")]
30+
#[cfg_attr(not(feature = "getrandom"), doc = "```ignore")]
31+
/// // NOTE: requires `getrandom` crate feature is enabled
2832
///
29-
///
30-
/// ```rust
3133
/// use sha2::Sha256;
34+
/// use srp::{EphemeralSecret, Generate};
3235
/// # fn get_client_request()-> (Vec<u8>, Vec<u8>) { (vec![], vec![])}
3336
/// # fn get_user(_: &[u8])-> (Vec<u8>, Vec<u8>) { (vec![], vec![])}
3437
///
3538
/// let server = srp::ServerG2048::<Sha256>::new();
3639
/// let (username, a_pub) = get_client_request();
3740
/// let (salt, v) = get_user(&username);
38-
/// let mut b = [0u8; 64];
39-
/// // rng.fill_bytes(&mut b);
41+
/// let mut b = EphemeralSecret::generate();
4042
/// let b_pub = server.compute_public_ephemeral(&b, &v);
4143
/// ```
4244
///
@@ -49,53 +51,34 @@ pub type ServerG4096<D> = Server<G4096, D>;
4951
/// # fn get_client_response() -> Vec<u8> { vec![1] }
5052
/// # let b = [0u8; 64];
5153
/// # let v = b"";
52-
///
54+
/// # let username = b"user";
55+
/// # let salt = b"nacl";
5356
/// let a_pub = get_client_response();
54-
/// let verifier = server.process_reply_legacy(&b, v, &a_pub).unwrap();
57+
/// let verifier = server.process_reply(username, salt, &b, v, &a_pub).unwrap();
5558
/// ```
5659
///
5760
///
5861
/// And finally receive user proof, verify it and send server proof in the
5962
/// reply:
6063
///
61-
/// ```rust
64+
/// ```ignore
6265
/// # let server = srp::ServerG2048::<sha2::Sha256>::new();
63-
/// # let verifier = server.process_reply_legacy(b"", b"", b"1").unwrap();
66+
/// # let verifier = server.process_reply(b"", b"", b"", b"", b"1").unwrap();
6467
/// # fn get_client_proof()-> Vec<u8> { vec![26, 80, 8, 243, 111, 162, 238, 171, 208, 237, 207, 46, 46, 137, 44, 213, 105, 208, 84, 224, 244, 216, 103, 145, 14, 103, 182, 56, 242, 4, 179, 57] };
6568
/// # fn send_proof(_: &[u8]) { };
66-
///
6769
/// let client_proof = get_client_proof();
6870
/// verifier.verify_client(&client_proof).unwrap();
6971
/// send_proof(verifier.proof());
7072
/// ```
7173
///
72-
///
7374
/// `key` contains shared secret key between user and the server. You can extract shared secret
7475
/// key using `key()` method.
7576
/// ```rust
7677
/// # let server = srp::ServerG2048::<sha2::Sha256>::new();
77-
/// # let verifier = server.process_reply_legacy(b"", b"", b"1").unwrap();
78-
///
78+
/// # let verifier = server.process_reply(b"", b"", b"", b"", b"1").unwrap();
7979
/// verifier.key();
8080
/// ```
81-
///
82-
///
83-
/// Alternatively, you can use `process_reply_rfc5054` method to process parameters
84-
/// according to RFC 5054 if the client is using it. You need to pass `username` and
85-
/// `salt` in addition to other parameters to this method. This way, it generates M1
86-
/// and M2 differently and also the `verify_client` method will return a shared session
87-
/// key in case of correct server data.
88-
///
89-
/// ```ident
90-
/// # let server = srp::ServerG2048::<sha2::Sha256>::new();
91-
/// # let verifier = server.process_reply_rfc5054(b"", b"", b"", b"", b"1").unwrap();
92-
/// # fn get_client_proof()-> Vec<u8> { vec![53, 91, 252, 129, 223, 201, 97, 145, 208, 243, 229, 232, 20, 118, 108, 126, 244, 68, 237, 38, 121, 24, 181, 53, 155, 103, 134, 44, 107, 204, 56, 50] };
93-
/// # fn send_proof(_: &[u8]) { };
94-
///
95-
/// let client_proof = get_client_proof();
96-
/// let session_key = verifier.verify_client(&client_proof).unwrap();
97-
/// send_proof(verifier.proof());
98-
/// ```
81+
9982
#[derive(Debug)]
10083
pub struct Server<G: Group, D: Digest> {
10184
g: BoxedMontyForm,
@@ -208,10 +191,7 @@ impl<G: Group, D: Digest> Server<G, D> {
208191
/// # Params
209192
/// - `b` is a random value,
210193
/// - `v` is the provided during initial user registration
211-
#[deprecated(
212-
since = "0.7.0",
213-
note = "please switch to `Server::process_reply_rfc5054`"
214-
)]
194+
#[deprecated(since = "0.7.0", note = "please use `Server::process_reply` (RFC5054)")]
215195
#[allow(deprecated)]
216196
pub fn process_reply_legacy(
217197
&self,

srp/src/utils.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use alloc::vec::Vec;
2-
use crypto_bigint::{
2+
use bigint::{
33
BoxedUint, Resize,
44
modular::{BoxedMontyForm, BoxedMontyParams},
55
};

srp/tests/bad_public.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crypto_bigint::BoxedUint;
1+
use bigint::BoxedUint;
22
use sha1::Sha1;
33
use srp::{ClientG2048, ServerG2048};
44

srp/tests/rfc5054.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crypto_bigint::BoxedUint;
1+
use bigint::BoxedUint;
22
use hex_literal::hex;
33
use sha1::Sha1;
44
use srp::utils::{compute_k, compute_u};

0 commit comments

Comments
 (0)