-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
196 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,3 +8,7 @@ Cargo.lock | |
|
||
# These are backup files generated by rustfmt | ||
**/*.rs.bk | ||
|
||
/target | ||
**/*.rs.bk | ||
Cargo.lock |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
[package] | ||
name = "branca" | ||
description = "A Rust implementation of branca, a JWT alternative." | ||
version = "0.1.0" | ||
authors = ["return"] | ||
keywords = ["fernet", "branca", "crypto", "jwt"] | ||
categories = ["cryptography"] | ||
readme = "README.md" | ||
license = "MIT" | ||
documentation = "https://docs.rs/branca" | ||
|
||
[dependencies] | ||
|
||
base-x = "0.2.3" | ||
byteorder = "1.2.7" | ||
chrono = { version = "0.4.6", features = ["serde"] } | ||
hex = "0.3.2" | ||
# Will change this to point a sodiumoxide release that has crypto_aead_xchacha20poly1305_ietf_* functions. | ||
# In the meantime, use a local version instead. | ||
sodiumoxide = { version = "0.1.0"} | ||
serde = "^1" | ||
|
||
[[example]] | ||
name = "example" | ||
path = "test/main.rs" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
# branca-rs | ||
A Rust implementation of the branca specification | ||
# branca | ||
A Rust implementation of the branca specification. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
extern crate sodiumoxide; | ||
extern crate serde; | ||
extern crate byteorder; | ||
extern crate chrono; | ||
extern crate base_x; | ||
|
||
use byteorder::*; | ||
use chrono::prelude::*; | ||
use base_x::*; | ||
|
||
use sodiumoxide::randombytes::*; | ||
use sodiumoxide::crypto::aead::xchacha20poly1305_ietf; | ||
use std::io::*; | ||
use std::io::Read; | ||
|
||
// Branca magic byte | ||
const VERSION: u8 = 0xBA; | ||
// Branca nonce bytes | ||
const NONCE_BYTES: usize = 24; | ||
// Base 62 alphabet | ||
const BASE62: &'static str = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; | ||
|
||
// Branca builder | ||
#[derive(Clone, PartialEq, Debug)] | ||
pub struct Branca { | ||
key: Option<Vec<u8>>, | ||
nonce: Option<Vec<u8>>, | ||
message:Option<String>, | ||
ttl: Option<u32>, | ||
timestamp: Option<u32>, | ||
} | ||
|
||
impl Branca { | ||
pub fn new () -> Branca { | ||
Branca { | ||
key: None, | ||
nonce: None, | ||
message: None, | ||
ttl: None, | ||
timestamp: None | ||
} | ||
} | ||
|
||
pub fn set_key(mut self, key: Vec<u8>) -> Self { | ||
self.key = Some(key); | ||
self | ||
} | ||
|
||
pub fn set_nonce(mut self, nonce:Vec<u8> ) -> Self { | ||
self.nonce = Some(nonce); | ||
self | ||
} | ||
|
||
pub fn set_message(mut self, message:String) -> Self { | ||
self.message = Some(message); | ||
self | ||
} | ||
|
||
pub fn set_ttl(mut self, ttl: u32) -> Self { | ||
self.ttl = Some(ttl); | ||
self | ||
} | ||
|
||
pub fn set_timestamp(mut self, timestamp: u32) -> Self { | ||
self.timestamp = Some(timestamp); | ||
self | ||
} | ||
|
||
pub fn build(self) -> Result<String> { | ||
let key = self.key.unwrap(); | ||
let nonce = self.nonce.unwrap(); | ||
let message = self.message.unwrap(); | ||
let ttl = self.ttl.unwrap(); | ||
let timestamp = self.timestamp.unwrap(); | ||
let crypted = encode(message, key, nonce, timestamp); | ||
return Ok(crypted.unwrap()); | ||
} | ||
} | ||
|
||
pub fn encode(msg: String, key: Vec<u8>, nonce: Vec<u8>, timestamp: u32) -> Result<String> { | ||
|
||
sodiumoxide::init(); | ||
|
||
let k = xchacha20poly1305_ietf::Key::from_slice(key.as_slice()).unwrap(); | ||
|
||
let mut nonce_n: [u8; 24] = Default::default(); | ||
nonce_n.copy_from_slice(nonce.as_slice()); | ||
let nonce_b = xchacha20poly1305_ietf::Nonce(nonce_n); | ||
|
||
let timestamp: u32 = timestamp; | ||
|
||
let mut time_bytes = vec![0x0; 4]; | ||
BigEndian::write_u32(&mut time_bytes, timestamp); | ||
time_bytes.append(&mut Vec::from(nonce)); | ||
|
||
let mut version_header = vec![VERSION]; | ||
version_header.append(&mut time_bytes); | ||
|
||
let mut crypted = xchacha20poly1305_ietf::seal(msg.as_bytes(), Some(version_header.as_slice()), &nonce_b, &k); | ||
|
||
version_header.append(&mut crypted); | ||
|
||
let b62_enc = base_x::encode(BASE62, &mut version_header.as_slice()); | ||
|
||
return Ok(b62_enc.to_string()); | ||
} | ||
|
||
pub fn decode(data: String, key: String) -> Result<String> { | ||
let g_data = base_x::decode(BASE62, &data).unwrap(); | ||
let k = xchacha20poly1305_ietf::Key::from_slice(key.as_bytes()).unwrap(); | ||
|
||
let header = &g_data[0..29]; | ||
let ciphertext = &g_data[29..]; | ||
|
||
let mut nonce_n: [u8; 24] = Default::default(); | ||
nonce_n.copy_from_slice(&header[5..]); | ||
let nonce_b = xchacha20poly1305_ietf::Nonce(nonce_n); | ||
|
||
let decode = xchacha20poly1305_ietf::open(ciphertext, Some(header), &nonce_b, &k).unwrap(); | ||
|
||
return Ok(String::from_utf8(decode).unwrap()); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
extern crate branca; | ||
|
||
use branca::{Branca, encode, decode,}; | ||
|
||
fn main(){ | ||
} | ||
|
||
#[cfg(test)] | ||
mod branca_unit_tests { | ||
|
||
use super::*; | ||
use branca::{Branca, encode, decode}; | ||
|
||
#[test] | ||
pub fn test_encode() { | ||
let keygen = String::from("supersecretkeyyoushouldnotcommit").into_bytes(); | ||
let message = String::from("Hello world!"); | ||
let nonce = [0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c].to_vec(); | ||
let timestamp = 123206400; | ||
let branca_token = encode(message,keygen,nonce,timestamp).unwrap(); | ||
assert_eq!(branca_token, "875GH233T7IYrxtgXxlQBYiFobZMQdHAT51vChKsAIYCFxZtL1evV54vYqLyZtQ0ekPHt8kJHQp0a"); | ||
} | ||
|
||
#[test] | ||
pub fn test_decode() { | ||
let ciphertext = String::from("875GH233T7IYrxtgXxlQBYiFobZMQdHAT51vChKsAIYCFxZtL1evV54vYqLyZtQ0ekPHt8kJHQp0a"); | ||
let keygen = String::from("supersecretkeyyoushouldnotcommit"); | ||
assert_eq!(decode(ciphertext, keygen).unwrap(), "Hello world!"); | ||
} | ||
|
||
#[test] | ||
pub fn test_encode_builder() { | ||
let token = Branca::new() | ||
.set_key(String::from("supersecretkeyyoushouldnotcommit").into_bytes()) | ||
.set_message(String::from("Hello world!")) | ||
.set_nonce([0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c].to_vec()) | ||
.set_timestamp(123206400) | ||
.set_ttl(3600) | ||
.build(); | ||
|
||
assert_eq!(token.unwrap(), "875GH233T7IYrxtgXxlQBYiFobZMQdHAT51vChKsAIYCFxZtL1evV54vYqLyZtQ0ekPHt8kJHQp0a"); | ||
} | ||
} |