Skip to content

Commit

Permalink
Genesis Commit
Browse files Browse the repository at this point in the history
  • Loading branch information
NishantJoshi00 committed Oct 19, 2023
0 parents commit 69979a0
Show file tree
Hide file tree
Showing 10 changed files with 272 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/target
/Cargo.lock
33 changes: 33 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
[package]
name = "tartarus"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
# Tokio Dependencies
tokio = { version = "1.33.0", features = ["macros", "rt-multi-thread"] }
axum = "0.6.20"
hyper = "0.14.27"
tower = "0.4.13"

bb8 = "0.8.1"
diesel = "2.1.3"
diesel-async = { version = "0.4.1", features = ["postgres", "bb8"] }

serde = { version = "1.0.189", features = ["derive"] }
serde_json = "1.0.107"
josekit = "0.8.4"

thiserror = "1.0.49"
error-stack = "0.4.1"
futures-util = "0.3.28"






[[bin]]
name = "locker"
32 changes: 32 additions & 0 deletions src/app.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use axum::routing;
use hyper::server::conn;

use crate::{config, db, error};

#[derive(Clone)]
struct AppState {
db: db::Pool,
}

pub fn application_builder<I, S, State>(
config: config::Config,
) -> Result<
hyper::Server<conn::AddrIncoming, routing::IntoMakeService<axum::Router>>,
error::ConfigurationError,
>
where
{
let socket_addr =
std::net::SocketAddr::new(config.server.host.parse()?, config.server.port);

let router = axum::Router::new().with_state(AppState::new(config));

let server = axum::Server::try_bind(&socket_addr)?.serve(router.into_make_service());
Ok(server)
}

impl AppState {
fn new(config: config::Config) -> Self {
todo!()
}
}
5 changes: 5 additions & 0 deletions src/bin/locker.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

#[tokio::main]
async fn main() {

}
12 changes: 12 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@


#[derive(Clone)]
pub struct Config {
pub server: Server
}

#[derive(Clone)]
pub struct Server {
pub host: String,
pub port: u16
}
11 changes: 11 additions & 0 deletions src/crypto.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use axum::{response::IntoResponse, body::BoxBody};

pub trait Encryption<I, O: serde::Serialize + serde::de::DeserializeOwned> {
type Key;
type Error;
fn encrypt(input: I, key: Self::Key) -> Result<O, Self::Error>;
fn decrypt(input: O, key: Self::Key) -> Result<I, Self::Error>;
}

pub mod jw;

148 changes: 148 additions & 0 deletions src/crypto/jw.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
use crate::error;
use josekit::{jwe, jws};

pub struct JWEncryption;

pub struct LockerKey {
private_key: String,
public_key: String,
}

#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct JwsBody {
pub header: String,
pub payload: String,
pub signature: String,
}

impl JwsBody {
fn from_str(input: &str) -> Option<Self> {
let mut data = input.split('.');
let header = data.next()?.to_string();
let payload = data.next()?.to_string();
let signature = data.next()?.to_string();
Some(Self {
header,
payload,
signature,
})
}

pub fn get_dotted_jws(self) -> String {
let header = self.header;
let payload = self.payload;
let signature = self.signature;
format!("{header}.{payload}.{signature}")
}
}

#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct JweBody {
pub header: String,
pub iv: String,
pub encrypted_payload: String,
pub tag: String,
pub encrypted_key: String,
}

impl JweBody {
fn from_str(input: &str) -> Option<Self> {
let mut data = input.split('.');
let header = data.next()?.to_string();
let encrypted_key = data.next()?.to_string();
let iv = data.next()?.to_string();
let encrypted_payload = data.next()?.to_string();
let tag = data.next()?.to_string();
Some(Self {
header,
iv,
encrypted_payload,
tag,
encrypted_key,
})
}

pub fn get_dotted_jwe(self) -> String {
let header = self.header;
let encryption_key = self.encrypted_key;
let iv = self.iv;
let encryption_payload = self.encrypted_payload;
let tag = self.tag;
format!("{header}.{encryption_key}.{iv}.{encryption_payload}.{tag}")
}
}

