Skip to main content
Glama
decryption_key.rs6.15 kB
use std::{ io, path::Path, }; use base64::{ Engine, engine::general_purpose, }; use si_hash::Hash; use sodiumoxide::crypto::box_::{ PublicKey as BoxPublicKey, SecretKey as BoxSecretKey, }; use telemetry::prelude::*; use thiserror::Error; use tokio::{ fs::File, io::AsyncReadExt, }; use crate::VeritechCryptoConfig; /// An error that can be returned when working with a [`VeritechDecryptionKey`]. #[remain::sorted] #[derive(Error, Debug)] pub enum VeritechDecryptionKeyError { /// When deserializing a crypted message from base64 encoding fails #[error("base64 decode error: {0}")] Base64Decode(#[from] base64::DecodeError), /// When a message fails to be decrypted using the decryption key #[error("failed to decrypt encryption key from bytes")] DecryptionFailed, /// When a key cannot be made from the supplied config #[error( "key cannot be made from the supplied config, must supply either a base64 string or a filepath" )] FromConfig, /// When a key fails to be parsed from bytes #[error("failed to load key from bytes")] KeyParse, /// When an error is return while reading from a key file #[error("failed to load key from file: {0}")] LoadKeyIO(#[source] io::Error), } /// A key that decrypts segements of a Veritech function request message. #[derive(Debug, Clone)] pub struct VeritechDecryptionKey { secret_key: BoxSecretKey, public_key: BoxPublicKey, public_key_hash: Hash, public_key_hash_string: String, } impl VeritechDecryptionKey { /// Creates an instance of [`VeritechDecryptionKey`] based on the /// supplied configuration. /// /// # Errors /// /// Return `Err` if: /// /// - A key file was not readable (i.e. incorrect permission and/or ownership) /// - A key file could not be successfuly parsed /// - A key string could not be successfully parsed /// - An invalid configuration was passed in pub async fn from_config( config: VeritechCryptoConfig, ) -> Result<Self, VeritechDecryptionKeyError> { match (config.decryption_key_file, config.decryption_key_base64) { (Some(path), None) => Self::load(path).await, (None, Some(b64_string)) => Self::decode(b64_string).await, _ => Err(VeritechDecryptionKeyError::FromConfig), } } /// Loads a [`VeritechDecryptionKey`] from a file path. /// /// # Errors /// /// Return `Err` if: /// /// - A key file was not readable (i.e. incorrect permission and/or ownership) /// - A key file could not be successfuly parsed pub async fn load( decryption_key_path: impl AsRef<Path>, ) -> Result<Self, VeritechDecryptionKeyError> { trace!( decryption_key_path = %decryption_key_path.as_ref().display(), "loading veritech decryption key from disk", ); let mut file = File::open(decryption_key_path) .await .map_err(VeritechDecryptionKeyError::LoadKeyIO)?; let mut buf: Vec<u8> = Vec::with_capacity(32); file.read_to_end(&mut buf) .await .map_err(VeritechDecryptionKeyError::LoadKeyIO)?; let secret_key = BoxSecretKey::from_slice(&buf).ok_or(VeritechDecryptionKeyError::KeyParse)?; let public_key = secret_key.public_key(); let public_key_hash = Hash::new(public_key.as_ref()); let public_key_hash_string = public_key_hash.to_string(); Ok(Self { secret_key, public_key, public_key_hash, public_key_hash_string, }) } /// Loads a [`VeritechDecryptionKey`] from a base64 encoded string. /// /// # Errors /// /// Return `Err` if: /// /// - A key string could not be successfully parsed pub async fn decode(encryption_key_string: String) -> Result<Self, VeritechDecryptionKeyError> { trace!( "loading veritech encryption key from base64 string {}", encryption_key_string ); let buf = general_purpose::STANDARD .decode(encryption_key_string) .map_err(VeritechDecryptionKeyError::Base64Decode)?; let secret_key = BoxSecretKey::from_slice(&buf).ok_or(VeritechDecryptionKeyError::KeyParse)?; let public_key = secret_key.public_key(); let public_key_hash = Hash::new(public_key.as_ref()); let public_key_hash_string = public_key_hash.to_string(); Ok(Self { secret_key, public_key, public_key_hash, public_key_hash_string, }) } /// Decrypts an encrypted message which is Base64 encoded. /// /// # Errors /// /// Return `Err` if: /// /// - Base64 decoding fails /// - Message cannot be decrypted using this key pub fn decode_and_decrypt( &self, base64_encoded: impl AsRef<str>, ) -> Result<Vec<u8>, VeritechDecryptionKeyError> { let crypted = general_purpose::STANDARD_NO_PAD.decode(base64_encoded.as_ref())?; sodiumoxide::crypto::sealedbox::open(&crypted, &self.public_key, &self.secret_key) .map_err(|_| VeritechDecryptionKeyError::DecryptionFailed) } /// Returns a [`Hash`] of the encryption key which would have encoded a message. pub fn encryption_key_hash(&self) -> &Hash { &self.public_key_hash } /// Returns a string representaion of the hash of the encryption key which would have encoded a /// message. pub fn encryption_key_hash_str(&self) -> &str { self.public_key_hash_string.as_str() } } impl From<BoxSecretKey> for VeritechDecryptionKey { fn from(value: BoxSecretKey) -> Self { let public_key = value.public_key(); let secret_key = value; let public_key_hash = Hash::new(public_key.as_ref()); let public_key_hash_string = public_key_hash.to_string(); Self { secret_key, public_key, public_key_hash, public_key_hash_string, } } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/systeminit/si'

If you have feedback or need assistance with the MCP directory API, please join our Discord server