Skip to content

Commit ab6bf9a

Browse files
committed
chore(crypto): use blake3 instead of sha2
This uses blake3 for static file content hashing as well as calculating the session auth hash (using blake3's native keyed mode instead of HMAC). This is done to improve the performance without sacrificing security and to reduce the number of deps when we merge #443.
1 parent e201c9e commit ab6bf9a

File tree

8 files changed

+64
-50
lines changed

8 files changed

+64
-50
lines changed

Cargo.lock

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

Cargo.toml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ async-stream = "0.3"
6767
async-trait = "0.1"
6868
axum = { version = "0.8", default-features = false }
6969
backtrace = "0.3.76"
70+
blake3 = "1.8.3"
7071
bytes = "1.11"
7172
cargo_toml = "0.22"
7273
chrono = { version = "0.4.44", default-features = false }
@@ -85,7 +86,6 @@ darling = "0.23"
8586
deadpool-redis = { version = "0.22", default-features = false }
8687
derive_builder = "0.20"
8788
derive_more = "2"
88-
digest = "0.10"
8989
email_address = "0.2.9"
9090
fake = "4"
9191
fantoccini = "0.22"
@@ -97,7 +97,6 @@ glob = "0.3"
9797
grass = { version = "0.13.4", default-features = false }
9898
heck = "0.5"
9999
hex = "0.4"
100-
hmac = "0.12"
101100
http = "1.4"
102101
http-body = "1"
103102
http-body-util = "0.1.3"
@@ -130,7 +129,6 @@ serde_html_form = { version = "0.4", default-features = false }
130129
serde_json = "1"
131130
serde_path_to_error = "0.1.20"
132131
serde_urlencoded = "0.7"
133-
sha2 = "0.10"
134132
sqlx = { version = "0.8", default-features = false }
135133
subtle = { version = "2", default-features = false }
136134
swagger-ui-redist = { version = "0.1" }

cot/Cargo.toml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ aide = { workspace = true, optional = true }
2020
askama = { workspace = true, features = ["std"] }
2121
async-trait.workspace = true
2222
axum = { workspace = true, features = ["http1", "tokio"] }
23+
blake3.workspace = true
2324
bytes.workspace = true
2425
chrono = { workspace = true, features = ["alloc", "serde", "clock"] }
2526
chrono-tz.workspace = true
@@ -30,14 +31,12 @@ cot_macros.workspace = true
3031
deadpool-redis = { workspace = true, features = ["tokio-comp", "rt_tokio_1"], optional = true }
3132
derive_builder.workspace = true
3233
derive_more = { workspace = true, features = ["debug", "deref", "display", "from"] }
33-
digest.workspace = true
3434
email_address.workspace = true
3535
fake = { workspace = true, optional = true, features = ["derive", "chrono"] }
3636
form_urlencoded.workspace = true
3737
futures-core.workspace = true
3838
futures-util.workspace = true
3939
hex.workspace = true
40-
hmac.workspace = true
4140
http-body-util.workspace = true
4241
http.workspace = true
4342
humantime.workspace = true
@@ -55,7 +54,6 @@ sea-query = { workspace = true, optional = true }
5554
sea-query-binder = { workspace = true, features = ["with-chrono", "runtime-tokio"], optional = true }
5655
serde = { workspace = true, features = ["derive"] }
5756
serde_json = { workspace = true, optional = true }
58-
sha2.workspace = true
5957
sqlx = { workspace = true, features = ["runtime-tokio", "chrono"], optional = true }
6058
subtle = { workspace = true, features = ["std"] }
6159
swagger-ui-redist = { workspace = true, optional = true }

cot/src/auth.rs

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -180,16 +180,12 @@ pub trait User {
180180
/// use cot::auth::{SessionAuthHash, User, UserId};
181181
/// use cot::common_types::Password;
182182
/// use cot::config::SecretKey;
183-
/// use hmac::{Hmac, Mac};
184-
/// use sha2::Sha512;
185183
///
186184
/// struct MyUser {
187185
/// id: i64,
188186
/// password: Password,
189187
/// }
190188
///
191-
/// type SessionAuthHmac = Hmac<Sha512>;
192-
///
193189
/// impl User for MyUser {
194190
/// fn id(&self) -> Option<UserId> {
195191
/// Some(UserId::Int(self.id))
@@ -211,12 +207,12 @@ pub trait User {
211207
/// // thanks to this, the session hash is invalidated when the user changes their password
212208
/// // and the user is automatically logged out
213209
///
214-
/// let mut mac = SessionAuthHmac::new_from_slice(secret_key.as_bytes())
215-
/// .expect("HMAC can take key of any size");
216-
/// mac.update(self.password.as_str().as_bytes());
217-
/// let hmac_data = mac.finalize().into_bytes();
210+
/// const SESSION_AUTH_HASH_CONTEXT: &'static str = "cot.rs session auth hash v1";
211+
///
212+
/// let key = blake3::derive_key(SESSION_AUTH_HASH_CONTEXT, secret_key.as_bytes());
213+
/// let hash = blake3::keyed_hash(&key, self.password.as_str().as_bytes());
218214
///
219-
/// Some(SessionAuthHash::new(&hmac_data))
215+
/// Some(SessionAuthHash::new(&hash.as_slice()))
220216
/// }
221217
/// }
222218
/// ```
@@ -350,16 +346,12 @@ impl User for AnonymousUser {}
350346
/// use cot::auth::{SessionAuthHash, User, UserId};
351347
/// use cot::common_types::Password;
352348
/// use cot::config::SecretKey;
353-
/// use hmac::{Hmac, Mac};
354-
/// use sha2::Sha512;
355349
///
356350
/// struct MyUser {
357351
/// id: i64,
358352
/// password: Password,
359353
/// }
360354
///
361-
/// type SessionAuthHmac = Hmac<Sha512>;
362-
///
363355
/// impl User for MyUser {
364356
/// fn id(&self) -> Option<UserId> {
365357
/// Some(UserId::Int(self.id))
@@ -381,12 +373,12 @@ impl User for AnonymousUser {}
381373
/// // thanks to this, the session hash is invalidated when the user changes their password
382374
/// // and the user is automatically logged out
383375
///
384-
/// let mut mac = SessionAuthHmac::new_from_slice(secret_key.as_bytes())
385-
/// .expect("HMAC can take key of any size");
386-
/// mac.update(self.password.as_str().as_bytes());
387-
/// let hmac_data = mac.finalize().into_bytes();
376+
/// const SESSION_AUTH_HASH_CONTEXT: &'static str = "cot.rs session auth hash v1";
377+
///
378+
/// let key = blake3::derive_key(SESSION_AUTH_HASH_CONTEXT, secret_key.as_bytes());
379+
/// let hash = blake3::keyed_hash(&key, self.password.as_str().as_bytes());
388380
///
389-
/// Some(SessionAuthHash::new(&hmac_data))
381+
/// Some(SessionAuthHash::new(&hash.as_slice()))
390382
/// }
391383
/// }
392384
/// ```

cot/src/auth/db.rs

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@ use async_trait::async_trait;
1212
// can figure out it's an autogenerated field
1313
use cot::db::Auto;
1414
use cot_macros::AdminModel;
15-
use hmac::{Hmac, Mac};
16-
use sha2::Sha512;
1715
use thiserror::Error;
1816

1917
use crate::App;
@@ -345,8 +343,6 @@ impl DatabaseUser {
345343
}
346344
}
347345

348-
type SessionAuthHmac = Hmac<Sha512>;
349-
350346
impl User for DatabaseUser {
351347
fn id(&self) -> Option<UserId> {
352348
Some(UserId::Int(self.id()))
@@ -365,12 +361,12 @@ impl User for DatabaseUser {
365361
}
366362

367363
fn session_auth_hash(&self, secret_key: &SecretKey) -> Option<SessionAuthHash> {
368-
let mut mac = SessionAuthHmac::new_from_slice(secret_key.as_bytes())
369-
.expect("HMAC can take key of any size");
370-
mac.update(self.password.as_str().as_bytes());
371-
let hmac_data = mac.finalize().into_bytes();
364+
const SESSION_AUTH_HASH_CONTEXT: &str = "cot.rs session auth hash v1";
365+
366+
let key = blake3::derive_key(SESSION_AUTH_HASH_CONTEXT, secret_key.as_bytes());
367+
let hash = blake3::keyed_hash(&key, self.password.as_str().as_bytes());
372368

373-
Some(SessionAuthHash::new(&hmac_data))
369+
Some(SessionAuthHash::new(hash.as_slice()))
374370
}
375371
}
376372

cot/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ pub(crate) mod utils;
8484

8585
#[cfg(feature = "openapi")]
8686
pub use aide;
87+
pub use bytes;
8788
/// A wrapper around a handler that's used in [`Bootstrapper`].
8889
///
8990
/// It is returned by [`Bootstrapper::finish`]. Typically, you don't need to
@@ -181,9 +182,9 @@ pub use cot_macros::e2e_test;
181182
/// ```
182183
pub use cot_macros::main;
183184
pub use cot_macros::test;
185+
pub use http;
184186
#[cfg(feature = "openapi")]
185187
pub use schemars;
186-
pub use {bytes, http};
187188

188189
pub use crate::__private::askama::{Template, filter_fn};
189190
pub use crate::project::{

cot/src/static_files.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ use std::time::Duration;
1313

1414
use bytes::Bytes;
1515
use cot_core::error::impl_into_cot_error;
16-
use digest::Digest;
1716
use futures_core::ready;
1817
use http::{Request, header};
1918
use pin_project_lite::pin_project;
@@ -128,7 +127,7 @@ impl StaticFiles {
128127

129128
#[must_use]
130129
fn file_hash(file: &StaticFile) -> String {
131-
hex::encode(&sha2::Sha256::digest(&file.content).as_slice()[0..6])
130+
hex::encode(&blake3::hash(&file.content).as_slice()[0..6])
132131
}
133132

134133
#[must_use]

deny.toml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,14 @@ all-features = true
1414
# See https://spdx.org/licenses/ for list of possible licenses
1515
# [possible values: any SPDX 3.11 short identifier (+ optional exception)].
1616
allow = [
17-
"MIT",
18-
"Apache-2.0",
17+
"0BSD",
1918
"Apache-2.0 WITH LLVM-exception",
19+
"Apache-2.0",
20+
"BSD-2-Clause",
21+
"BSD-3-Clause",
2022
"CDLA-Permissive-2.0",
2123
"ISC",
24+
"MIT",
2225
"Unicode-3.0",
23-
"0BSD",
24-
"BSD-3-Clause",
2526
"Zlib",
2627
]

0 commit comments

Comments
 (0)