Compare commits
No commits in common. "2471cff83e2ba4a29e0f8b2a0d776738a6be8d68" and "b8e00c244ae11d0eaabf228e8a2e518e9a3ae8f5" have entirely different histories.
2471cff83e
...
b8e00c244a
6 changed files with 54 additions and 64 deletions
|
@ -15,7 +15,7 @@ oxidetalis_core = { path = "crates/oxidetalis_core" }
|
|||
oxidetalis_config = { path = "crates/oxidetalis_config" }
|
||||
oxidetalis_migrations = { path = "crates/oxidetalis_migrations" }
|
||||
oxidetalis_entities = { path = "crates/oxidetalis_entities" }
|
||||
# Shared dependencies
|
||||
# Shered dependencies
|
||||
base58 = "0.2.0"
|
||||
serde = "1.0.203"
|
||||
thiserror = "1.0.61"
|
||||
|
|
|
@ -49,10 +49,10 @@ pub enum ApiError {
|
|||
/// The entered public key is already registered (400 Bad Request)
|
||||
#[error("The entered public key is already registered")]
|
||||
DuplicatedUser,
|
||||
/// The user entered two different public keys
|
||||
/// The user enterd tow different public keys
|
||||
/// one in the header and other in the request body
|
||||
/// (400 Bad Request)
|
||||
#[error("You entered two different public keys")]
|
||||
#[error("TODO")]
|
||||
TwoDifferentKeys,
|
||||
}
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ pub trait DepotExt {
|
|||
/// Returns the server configuration
|
||||
fn config(&self) -> &Config;
|
||||
/// Retutns the nonce cache
|
||||
fn nonce_cache(&self) -> Arc<NonceCache>;
|
||||
fn nonce_cache(&self) -> &NonceCache;
|
||||
/// Returns the size of the nonce cache
|
||||
fn nonce_cache_size(&self) -> &usize;
|
||||
}
|
||||
|
@ -52,11 +52,9 @@ impl DepotExt for Depot {
|
|||
self.obtain::<Arc<Config>>().expect("Config not found")
|
||||
}
|
||||
|
||||
fn nonce_cache(&self) -> Arc<NonceCache> {
|
||||
Arc::clone(
|
||||
fn nonce_cache(&self) -> &NonceCache {
|
||||
self.obtain::<Arc<NonceCache>>()
|
||||
.expect("Nonce cache not found"),
|
||||
)
|
||||
.expect("Nonce cache not found")
|
||||
}
|
||||
|
||||
fn nonce_cache_size(&self) -> &usize {
|
||||
|
|
|
@ -42,18 +42,20 @@ pub async fn signature_check(
|
|||
let mut write_err =
|
||||
|message: &str, status_code| super::write_error(res, ctrl, message.to_owned(), status_code);
|
||||
|
||||
let data = if req.body().is_end_stream() {
|
||||
format!("{}{}", req.method(), req.uri().path())
|
||||
} else {
|
||||
match req.parse_json::<serde_json::Value>().await {
|
||||
if req.body().is_end_stream() {
|
||||
write_err(
|
||||
"Request body is empty, the signature need a signed body",
|
||||
UNAUTHORIZED,
|
||||
);
|
||||
return;
|
||||
}
|
||||
let json_body = match req.parse_json::<serde_json::Value>().await {
|
||||
Ok(j) => j.to_string(),
|
||||
Err(err) => {
|
||||
write_err(&err.to_string(), UNAUTHORIZED);
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let signature = match utils::extract_signature(req) {
|
||||
Ok(s) => s,
|
||||
Err(err) => {
|
||||
|
@ -70,12 +72,12 @@ pub async fn signature_check(
|
|||
}
|
||||
};
|
||||
|
||||
if !utils::is_valid_nonce(&signature, &depot.nonce_cache(), depot.nonce_cache_size())
|
||||
if !utils::is_valid_nonce(&signature, depot.nonce_cache(), depot.nonce_cache_size())
|
||||
|| !utils::is_valid_signature(
|
||||
&sender_public_key,
|
||||
&depot.config().server.private_key,
|
||||
&signature,
|
||||
data.as_bytes(),
|
||||
json_body.as_bytes(),
|
||||
)
|
||||
{
|
||||
write_err("Invalid signature", UNAUTHORIZED);
|
||||
|
|
|
@ -33,6 +33,7 @@ use k256::{
|
|||
NonZeroScalar,
|
||||
PublicKey,
|
||||
};
|
||||
use logcall::logcall;
|
||||
use rand::{thread_rng, RngCore};
|
||||
|
||||
use crate::types::{
|
||||
|
@ -105,30 +106,6 @@ impl K256Secret {
|
|||
)
|
||||
}
|
||||
|
||||
/// Sign a data with the shared secret.
|
||||
///
|
||||
/// The signature is exiplained in the OTMP specification.
|
||||
pub fn sign_with_shared_secret(data: &[u8], shared_secret: &[u8; 32]) -> CoreSignature {
|
||||
let mut time_and_nonce = [0u8; 24];
|
||||
time_and_nonce[0..=7].copy_from_slice(
|
||||
&SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.expect("SystemTime before UNIX EPOCH!")
|
||||
.as_secs()
|
||||
.to_be_bytes(),
|
||||
);
|
||||
thread_rng().fill_bytes(&mut time_and_nonce[8..=23]);
|
||||
|
||||
let mut hmac_secret = [0u8; 56];
|
||||
hmac_secret[0..=31].copy_from_slice(shared_secret);
|
||||
hmac_secret[32..=55].copy_from_slice(&time_and_nonce);
|
||||
let mut signature = [0u8; 56];
|
||||
signature[0..=31].copy_from_slice(&hmac_sha256(data, &hmac_secret));
|
||||
signature[32..=55].copy_from_slice(&time_and_nonce);
|
||||
|
||||
CoreSignature::from(signature)
|
||||
}
|
||||
|
||||
/// Returns the public key.
|
||||
pub fn pubkey(&self) -> CorePublicKey {
|
||||
CorePublicKey::try_from(
|
||||
|
@ -202,22 +179,45 @@ impl K256Secret {
|
|||
|
||||
/// Sign a data with the shared secret.
|
||||
///
|
||||
/// The signature is explained in the OTMP specification.
|
||||
/// The signature is exiplained in the OTMP specification.
|
||||
#[logcall]
|
||||
pub fn sign(&self, data: &[u8], sign_to: &CorePublicKey) -> CoreSignature {
|
||||
Self::sign_with_shared_secret(data, &self.shared_secret(sign_to))
|
||||
let mut time_and_nonce = [0u8; 24];
|
||||
time_and_nonce[0..=7].copy_from_slice(
|
||||
&SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.expect("SystemTime before UNIX EPOCH!")
|
||||
.as_secs()
|
||||
.to_be_bytes(),
|
||||
);
|
||||
thread_rng().fill_bytes(&mut time_and_nonce[8..=23]);
|
||||
|
||||
let mut hmac_secret = [0u8; 56];
|
||||
hmac_secret[0..=31].copy_from_slice(&self.shared_secret(sign_to));
|
||||
hmac_secret[32..=55].copy_from_slice(&time_and_nonce);
|
||||
let mut signature = [0u8; 56];
|
||||
signature[0..=31].copy_from_slice(&hmac_sha256(data, &hmac_secret));
|
||||
signature[32..=55].copy_from_slice(&time_and_nonce);
|
||||
|
||||
CoreSignature::from(signature)
|
||||
}
|
||||
|
||||
/// Verify the given signature with the signer.
|
||||
/// Verify a signature with the shared secret.
|
||||
///
|
||||
/// Note:
|
||||
/// The time and the nonce will not be checked here
|
||||
#[logcall]
|
||||
pub fn verify(&self, data: &[u8], signature: &CoreSignature, signer: &CorePublicKey) -> bool {
|
||||
signature.verify(data, &self.shared_secret(signer))
|
||||
let mut hmac_secret = [0u8; 56];
|
||||
hmac_secret[0..=31].copy_from_slice(&self.shared_secret(signer));
|
||||
hmac_secret[32..=39].copy_from_slice(signature.timestamp());
|
||||
hmac_secret[40..=55].copy_from_slice(signature.nonce());
|
||||
|
||||
&hmac_sha256(data, &hmac_secret) == signature.hmac_output()
|
||||
}
|
||||
}
|
||||
|
||||
/// Compute the HMAC-SHA256 of the given data with the given secret.
|
||||
pub(crate) fn hmac_sha256(data: &[u8], secret: &[u8]) -> [u8; 32] {
|
||||
fn hmac_sha256(data: &[u8], secret: &[u8]) -> [u8; 32] {
|
||||
let mut mac = HmacSha256::new_from_slice(secret).expect("HMAC can take key of any size");
|
||||
mac.update(data);
|
||||
mac.finalize().into_bytes().into()
|
||||
|
|
|
@ -31,13 +31,13 @@ use salvo_oapi::{
|
|||
ToSchema,
|
||||
};
|
||||
|
||||
use crate::cipher::{hmac_sha256, CipherError};
|
||||
use crate::cipher::CipherError;
|
||||
|
||||
/// Correct length except message
|
||||
const CORRECT_LENGTH: &str = "The length is correct";
|
||||
|
||||
/// K256 public key
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub struct PublicKey([u8; 33]);
|
||||
|
||||
/// K256 private key
|
||||
|
@ -45,7 +45,7 @@ pub struct PublicKey([u8; 33]);
|
|||
pub struct PrivateKey([u8; 32]);
|
||||
|
||||
/// OTMP signature
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Signature {
|
||||
hmac_output: [u8; 32],
|
||||
timestamp: [u8; 8],
|
||||
|
@ -90,16 +90,6 @@ impl Signature {
|
|||
sig[40..=55].copy_from_slice(&self.nonce);
|
||||
sig
|
||||
}
|
||||
|
||||
/// Verify the signature with the given shared secret.
|
||||
pub fn verify(&self, data: &[u8], shared_secret: &[u8; 32]) -> bool {
|
||||
let mut hmac_secret = [0u8; 56];
|
||||
hmac_secret[0..=31].copy_from_slice(shared_secret);
|
||||
hmac_secret[32..=39].copy_from_slice(self.timestamp());
|
||||
hmac_secret[40..=55].copy_from_slice(self.nonce());
|
||||
|
||||
&hmac_sha256(data, &hmac_secret) == self.hmac_output()
|
||||
}
|
||||
}
|
||||
|
||||
/// Public key to base58 string
|
||||
|
|
Loading…
Reference in a new issue