golem_certificate/
cryptography.rs

1use anyhow::Result;
2
3use serde::{Deserialize, Serialize};
4use serde_json::{json, Value};
5
6use sha2::{Digest, Sha224, Sha256, Sha384, Sha512};
7use sha3::{Sha3_224, Sha3_256, Sha3_384, Sha3_512};
8
9use ed25519_dalek::{
10    ExpandedSecretKey, Keypair, PublicKey, SecretKey, Signature as EdDSASignature, Verifier,
11};
12use rand::rngs::OsRng;
13
14use crate::schemas::signature::SignatureAlgorithm;
15use crate::serde_utils::{bytes_to_hex, hex_to_bytes};
16use crate::Error;
17
18#[derive(Clone, Debug, Deserialize, Serialize, Default)]
19#[serde(rename_all = "kebab-case")]
20pub enum HashAlgorithm {
21    Sha224,
22    Sha256,
23    Sha384,
24    #[default]
25    Sha512,
26    Sha3_224,
27    Sha3_256,
28    Sha3_384,
29    Sha3_512,
30}
31
32#[derive(Clone, Debug, Deserialize, Serialize, Default)]
33pub enum EncryptionAlgorithm {
34    #[default]
35    EdDSA,
36    EdDSAOpenPGP,
37}
38
39#[derive(Deserialize, Serialize, Debug, Clone)]
40pub struct Key {
41    algorithm: EncryptionAlgorithm,
42    #[serde(serialize_with = "bytes_to_hex", deserialize_with = "hex_to_bytes")]
43    key: Vec<u8>,
44    #[serde(skip_serializing_if = "Option::is_none")]
45    parameters: Option<Value>,
46}
47
48impl From<[u8; 32]> for Key {
49    fn from(value: [u8; 32]) -> Self {
50        Self {
51            algorithm: EncryptionAlgorithm::EdDSA,
52            parameters: Some(json!({ "scheme": "Ed25519" })),
53            key: value.into(),
54        }
55    }
56}
57
58pub struct KeyPair {
59    pub public_key: Key,
60    pub private_key: Key,
61}
62
63pub fn create_key_pair() -> KeyPair {
64    let mut csprng = OsRng {};
65    let keypair = Keypair::generate(&mut csprng);
66    KeyPair {
67        public_key: keypair.public.to_bytes().into(),
68        private_key: keypair.secret.to_bytes().into(),
69    }
70}
71
72pub fn create_default_hash(value: &Value) -> Result<Vec<u8>, Error> {
73    create_hash(value, &HashAlgorithm::default())
74}
75
76pub fn create_hash(value: &Value, hash_algorithm: &HashAlgorithm) -> Result<Vec<u8>, Error> {
77    serde_json_canonicalizer::to_vec(value)
78        .map(|canonical_json| create_digest(canonical_json, hash_algorithm))
79        .map_err(|e| Error::JcsSerializationError(e.to_string()))
80}
81
82fn create_digest(input: impl AsRef<[u8]>, hash_algorithm: &HashAlgorithm) -> Vec<u8> {
83    // Digest trait and the output hash contains the size so we cannot create a common variable prior to converting it into a Vec<u8>
84    match hash_algorithm {
85        HashAlgorithm::Sha224 => Sha224::digest(input).into_iter().collect(),
86        HashAlgorithm::Sha256 => Sha256::digest(input).into_iter().collect(),
87        HashAlgorithm::Sha384 => Sha384::digest(input).into_iter().collect(),
88        HashAlgorithm::Sha512 => Sha512::digest(input).into_iter().collect(),
89        HashAlgorithm::Sha3_224 => Sha3_224::digest(input).into_iter().collect(),
90        HashAlgorithm::Sha3_256 => Sha3_256::digest(input).into_iter().collect(),
91        HashAlgorithm::Sha3_384 => Sha3_384::digest(input).into_iter().collect(),
92        HashAlgorithm::Sha3_512 => Sha3_512::digest(input).into_iter().collect(),
93    }
94}
95
96pub fn sign_json(value: &Value, private_key: &Key) -> Result<(SignatureAlgorithm, Vec<u8>)> {
97    let canonical_json = serde_json_canonicalizer::to_vec(value)?;
98    let secret_key = SecretKey::from_bytes(&private_key.key)?;
99    let signature_value = sign_bytes(canonical_json, &secret_key);
100    let algorithm = SignatureAlgorithm::default();
101    Ok((algorithm, signature_value))
102}
103
104fn sign_bytes(bytes: impl AsRef<[u8]>, secret_key: &SecretKey) -> Vec<u8> {
105    let expanded_secret_key = ExpandedSecretKey::from(secret_key);
106    let public_key = PublicKey::from(secret_key);
107    let signature_value = expanded_secret_key.sign(bytes.as_ref(), &public_key);
108    signature_value.to_bytes().into()
109}
110
111pub fn verify_signature_json(
112    value: &Value,
113    signature_algorithm: &EncryptionAlgorithm,
114    signature_value: impl AsRef<[u8]>,
115    public_key: &Key,
116) -> Result<(), Error> {
117    let canonical_json = serde_json_canonicalizer::to_vec(value)
118        .map_err(|e| Error::JcsSerializationError(e.to_string()))?;
119    let eddsa_signature = EdDSASignature::from_bytes(signature_value.as_ref())
120        .map_err(|_| Error::InvalidSignatureValue)?;
121    let public_key = PublicKey::from_bytes(&public_key.key).map_err(|_| Error::InvalidPublicKey)?;
122    match signature_algorithm {
123        EncryptionAlgorithm::EdDSA => verify_bytes(canonical_json, &eddsa_signature, &public_key),
124        EncryptionAlgorithm::EdDSAOpenPGP => {
125            verify_bytes_openpgp(canonical_json, &eddsa_signature, &public_key)
126        }
127    }
128}
129
130// OpenPGP uses the hash of the message as input to the signature algorithm
131// https://datatracker.ietf.org/doc/html/rfc4880#section-5.2.4
132// This is used when signing with OpenPGP application on smartcards
133fn verify_bytes_openpgp(
134    bytes: impl AsRef<[u8]>,
135    signature: &EdDSASignature,
136    public_key: &PublicKey,
137) -> Result<(), Error> {
138    let bytes_hash = create_digest(bytes, &HashAlgorithm::Sha512);
139    verify_bytes(bytes_hash, signature, public_key)
140}
141
142fn verify_bytes(
143    bytes: impl AsRef<[u8]>,
144    signature: &EdDSASignature,
145    public_key: &PublicKey,
146) -> Result<(), Error> {
147    public_key
148        .verify(bytes.as_ref(), signature)
149        .map_err(|_| Error::InvalidSignature)
150}