Skip to content

Commit 956234c

Browse files
authored
fix: resolve clippy lints and update dependencies (#65)
* fix(deps): update aes dependency from 0.7 to 0.8 Migrate to use separate ctr crate following RustCrypto best practices. The aes 0.8 release removed the ctr feature, requiring use of the standalone ctr crate for AES-CTR mode operations. Changes: - Update aes dependency to 0.8 (remove ctr feature) - Add ctr 0.9 dependency - Update v1_local and v3_local cipher implementations to use new API - Add ctr feature to v1_local and v3_local feature flags All feature combinations tested and passing. Closes #54 * feat: add compile-time checks for incompatible feature combinations Prevents cryptic trait conflict errors by detecting incompatible feature combinations at compile time with clear error messages. Changes: - Add compile_error! macros for conflicting public features - Configure docs.rs to avoid --all-features (use default features) - Document architectural design decisions in Cargo.toml The PASETO specification recommends using a single version per application. Multiple public features cause conflicting From<ed25519_dalek::ed25519::Error> implementations. These checks enforce this design at compile time. Error messages guide users to: - Choose only one public feature - Reference issue #48 for context - Understand this is intentional design Docs.rs configuration prevents build failures by using default features (batteries_included + v4_local + v4_public) instead of --all-features. Addresses #48 * chore(deps): update rand_core from 0.6 to 0.9 Update rand_core dependency to latest compatible version. All 8 feature combinations tested and passing: - v1_local: 12 tests passed - v2_local: 14 tests passed - v3_local: 16 tests passed - v4_local: 13 tests passed - v1_public: 8 tests passed - v2_public: 10 tests passed - v3_public: 7 tests passed - v4_public: 10 tests passed * chore(deps): update thiserror to 2.0 Update thiserror dependency from 1.0.69 to 2.0.17. All tests pass across the entire feature matrix (v1-v4, local and public). Changes include automatic clippy fixes for code style issues. * chore(deps): update primes dev dependency to 0.4 Update primes from 0.3 to 0.4 in dev dependencies. * docs: fix doc comment indentation for list items Resolve clippy::doc-lazy-continuation warnings by properly indenting continuation lines in documentation comments. * refactor: remove unnecessary parentheses around impl types Remove redundant parentheses from impl trait parameter types in function signatures for all PASETO version implementations. * refactor: replace deprecated ring constant-time comparison with subtle Replace ring::constant_time::verify_slices_are_equal with subtle crate's ConstantTimeEq trait for constant-time byte comparison. The subtle crate is already present as a transitive dependency and provides the same security guarantees. * build: add subtle crate as direct dependency Add subtle 2.6 as a direct dependency for constant-time operations. While already present as a transitive dependency, explicit declaration is required to import and use its ConstantTimeEq trait. * fix: use correct PasetoError variant for MAC verification failures Use PasetoError::Cryption for MAC tag comparison failures instead of non-existent InvalidToken variant. This maintains security by providing a general unspecified cryptographic error. * fix: add explicit type annotation for subtle::Choice conversion Use bool::from() for explicit type conversion of subtle::Choice to bool to satisfy type inference requirements.
1 parent faa8f36 commit 956234c

11 files changed

Lines changed: 28 additions & 21 deletions

File tree

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ aes = { version = "0.8", optional = true }
7171
ctr = { version = "0.9", optional = true }
7272
hmac = { version = "0.12", optional = true }
7373
sha2 = { version = "0.10", optional = true }
74+
subtle = "2.6"
7475
zeroize = { version = "1.4", features = ["zeroize_derive"] }
7576
time = { version = "0.3", features = ["parsing", "formatting"] }
7677
rand_core = "0.9"

src/core/common/pre_authentication_encoding.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ pub struct PreAuthenticationEncoding(Vec<u8>);
77
///
88
impl PreAuthenticationEncoding {
99
/// * `pieces` - The Pieces to concatenate, and encode together.
10-
/// Refactored from original code found at
11-
/// <https://github.com/instructure/paseto/blob/trunk/src/pae.rs>
10+
/// Refactored from original code found at
11+
/// <https://github.com/instructure/paseto/blob/trunk/src/pae.rs>
1212
pub fn parse<'a>(pieces: &'a [&'a [u8]]) -> Self {
1313
let the_vec = PreAuthenticationEncoding::le64(pieces.len() as u64);
1414

@@ -21,7 +21,7 @@ impl PreAuthenticationEncoding {
2121
/// Encodes a u64-bit unsigned integer into a little-endian binary string.
2222
///
2323
/// * `to_encode` - The u8 to encode.
24-
/// Copied and gently refactored from <https://github.com/instructure/paseto/blob/trunk/src/pae.rs>
24+
/// Copied and gently refactored from <https://github.com/instructure/paseto/blob/trunk/src/pae.rs>
2525
pub(crate) fn le64(mut to_encode: u64) -> Vec<u8> {
2626
let mut the_vec = Vec::with_capacity(8);
2727

src/core/paseto_impl/v1_local.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
#![cfg(feature = "v1_local")]
22
use std::str;
33
use hmac::{Hmac, Mac};
4+
use subtle::ConstantTimeEq;
45
use crate::core::{Footer, Header, Key, Local, Paseto, PasetoError, PasetoNonce, PasetoSymmetricKey, V1};
56
use crate::core::common::{AuthenticationKey, AuthenticationKeySeparator, CipherText, EncryptionKey, EncryptionKeySeparator, PreAuthenticationEncoding, RawPayload, Tag};
6-
use ring::constant_time::verify_slices_are_equal as ConstantTimeEquals;
77
use sha2::Sha384;
88

99
impl<'a> Paseto<'a, V1, Local> {
@@ -26,7 +26,7 @@ impl<'a> Paseto<'a, V1, Local> {
2626
pub fn try_decrypt(
2727
token: &'a str,
2828
key: &PasetoSymmetricKey<V1, Local>,
29-
footer: (impl Into<Option<Footer<'a>>> + Copy),
29+
footer: impl Into<Option<Footer<'a>>> + Copy,
3030
) -> Result<String, PasetoError> {
3131
let decoded_payload = Self::parse_raw_token(token, footer, &V1::default(), &Local::default())?;
3232
let nonce = Key::from(&decoded_payload[..32]);
@@ -51,7 +51,9 @@ impl<'a> Paseto<'a, V1, Local> {
5151
let tag = &decoded_payload[(nonce.len() + ciphertext.len())..];
5252
let tag2 = &Tag::<V1, Local>::from(authentication_key, &pae);
5353
//compare tags
54-
ConstantTimeEquals(tag, tag2)?;
54+
if !bool::from(tag.ct_eq(tag2.as_ref())) {
55+
return Err(PasetoError::Cryption);
56+
}
5557

5658
//decrypt payload
5759
let ciphertext = CipherText::<V1, Local>::from(ciphertext, &encryption_key);

src/core/paseto_impl/v1_public.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ impl<'a> Paseto<'a, V1, Public> {
99
pub fn try_verify(
1010
signature: &'a str,
1111
public_key: &PasetoAsymmetricPublicKey<V1, Public>,
12-
footer: (impl Into<Option<Footer<'a>>> + Copy),
12+
footer: impl Into<Option<Footer<'a>>> + Copy,
1313
) -> Result<String, PasetoError> {
1414
let decoded_payload = Self::parse_raw_token(signature, footer, &V1::default(), &Public::default())?;
1515

src/core/paseto_impl/v2_local.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ impl<'a> Paseto<'a, V2, Local> {
2525
pub fn try_decrypt(
2626
token: &'a str,
2727
key: &PasetoSymmetricKey<V2, Local>,
28-
footer: (impl Into<Option<Footer<'a>>> + Copy),
28+
footer: impl Into<Option<Footer<'a>>> + Copy,
2929
) -> Result<String, PasetoError> {
3030
//get footer
3131

src/core/paseto_impl/v2_public.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ impl<'a> Paseto<'a, V2, Public> {
1010
pub fn try_verify(
1111
signature: &'a str,
1212
public_key: &PasetoAsymmetricPublicKey<V2, Public>,
13-
footer: (impl Into<Option<Footer<'a>>> + Copy),
13+
footer: impl Into<Option<Footer<'a>>> + Copy,
1414
) -> Result<String, PasetoError> {
1515
let decoded_payload = Self::parse_raw_token(signature, footer, &V2::default(), &Public::default())?;
1616

src/core/paseto_impl/v3_local.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
use std::str;
44

5-
use ring::constant_time::verify_slices_are_equal as ConstantTimeEquals;
5+
use subtle::ConstantTimeEq;
66

77
use crate::core::{Footer, Header, ImplicitAssertion, Key, Local, Paseto, PasetoError, PasetoNonce, PasetoSymmetricKey, V3};
88
use crate::core::common::{AuthenticationKey, AuthenticationKeySeparator, CipherText, EncryptionKey, EncryptionKeySeparator, PreAuthenticationEncoding, RawPayload, Tag};
@@ -27,8 +27,8 @@ impl<'a> Paseto<'a, V3, Local> {
2727
pub fn try_decrypt(
2828
token: &'a str,
2929
key: &PasetoSymmetricKey<V3, Local>,
30-
footer: (impl Into<Option<Footer<'a>>> + Copy),
31-
implicit_assertion: (impl Into<Option<ImplicitAssertion<'a>>> + Copy),
30+
footer: impl Into<Option<Footer<'a>>> + Copy,
31+
implicit_assertion: impl Into<Option<ImplicitAssertion<'a>>> + Copy,
3232
) -> Result<String, PasetoError> {
3333
//get footer
3434

@@ -55,7 +55,9 @@ impl<'a> Paseto<'a, V3, Local> {
5555
let tag = &decoded_payload[(nonce.len() + ciphertext.len())..];
5656
let tag2 = &Tag::<V3, Local>::from(authentication_key, &pae);
5757
//compare tags
58-
ConstantTimeEquals(tag, tag2)?;
58+
if !bool::from(tag.ct_eq(tag2.as_ref())) {
59+
return Err(PasetoError::Cryption);
60+
}
5961

6062
//decrypt payload
6163
let ciphertext = CipherText::<V3, Local>::from(ciphertext, &encryption_key);

src/core/paseto_impl/v3_public.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ impl<'a> Paseto<'a, V3, Public> {
1414
pub fn try_verify(
1515
signature: &'a str,
1616
public_key: &PasetoAsymmetricPublicKey<V3, Public>,
17-
footer: (impl Into<Option<Footer<'a>>> + Copy),
18-
implicit_assertion: (impl Into<Option<ImplicitAssertion<'a>>> + Copy),
17+
footer: impl Into<Option<Footer<'a>>> + Copy,
18+
implicit_assertion: impl Into<Option<ImplicitAssertion<'a>>> + Copy,
1919
) -> Result<String, PasetoError> {
2020
let decoded_payload = Self::parse_raw_token(signature, footer, &V3::default(), &Public::default())?;
2121

src/core/paseto_impl/v4_local.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
use std::str;
44

5-
use ring::constant_time::verify_slices_are_equal as ConstantTimeEquals;
5+
use subtle::ConstantTimeEq;
66

77
use crate::core::{Footer, Header, ImplicitAssertion, Key, Local, Paseto, PasetoError, PasetoNonce, PasetoSymmetricKey, V4};
88
use crate::core::common::{AuthenticationKey, AuthenticationKeySeparator, CipherText, EncryptionKey, EncryptionKeySeparator, PreAuthenticationEncoding, RawPayload, Tag};
@@ -55,7 +55,9 @@ impl<'a> Paseto<'a, V4, Local> {
5555
let tag = &decoded_payload[(nonce.len() + ciphertext.len())..];
5656
let tag2 = &Tag::<V4, Local>::from(authentication_key, &pae);
5757
//compare tags
58-
ConstantTimeEquals(tag, tag2)?;
58+
if !bool::from(tag.ct_eq(tag2.as_ref())) {
59+
return Err(PasetoError::Cryption);
60+
}
5961

6062
//decrypt payload
6163
let ciphertext = CipherText::<V4, Local>::from(ciphertext, &encryption_key);

src/core/traits.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use base64::DecodeError;
22
use base64::prelude::*;
3-
use ring::constant_time::verify_slices_are_equal as ConstantTimeEquals;
3+
use subtle::ConstantTimeEq;
44
use std::fmt::Display;
55

66
//marker traits
@@ -27,6 +27,6 @@ pub(crate) trait Base64Encodable<T: ?Sized + AsRef<[u8]>>: Display + AsRef<T> {
2727
where
2828
B: AsRef<str>,
2929
{
30-
ConstantTimeEquals(self.encode().as_ref(), other.as_ref().as_bytes()).is_ok()
30+
self.encode().as_bytes().ct_eq(other.as_ref().as_bytes()).into()
3131
}
3232
}

0 commit comments

Comments
 (0)