diff --git a/.github/workflows/clippy.yml b/.github/workflows/clippy.yml new file mode 100644 index 0000000..ab896b7 --- /dev/null +++ b/.github/workflows/clippy.yml @@ -0,0 +1,24 @@ +name: Clippy +on: + workflow_dispatch: + push: + branches: [trunk] + pull_request: + branches: [trunk] + +permissions: + contents: read + +jobs: + clippy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - name: Install Rust + run: rustup update stable + + - name: Install Clippy + run: rustup component add clippy + + - name: Run Clippy + run: cargo clippy diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..8023044 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,17 @@ +## v0.2.1 + +- Fix linter warnings +- Add linter workflow +- Add OpenSSF Best Practices badge + +## v0.2.0 + +- Interoperability with other Atsign SDKs +- Autobug workflow +- Removed direct dependency on a specific TLS client +- OpenSSF Scorecard +- create at_secrets from values + +## v0.1.0 + +- Initial version with PKAM auth and simple data exchange diff --git a/Cargo.toml b/Cargo.toml index 235b4ae..a591804 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "at_rust" -version = "0.2.0" +version = "0.2.1" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/README.md b/README.md index cd4aafa..36edd7c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/atsign-foundation/at_rust/badge)](https://api.securityscorecards.dev/projects/github.com/atsign-foundation/at_rust) +[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/8148/badge)](https://www.bestpractices.dev/projects/8148) # Rust SDK - (⚠️Alpha version⚠️) This repo contains libraries, tools, samples and examples for developers who wish to work with the atPlatform from Rust code. diff --git a/src/at_chops/at_chops.rs b/src/at_chops/chops.rs similarity index 89% rename from src/at_chops/at_chops.rs rename to src/at_chops/chops.rs index f6c2606..f4849db 100644 --- a/src/at_chops/at_chops.rs +++ b/src/at_chops/chops.rs @@ -1,4 +1,4 @@ -use log::{info, warn}; +//use log::{info, warn}; use super::utils::{ base64_decode, base64_encode, construct_aes_key, construct_rsa_private_key, @@ -19,7 +19,7 @@ pub fn decrypt_private_key( ) -> String { let iv: [u8; 16] = [0x00; 16]; let mut cypher = construct_aes_key(decoded_self_encryption_key, &iv); - let decoded_private_key = base64_decode(&encrypted_private_key); + let decoded_private_key = base64_decode(encrypted_private_key); let mut output: Vec = vec![0; decoded_private_key.len()]; cypher.process(&decoded_private_key, &mut output); @@ -36,9 +36,9 @@ pub fn decrypt_private_key( /// Sign a given challenge with the decrypted private key. pub fn sign_challenge(challenge: &str, decrypted_private_key: &str) -> String { - let decoded_private_key = base64_decode(&decrypted_private_key); + let decoded_private_key = base64_decode(decrypted_private_key); let rsa_private_key = construct_rsa_private_key(&decoded_private_key); - rsa_sign(rsa_private_key, &challenge.as_bytes()) + rsa_sign(rsa_private_key, challenge.as_bytes()) } /// Cut a new symmetric key to be used when interacting with a new atSign. @@ -49,37 +49,35 @@ pub fn create_new_shared_symmetric_key() -> String { /// Decrypt the symmetric key with "our" private key. pub fn decrypt_symmetric_key(encrypted_symmetric_key: &str, decrypted_private_key: &str) -> String { - let decoded_private_key = base64_decode(&decrypted_private_key); + let decoded_private_key = base64_decode(decrypted_private_key); let rsa_private_key = construct_rsa_private_key(&decoded_private_key); - let decoded_symmetric_key = base64_decode(&encrypted_symmetric_key); - let decrypted_symmetric_key = - decrypt_symm_key_with_private_key(&rsa_private_key, &decoded_symmetric_key); - decrypted_symmetric_key + let decoded_symmetric_key = base64_decode(encrypted_symmetric_key); + decrypt_symm_key_with_private_key(&rsa_private_key, &decoded_symmetric_key) } /// Encrypt data with our RSA public key. pub fn encrypt_data_with_public_key(encoded_public_key: &str, data: &str) -> String { - let decoded_public_key = base64_decode(&encoded_public_key); + let decoded_public_key = base64_decode(encoded_public_key); let rsa_public_key = construct_rsa_public_key(&decoded_public_key); - let encrypted_data = encrypt_with_public_key(&rsa_public_key, &data.as_bytes()); + let encrypted_data = encrypt_with_public_key(&rsa_public_key, data.as_bytes()); encrypted_data } /// Encrypt data with AES symm key. pub fn encrypt_data_with_shared_symmetric_key(encoded_symmetric_key: &str, data: &str) -> String { - let decoded_symmetric_key = base64_decode(&encoded_symmetric_key); + let decoded_symmetric_key = base64_decode(encoded_symmetric_key); let iv: [u8; 16] = [0x00; 16]; let mut cypher = construct_aes_key(&decoded_symmetric_key, &iv); - let encrypted_data = encrypt_data_with_aes_key(&mut cypher, &data.as_bytes()); + let encrypted_data = encrypt_data_with_aes_key(&mut cypher, data.as_bytes()); base64_encode(&encrypted_data) } /// Decrypt data with an encoded AES symm key. pub fn decrypt_data_with_shared_symmetric_key(encoded_symmetric_key: &str, data: &str) -> String { - let decoded_symmetric_key = base64_decode(&encoded_symmetric_key); + let decoded_symmetric_key = base64_decode(encoded_symmetric_key); let iv: [u8; 16] = [0x00; 16]; let mut cypher = construct_aes_key(&decoded_symmetric_key, &iv); - let decoded_data = base64_decode(&data); + let decoded_data = base64_decode(data); let decrypted_data = decrypt_data_with_aes_key(&mut cypher, &decoded_data); String::from_utf8(decrypted_data).expect("Unable to convert to UTF-8") } @@ -115,13 +113,13 @@ mod test { #[test] fn decrypt_private_key_test() { let self_encryption_key = decode_self_encryption_key(SELF_ENCRYPTION_KEY_ENCODED); - let result = decrypt_private_key(&PKAM_KEY_ENCRYPTED_AND_ENCODED, &self_encryption_key); + let result = decrypt_private_key(PKAM_KEY_ENCRYPTED_AND_ENCODED, &self_encryption_key); assert_eq!(result, PKAM_KEY_DECRYPTED_AND_ENCODED); } #[test] fn sign_challenge_test() { - let result = sign_challenge(CHALLENGE_TEXT, &PKAM_KEY_DECRYPTED_AND_ENCODED); + let result = sign_challenge(CHALLENGE_TEXT, PKAM_KEY_DECRYPTED_AND_ENCODED); assert_eq!(result, CHALLENGE_RESULT); } diff --git a/src/at_chops/mod.rs b/src/at_chops/mod.rs index f85f6c7..a17b577 100644 --- a/src/at_chops/mod.rs +++ b/src/at_chops/mod.rs @@ -1,4 +1,4 @@ -pub mod at_chops; +pub mod chops; mod b64_encoded_string; mod utils; diff --git a/src/at_chops/utils.rs b/src/at_chops/utils.rs index bbc73c3..0c3bf97 100644 --- a/src/at_chops/utils.rs +++ b/src/at_chops/utils.rs @@ -1,9 +1,9 @@ -use std::iter::repeat; +//use std::iter::repeat; use crypto::{aes::KeySize, symmetriccipher::SynchronousStreamCipher}; use base64::{engine::general_purpose, Engine as _}; -use log::info; +//use log::info; use rsa::{ pkcs1v15::SigningKey, pkcs8::{DecodePrivateKey, DecodePublicKey}, @@ -33,16 +33,14 @@ pub fn construct_aes_key(data: &[u8], iv: &[u8; 16]) -> Box RsaPrivateKey { - let rsa_key = RsaPrivateKey::from_pkcs8_der(&data).expect("Unable to create RSA Private Key"); + let rsa_key = RsaPrivateKey::from_pkcs8_der(data).expect("Unable to create RSA Private Key"); rsa_key.validate().expect("Invalid RSA Private Key"); rsa_key } /// Construct an RSA public key from a decoded key. pub fn construct_rsa_public_key(data: &[u8]) -> RsaPublicKey { - let rsa_key = - RsaPublicKey::from_public_key_der(&data).expect("Unable to create RSA Public Key"); - rsa_key + RsaPublicKey::from_public_key_der(data).expect("Unable to create RSA Public Key") } /// Sign data using an RSA private key. @@ -53,16 +51,15 @@ pub fn rsa_sign(key: RsaPrivateKey, data: &[u8]) -> String { let verifying_key = signing_key.verifying_key(); // Sign - let signature = signing_key.sign_with_rng(&mut rng, &data); + let signature = signing_key.sign_with_rng(&mut rng, data); verifying_key - .verify(&data, &signature) + .verify(data, &signature) .expect("failed to verify"); let binding = signature.to_bytes(); let signature_bytes = binding.as_ref(); // Encode signature - let sha256_signature_encoded = base64_encode(&signature_bytes); - sha256_signature_encoded + base64_encode(signature_bytes) } /// Create a new AES-256 key from scratch. @@ -116,7 +113,7 @@ pub fn decrypt_data_with_aes_key( data: &[u8], ) -> Vec { let mut output: Vec = vec![0; data.len()]; - aes_key.process(&data, &mut output); + aes_key.process(data, &mut output); // Remove padding due to PkCS#7 padding used by other SDKs let last = output.last().unwrap(); output.truncate(output.len() - usize::from(*last)); @@ -182,7 +179,7 @@ mod test { #[test] fn construct_rsa_private_key_test() { // Arrange - let private_key = base64_decode(&PKAM_KEY_DECRYPTED_AND_ENCODED); + let private_key = base64_decode(PKAM_KEY_DECRYPTED_AND_ENCODED); // Act let _ = construct_rsa_private_key(&private_key); // Assert it doesn't panic @@ -191,7 +188,7 @@ mod test { #[test] fn construct_rsa_public_key_test() { // Arrange - let public_key = base64_decode(&PUBLIC_ENCRYPTION_KEY); + let public_key = base64_decode(PUBLIC_ENCRYPTION_KEY); // Act let _ = construct_rsa_public_key(&public_key); // Assert it doesn't panic @@ -200,7 +197,7 @@ mod test { #[test] fn rsa_sign_test() { // Arrange - let private_key = base64_decode(&PKAM_KEY_DECRYPTED_AND_ENCODED); + let private_key = base64_decode(PKAM_KEY_DECRYPTED_AND_ENCODED); let rsa_key = construct_rsa_private_key(&private_key); // Act let decrypted = rsa_sign(rsa_key, CHALLENGE_TEXT.as_bytes()); @@ -216,7 +213,7 @@ mod test { #[test] fn encrypt_with_public_key_test() { - let public_key = base64_decode(&PUBLIC_ENCRYPTION_KEY); + let public_key = base64_decode(PUBLIC_ENCRYPTION_KEY); let public_key = construct_rsa_public_key(&public_key); let _ = encrypt_with_public_key(&public_key, &TEST_KEY_DECODED); // Assert it doesn't panic. diff --git a/src/at_client.rs b/src/at_client.rs index 7e6b124..573b1f5 100644 --- a/src/at_client.rs +++ b/src/at_client.rs @@ -1,6 +1,6 @@ use log::info; -use crate::at_chops::at_chops::{ +use crate::at_chops::chops::{ create_new_shared_symmetric_key, decrypt_data_with_shared_symmetric_key, decrypt_symmetric_key, encrypt_data_with_public_key, encrypt_data_with_shared_symmetric_key, }; @@ -59,7 +59,7 @@ impl AtClient { // Save for our use let encrypted_encoded_sym_key = encrypt_data_with_public_key(&self.secrets.encrypt_public_key, &new_key); - let _ = UpdateVerb::execute( + UpdateVerb::execute( &mut self.tls_client, UpdateVerbInputs::new( &self.at_sign, @@ -82,7 +82,7 @@ impl AtClient { symm_key_encrypted_with_recipient_public_key ); // Send data - let _ = UpdateVerb::execute( + UpdateVerb::execute( &mut self.tls_client, UpdateVerbInputs::new( &self.at_sign, @@ -96,9 +96,9 @@ impl AtClient { } else if response.contains("data") { info!("Already have a copy of the key"); // Decrypt symm key - let encrypted_symmetric_key = response.split(":").collect::>()[1]; + let encrypted_symmetric_key = response.split(':').collect::>()[1]; symm_key = - decrypt_symmetric_key(&encrypted_symmetric_key, &self.secrets.encrypt_private_key); + decrypt_symmetric_key(encrypted_symmetric_key, &self.secrets.encrypt_private_key); info!("Decrypted symmetric key: {}", symm_key); } else { return Err(AtError::new(String::from("Unknown response from server"))); @@ -110,7 +110,7 @@ impl AtClient { UpdateVerbInputs::new( &self.at_sign, // TODO: Pass this in as an option somewhere - &record_id, + record_id, &encrypted_data_to_send, Some(&self.namespace), None, @@ -128,7 +128,7 @@ impl AtClient { &mut self.tls_client, LookupVerbInputs::new(&from, record_id, Some(&self.namespace)), )?; - let encrypted_and_encoded_data = response.split(":").collect::>()[1]; + let encrypted_and_encoded_data = response.split(':').collect::>()[1]; info!("Fetching symmetric key"); // Fetch symm key let response = LookupVerb::execute( @@ -136,15 +136,15 @@ impl AtClient { LookupVerbInputs::new(&from, "shared_key", None), )?; info!("Decrypting symmetric key"); - let encrypted_and_encoded_symm_key = response.split(":").collect::>()[1]; + let encrypted_and_encoded_symm_key = response.split(':').collect::>()[1]; let symm_key = decrypt_symmetric_key( - &encrypted_and_encoded_symm_key, + encrypted_and_encoded_symm_key, &self.secrets.encrypt_private_key, ); info!("Decrypted symmetric key: {}", symm_key); info!("Decrypting data"); let encoded_data = - decrypt_data_with_shared_symmetric_key(&symm_key, &encrypted_and_encoded_data); + decrypt_data_with_shared_symmetric_key(&symm_key, encrypted_and_encoded_data); info!("Decrypted data: {}", encoded_data); Ok(()) @@ -183,7 +183,7 @@ fn get_at_sign_server_addr( // Trimming to remove the newline character let addr = addr.trim(); - let addr = addr.split(":").collect::>(); + let addr = addr.split(':').collect::>(); let host = addr[0].to_string(); let port = addr[1] .parse::() diff --git a/src/at_secrets.rs b/src/at_secrets.rs index ae48f1f..ac02247 100644 --- a/src/at_secrets.rs +++ b/src/at_secrets.rs @@ -1,4 +1,4 @@ -use crate::at_chops::at_chops::{decode_self_encryption_key, decrypt_private_key}; +use crate::at_chops::chops::{decode_self_encryption_key, decrypt_private_key}; use crate::at_error::Result; use log::info; use serde_json::{from_str, Value}; @@ -64,17 +64,17 @@ impl AtSecrets { ) -> Result { info!("Decoding keys"); // Decode the self encrypt key from base64 - let decoded_self_encrypted_key = decode_self_encryption_key(&aes_self_encrypt_key); + let decoded_self_encrypted_key = decode_self_encryption_key(aes_self_encrypt_key); // Use the key to decrypt all the other private keys let pkam_public_key = - decrypt_private_key(&aes_pkam_public_key, &decoded_self_encrypted_key); + decrypt_private_key(aes_pkam_public_key, &decoded_self_encrypted_key); let pkam_private_key = - decrypt_private_key(&aes_pkam_private_key, &decoded_self_encrypted_key); + decrypt_private_key(aes_pkam_private_key, &decoded_self_encrypted_key); let encrypt_public_key = - decrypt_private_key(&aes_encrypt_public_key, &decoded_self_encrypted_key); + decrypt_private_key(aes_encrypt_public_key, &decoded_self_encrypted_key); let encrypt_private_key = - decrypt_private_key(&aes_encrypt_private_key, &decoded_self_encrypted_key); + decrypt_private_key(aes_encrypt_private_key, &decoded_self_encrypted_key); info!("Keys decoded and decrypted"); diff --git a/src/verbs/from.rs b/src/verbs/from.rs index bdc38b8..3213685 100644 --- a/src/verbs/from.rs +++ b/src/verbs/from.rs @@ -1,6 +1,6 @@ use log::info; -use crate::at_chops::at_chops::sign_challenge; +use crate::at_chops::chops::sign_challenge; use super::{prelude::*, Verb}; @@ -29,7 +29,7 @@ impl<'a> Verb<'a> for FromVerb { let (_, data) = response.split_at(6); info!("Challenge: {}", data); - let signed_challenge = sign_challenge(&data, input.priv_pkam); + let signed_challenge = sign_challenge(data, input.priv_pkam); tls_client.send(format!("pkam:{}\n", signed_challenge))?; let response = tls_client.read_line()?; diff --git a/src/verbs/lookup.rs b/src/verbs/lookup.rs index b0fcd7f..ae50ed7 100644 --- a/src/verbs/lookup.rs +++ b/src/verbs/lookup.rs @@ -32,7 +32,7 @@ impl<'a> Verb<'a> for LookupVerb { send_string.push_str(&format!(".{}", namespace)); } send_string.push_str(&format!("@{}", input.to_at_sign.get_at_sign())); - send_string.push_str(&format!("\n")); + send_string.push('\n'); tls_client.send(send_string)?; let response = tls_client.read_line()?; Ok(response)