Skip to content

Commit

Permalink
Add initial implementation.
Browse files Browse the repository at this point in the history
  • Loading branch information
return committed Nov 23, 2018
1 parent 06b521c commit d082515
Show file tree
Hide file tree
Showing 6 changed files with 196 additions and 2 deletions.
4 changes: 4 additions & 0 deletions .gitignore
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,7 @@ Cargo.lock

# These are backup files generated by rustfmt
**/*.rs.bk

/target
**/*.rs.bk
Cargo.lock
25 changes: 25 additions & 0 deletions Cargo.toml
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"
Empty file modified LICENSE
100644 → 100755
Empty file.
4 changes: 2 additions & 2 deletions README.md
100644 → 100755
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.
122 changes: 122 additions & 0 deletions src/lib.rs
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());
}
43 changes: 43 additions & 0 deletions test/main.rs
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");
}
}

0 comments on commit d082515

Please sign in to comment.