1use serde::ser::Serialize;
2
3use crate::algorithms::AlgorithmFamily;
4use crate::crypto;
5use crate::errors::{new_error, ErrorKind, Result};
6use crate::header::Header;
7use crate::pem::decoder::PemEncodedKey;
8use crate::serialization::b64_encode_part;
9
10#[derive(Debug, Clone, PartialEq)]
13pub struct EncodingKey {
14    pub(crate) family: AlgorithmFamily,
15    content: Vec<u8>,
16}
17
18impl EncodingKey {
19    pub fn from_secret(secret: &[u8]) -> Self {
21        EncodingKey { family: AlgorithmFamily::Hmac, content: secret.to_vec() }
22    }
23
24    pub fn from_base64_secret(secret: &str) -> Result<Self> {
26        let out = base64::decode(&secret)?;
27        Ok(EncodingKey { family: AlgorithmFamily::Hmac, content: out })
28    }
29
30    pub fn from_rsa_pem(key: &[u8]) -> Result<Self> {
33        let pem_key = PemEncodedKey::new(key)?;
34        let content = pem_key.as_rsa_key()?;
35        Ok(EncodingKey { family: AlgorithmFamily::Rsa, content: content.to_vec() })
36    }
37
38    pub fn from_ec_pem(key: &[u8]) -> Result<Self> {
41        let pem_key = PemEncodedKey::new(key)?;
42        let content = pem_key.as_ec_private_key()?;
43        Ok(EncodingKey { family: AlgorithmFamily::Ec, content: content.to_vec() })
44    }
45
46    pub fn from_rsa_der(der: &[u8]) -> Self {
48        EncodingKey { family: AlgorithmFamily::Rsa, content: der.to_vec() }
49    }
50
51    pub fn from_ec_der(der: &[u8]) -> Self {
53        EncodingKey { family: AlgorithmFamily::Ec, content: der.to_vec() }
54    }
55
56    pub(crate) fn inner(&self) -> &[u8] {
57        &self.content
58    }
59}
60
61pub fn encode<T: Serialize>(header: &Header, claims: &T, key: &EncodingKey) -> Result<String> {
84    if key.family != header.alg.family() {
85        return Err(new_error(ErrorKind::InvalidAlgorithm));
86    }
87    let encoded_header = b64_encode_part(&header)?;
88    let encoded_claims = b64_encode_part(&claims)?;
89    let message = [encoded_header.as_ref(), encoded_claims.as_ref()].join(".");
90    let signature = crypto::sign(&*message, key, header.alg)?;
91
92    Ok([message, signature].join("."))
93}