impl super::Encryption<Vec<u8>, Vec<u8>> for JWEncryption {
type Key = LockerKey;

type Error = error::CryptoError;

fn encrypt(input: Vec<u8>, key: Self::Key) -> Result<Vec<u8>, Self::Error> {
let payload = input;
let jws_encoded = jws_sign_payload(&payload, key.private_key.as_bytes())?;
let jws_body = JwsBody::from_str(&jws_encoded).ok_or(error::CryptoError::InvalidData(
"JWS encoded data is incomplete",
))?;
let jws_payload = serde_json::to_vec(&jws_body)?;
let jwe_encrypted = encrypt_jwe(&jws_payload, key.public_key)?;
let jwe_body = JweBody::from_str(&jwe_encrypted)
.ok_or(error::CryptoError::InvalidData("JWE data incomplete"))?;
Ok(serde_json::to_vec(&jwe_body)?)
}

fn decrypt(input: Vec<u8>, key: Self::Key) -> Result<Vec<u8>, Self::Error> {
let jwe_body: JweBody = serde_json::from_slice(&input)?;
let jwe_encoded = jwe_body.get_dotted_jwe();
let algo = jwe::RSA_OAEP;
let jwe_decrypted = decrypt_jwe(&jwe_encoded, key.private_key, algo)?;
let jws_parsed = JwsBody::from_str(&jwe_decrypted).ok_or(
error::CryptoError::InvalidData("Failed while extracting jws body"),
)?;
let jws_encoded = jws_parsed.get_dotted_jws();
let output = verify_sign(jws_encoded, key.public_key)?;
Ok(output.as_bytes().to_vec())
}
}

fn jws_sign_payload(
payload: &[u8],
private_key: impl AsRef<[u8]>,
) -> Result<String, error::CryptoError> {
let alg = jws::RS256;
let src_header = jws::JwsHeader::new();
let signer = alg.signer_from_pem(private_key)?;
Ok(jws::serialize_compact(payload, &src_header, &signer)?)
}

fn encrypt_jwe(payload: &[u8], public_key: impl AsRef<[u8]>) -> Result<String, error::CryptoError> {
let alg = jwe::RSA_OAEP_256;
let enc = "A256GCM";
let mut src_header = jwe::JweHeader::new();
src_header.set_content_type(enc);
src_header.set_token_type("JWT");
let encrypter = alg.encrypter_from_pem(public_key)?;

Ok(jwe::serialize_compact(payload, &src_header, &encrypter)?)
}

pub fn decrypt_jwe(
jwt: &str,
private_key: impl AsRef<[u8]>,
alg: jwe::alg::rsaes::RsaesJweAlgorithm,
) -> Result<String, error::CryptoError> {
let decrypter = alg.decrypter_from_pem(private_key)?;

let (dst_payload, _dst_header) = jwe::deserialize_compact(jwt, &decrypter)?;

Ok(String::from_utf8(dst_payload)?)
}

pub fn verify_sign(jws_body: String, key: impl AsRef<[u8]>) -> Result<String, error::CryptoError> {
let alg = jws::RS256;
let input = jws_body.as_bytes();
let verifier = alg.verifier_from_pem(key)?;
let (dst_payload, _dst_header) = jws::deserialize_compact(input, &verifier)?;
let resp = String::from_utf8(dst_payload)?;
Ok(resp)
}
3 changes: 3 additions & 0 deletions src/db.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
use diesel_async::{pooled_connection::AsyncDieselConnectionManager, AsyncPgConnection};

pub type Pool = bb8::Pool<AsyncDieselConnectionManager<AsyncPgConnection>>;
21 changes: 21 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use std::string::FromUtf8Error;

#[derive(Debug, thiserror::Error)]
pub enum ConfigurationError {
#[error("error while creating the webserver")]
ServerError(#[from] hyper::Error),
#[error("invalid host for socket")]
AddressError(#[from] std::net::AddrParseError),
}

#[derive(Debug, thiserror::Error)]
pub enum CryptoError {
#[error("failed while serializing with serde_json")]
SerdeJsonError(#[from] serde_json::Error),
#[error("error while performing jwe operation")]
JWError(#[from] josekit::JoseError),
#[error("invalid data received: {0}")]
InvalidData(&'static str),
#[error("error while parsing utf-8")]
EncodingError(#[from] FromUtf8Error)
}
5 changes: 5 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pub mod app;
pub mod error;
pub mod config;
pub mod db;
pub mod crypto;

0 comments on commit 69979a0

Please sign in to comment.