medallion/src/crypt.rs

115 lines
4.3 KiB
Rust
Raw Normal View History

2017-02-20 18:05:06 +00:00
use base64::{decode_config, encode_config, URL_SAFE_NO_PAD};
use header::Algorithm;
2017-02-13 23:40:07 +00:00
use openssl::hash::MessageDigest;
use openssl::memcmp;
use openssl::pkey::PKey;
use openssl::rsa::Rsa;
use openssl::sign::{Signer, Verifier};
2017-02-17 16:53:12 +00:00
use super::Result;
2017-02-13 23:40:07 +00:00
2017-02-17 16:53:12 +00:00
pub fn sign(data: &str, key: &[u8], algorithm: &Algorithm) -> Result<String> {
match algorithm {
&Algorithm::HS256 => sign_hmac(data, key, MessageDigest::sha256()),
&Algorithm::HS384 => sign_hmac(data, key, MessageDigest::sha384()),
&Algorithm::HS512 => sign_hmac(data, key, MessageDigest::sha512()),
&Algorithm::RS256 => sign_rsa(data, key, MessageDigest::sha256()),
&Algorithm::RS384 => sign_rsa(data, key, MessageDigest::sha384()),
&Algorithm::RS512 => sign_rsa(data, key, MessageDigest::sha512()),
}
}
2017-02-17 16:53:12 +00:00
pub fn verify(target: &str, data: &str, key: &[u8], algorithm: &Algorithm) -> Result<bool> {
match algorithm {
&Algorithm::HS256 => verify_hmac(target, data, key, MessageDigest::sha256()),
&Algorithm::HS384 => verify_hmac(target, data, key, MessageDigest::sha384()),
&Algorithm::HS512 => verify_hmac(target, data, key, MessageDigest::sha512()),
&Algorithm::RS256 => verify_rsa(target, data, key, MessageDigest::sha256()),
&Algorithm::RS384 => verify_rsa(target, data, key, MessageDigest::sha384()),
&Algorithm::RS512 => verify_rsa(target, data, key, MessageDigest::sha512()),
}
}
2017-02-17 16:53:12 +00:00
fn sign_hmac(data: &str, key: &[u8], digest: MessageDigest) -> Result<String> {
2017-02-17 17:39:28 +00:00
let secret_key = PKey::hmac(key)?;
2017-02-13 23:40:07 +00:00
2017-02-17 16:53:12 +00:00
let mut signer = Signer::new(digest, &secret_key)?;
signer.update(data.as_bytes())?;
2017-02-13 23:40:07 +00:00
2017-02-17 16:53:12 +00:00
let mac = signer.finish()?;
2017-02-20 18:05:06 +00:00
Ok(encode_config(&mac, URL_SAFE_NO_PAD))
2017-02-13 23:40:07 +00:00
}
2017-02-17 16:53:12 +00:00
fn sign_rsa(data: &str, key: &[u8], digest: MessageDigest) -> Result<String> {
let private_key = Rsa::private_key_from_pem(key)?;
let pkey = PKey::from_rsa(private_key)?;
2017-02-13 23:40:07 +00:00
2017-02-17 16:53:12 +00:00
let mut signer = Signer::new(digest, &pkey)?;
signer.update(data.as_bytes())?;
let sig = signer.finish()?;
2017-02-20 18:05:06 +00:00
Ok(encode_config(&sig, URL_SAFE_NO_PAD))
2017-02-13 23:40:07 +00:00
}
2017-02-17 16:53:12 +00:00
fn verify_hmac(target: &str, data: &str, key: &[u8], digest: MessageDigest) -> Result<bool> {
2017-02-20 18:05:06 +00:00
let target_bytes: Vec<u8> = decode_config(target, URL_SAFE_NO_PAD)?;
2017-02-17 16:53:12 +00:00
let secret_key = PKey::hmac(key)?;
2017-02-13 23:40:07 +00:00
2017-02-17 16:53:12 +00:00
let mut signer = Signer::new(digest, &secret_key)?;
signer.update(data.as_bytes())?;
2017-02-13 23:40:07 +00:00
2017-02-17 16:53:12 +00:00
let mac = signer.finish()?;
2017-02-13 23:40:07 +00:00
2017-02-17 16:53:12 +00:00
Ok(memcmp::eq(&mac, &target_bytes))
2017-02-13 23:40:07 +00:00
}
2017-02-17 16:53:12 +00:00
fn verify_rsa(signature: &str, data: &str, key: &[u8], digest: MessageDigest) -> Result<bool> {
2017-02-20 18:05:06 +00:00
let signature_bytes: Vec<u8> = decode_config(signature, URL_SAFE_NO_PAD)?;
2017-02-17 16:53:12 +00:00
let public_key = Rsa::public_key_from_pem(key)?;
let pkey = PKey::from_rsa(public_key)?;
let mut verifier = Verifier::new(digest, &pkey)?;
verifier.update(data.as_bytes())?;
2017-02-17 17:39:28 +00:00
Ok(verifier.finish(&signature_bytes)?)
2017-02-13 23:40:07 +00:00
}
2017-02-15 18:35:10 +00:00
#[cfg(test)]
2017-02-17 17:54:50 +00:00
pub mod tests {
use header::Algorithm;
use openssl;
2017-02-15 18:47:36 +00:00
use super::{sign, verify};
2017-02-15 18:35:10 +00:00
#[test]
2017-02-15 18:40:34 +00:00
pub fn sign_data_hmac() {
2017-02-15 18:35:10 +00:00
let header = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9";
let claims = "eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9";
2017-02-20 18:05:06 +00:00
let real_sig = "TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ";
2017-02-15 18:35:10 +00:00
let data = format!("{}.{}", header, claims);
let sig = sign(&*data, "secret".as_bytes(), &Algorithm::HS256);
2017-02-15 18:35:10 +00:00
2017-02-17 16:53:12 +00:00
assert_eq!(sig.unwrap(), real_sig);
2017-02-15 18:35:10 +00:00
}
#[test]
pub fn sign_and_verify_data_rsa() {
2017-02-15 18:35:10 +00:00
let header = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9";
let claims = "eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9";
2017-02-15 18:35:10 +00:00
let data = format!("{}.{}", header, claims);
let keypair = openssl::rsa::Rsa::generate(2048).unwrap();
2017-02-15 18:35:10 +00:00
let sig = sign(&*data, &keypair.private_key_to_pem().unwrap(), &Algorithm::RS256).unwrap();
2017-02-15 18:35:10 +00:00
assert!(verify(&sig, &*data, &keypair.public_key_to_pem().unwrap(), &Algorithm::RS256).unwrap());
2017-02-15 18:35:10 +00:00
}
#[test]
2017-02-15 18:40:34 +00:00
pub fn verify_data_hmac() {
2017-02-15 18:35:10 +00:00
let header = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9";
let claims = "eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9";
let target = "TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ";
let data = format!("{}.{}", header, claims);
2017-02-17 16:53:12 +00:00
assert!(verify(target, &*data, "secret".as_bytes(), &Algorithm::HS256).unwrap());
2017-02-15 18:35:10 +00:00
}
}