#jwt #security-key #security #token #auth-token #quic

bitwark

Empowering secure digital interactions with robust binary token management and dynamic rolling keys

14 stable releases

2.0.1 Oct 29, 2024
2.0.0 Oct 28, 2024
1.2.3 Aug 4, 2024
1.2.2 Mar 8, 2024
1.0.5 Oct 17, 2023

#188 in Cryptography

Download history 126/week @ 2024-08-03 8/week @ 2024-08-10 22/week @ 2024-09-21 4/week @ 2024-09-28 1/week @ 2024-10-05 264/week @ 2024-10-26 49/week @ 2024-11-02

313 downloads per month

MIT/Apache

73KB
1K SLoC

Bitwark   Build Status Latest Version bitwark: rustc 1.66+

Provides robust security for Rust applications through compact binary tokens and automated cryptographic defenses.


πŸš€ Introduction

Bitwark is your go-to library for enhancing security in Rust applications. It offers a streamlined, bandwidth-friendly version of JSON Web Tokens (JWTs) and includes features like automatic key rotation and data salting to bolster your app's defenses.

πŸ” Key Features:

  • Compact Tokens: Uses binary format for signed payloads, saving space compared to traditional JWTs.
  • Advanced Encryption: Employs EdDSA with Blake3 for robust signing and verification out of the box.
  • Dynamic Key Rotation: Simplifies the process to update keys and salts, keeping your security measures up-to-date.
  • Enhanced Security with Salting: Adds random data to payloads, making it tougher for attackers to crack.
  • Performance Optimized: Designed to be lightweight, ensuring your applications run smoothly under pressure.

πŸ› οΈ Getting Started

Explore the secure features of Bitwark for your Rust applications:

All-in-One Example (Alternative to JWT)

Imagine you have a structure you wish to sign and send back to the user:

#[derive(Serialize, Deserialize, Clone)]
pub struct Token {
    pub user_id: u32,
    pub permissions: Vec<String>,
}

First, generate a key that expires after 10 minutes, though you can set it for days, months, or years as needed. For a non-expiring key, simply use EdDsaKey::generate():

let exp_key = AutoExpiring::<EdDsaKey>::generate(
    Duration::minutes(10)
).unwrap();

Next, create the token. SaltyExpiringSigned adds a default 64-byte salt and includes an expiration time:

let token_object = Token { user_id: 123, permissions: vec!["Read".to_string(), "Write".to_string()] };

let token = SaltyExpiringSigned::<Token>::new(
    chrono::Duration::minutes(10),
    token_object
).unwrap();

Finally, prepare the token for the client. You can return it as bytes or convert it to base64:

let token_bytes: Vec<u8> = token.encode_and_sign(&*exp_key).unwrap();

When the user provides this token to your service, verifying it is straightforward:

let token = SaltyExpiringSigned::<Token>::decode_and_verify(&token_bytes, &*exp_key).unwrap();

if token.permissions.contains(&String::from("Read")) {
    // Proceed with the user's request
}

More Comprehensive Examples Follow

Signed Payload decoded as binary (alternative to JWT)

use bitwark::{
    exp::AutoExpiring,
    signed_exp::ExpiringSigned,
    salt::Salt64,
    keys::{ed::EdDsaKey},
};
use serde::{Serialize, Deserialize};
use chrono::Duration;

#[derive(Serialize, Deserialize)]
pub struct Claims {
    pub permissions: Vec<String>,
}

// Generate an EdDSA key pair and salt with a validity period
let exp_key = AutoExpiring::<EdDsaKey>::generate(
    Duration::minutes(10)
).unwrap();

let exp_salt = AutoExpiring::<Salt64>::generate(
    Duration::minutes(5)
).unwrap();

// Instantiate a token with specified claims.
let claims = Claims { 
    permissions: vec![
        "users:read".to_string(), 
        "users:write".to_string()
    ],
};

let token = ExpiringSigned::<Claims>::new(
    Duration::seconds(120), claims
).unwrap();

// Create a binary encoding of the token, signed with key and salt.
let signed_token_bytes = token.encode_and_sign_salted(
    &exp_salt, &*exp_key
).expect("Failed to sign token");

// Decode the token and verify its signature and validity.
let decoded_token = ExpiringSigned::<Claims>::decode_and_verify_salted(
    &signed_token_bytes, &exp_salt, &*exp_key
).expect("Failed to decode a token");

assert_eq!(
    2, 
    decoded_token.permissions.len(), 
    "Failed to find 2 permissions"
);

Key Rotation

use bitwark::{payload::SignedPayload, keys::ed::EdDsaKey, keys::CryptoKey, Generator};
use chrono::Duration;

// creating a key
let key = EdDsaKey::generate()?;

// Rotating key
let mut expiring_key = Expiring<EdDsaKey>::new(Duration::seconds(10), key);
if expiring_key.has_expired() {
    expiring_key.roll()?;
}

// Creating a payload
let payload = SignedPayload::<String>::new("A signed message".to_string());

// Encode the payload with signature based on the expiring key
let signed_payload_bytes = payload.encode_and_sign(&expiring_key)?;

// Decode the signed payload with verifying signature with payload's integrity
let decoded_payload = SignedPayload::<String>::decode_and_verify(&signed_payload_bytes, &expiring_key)?;
assert_eq!(*decoded_payload, *payload);

Salt Example

use bitwark::{
    salt::Salt64, 
    exp::AutoExpiring, 
    key::ed::EdDsaKey, 
    Rotation, Generator
};
use bitwark::payload::SignedPayload;
use chrono::Duration;

// Make a new salt.
let salt = Salt64::generate().unwrap();

// Make a salt that lasts for 10 seconds.
let mut expiring_salt = AutoExpiring::<Salt64>::new(
    Duration::seconds(10), salt
).unwrap();

// Change the salt if it's too old.
if expiring_salt.has_expired() {
    expiring_salt
        .rotate()
        .expect("Salt rotation failed.");
}

// Make a key that lasts for 120 seconds.
let key = AutoExpiring::<EdDsaKey>::generate(
    Duration::seconds(120)
).unwrap();

// Make a payload for signing
let payload = SignedPayload::<String>::new(
    "Hello, world!".to_string()
);

// Combine message and signature into one piece.
let signature_bytes = payload.encode_and_sign_salted(
    &expiring_salt, &*key
).expect("Failed to encode");

// Separate message and signature, verifying validity.
let decoded_result = 
    SignedPayload::<String>::decode_and_verify_salted(
        &signature_bytes, &expiring_salt, &*key
    );

assert!(decoded_result.is_ok());

πŸ’‘ Motivation

In today's digital landscape, security must not come at the expense of performance. Bitwark addresses this challenge by:

  • Providing lightweight, bandwidth-efficient tokens for data exchange.
  • Offering robust security features like automatic key rotation and salting to adapt to evolving threats.

🌱 Contribution

Be a Part of Bitwark’s Journey!

We believe in the power of community, and Bitwark thrives on contributions from developers like you:

  • Propose Ideas: Found a bug or have an idea? Open an Issue!
  • Code Contributions: Enhance Bitwark by submitting Pull Requests with your code.
  • Documentation: Help us keep our documentation clear and helpful.
  • Engage: Participate in community discussions to shape Bitwark's future.

πŸ“œ License

Bitwark is licensed under the MIT License or Apache-2.0 to ensure it remains accessible for all developers.

Dependencies

~11–19MB
~386K SLoC