From 096ccec741cc63cf3b9d4e6e230599c5c00274bc Mon Sep 17 00:00:00 2001 From: Jacob Kiers Date: Thu, 29 Feb 2024 19:20:24 +0100 Subject: [PATCH] Use crate rsa instead of openssl The rsa crate contains a pure rust implementation of the same primitives. This helps with cross platform support, such as Windows. Signed-off-by: Jacob Kiers --- Cargo.toml | 11 ++++++----- src/lib.rs | 48 ++++++++++++++++++++++++++++-------------------- 2 files changed, 34 insertions(+), 25 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 44cb907..835813f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,10 +11,11 @@ edition = "2018" [dependencies] anyhow = "1.0.32" -isahc = { version = "0.9.8", features = ["json"] } -dotenv = "0.15.0" -openssl = "0.10.30" -serde_json = "1.0.57" -serde = { version = "1.0.116", features = ["derive"] } base64 = "0.12.3" confy = "0.4.0" +dotenv = "0.15.0" +isahc = { version = "0.9.8", features = ["json"] } +rand = "0.8.5" +rsa = { version = "0.9.6", features = ["sha2"] } +serde = { version = "1.0.116", features = ["derive"] } +serde_json = "1.0.57" diff --git a/src/lib.rs b/src/lib.rs index 0d705ef..a72d2bd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,9 +1,12 @@ -use anyhow::Result; +use anyhow::{anyhow, Result}; +use isahc::http::StatusCode; use isahc::prelude::*; -use openssl::hash::MessageDigest; -use openssl::pkey::PKey; -use openssl::rsa::Rsa; -use openssl::sign::Signer; +use rsa::pkcs1::{DecodeRsaPrivateKey, EncodeRsaPrivateKey}; +use rsa::RsaPrivateKey; +use rsa::pkcs1v15::SigningKey; +use rsa::pkcs8::{EncodePublicKey, LineEnding}; +use rsa::signature::RandomizedSigner; +use rsa::sha2::Sha256; use serde::{de::DeserializeOwned, Deserialize, Serialize}; const BASE: &str = "https://api.bunq.com"; @@ -47,12 +50,11 @@ struct UserPerson { id: i64, } -fn sign(body: &str, key: &PKey) -> Result { - let mut signer = Signer::new(MessageDigest::sha256(), key)?; - - let sig = signer.sign_oneshot_to_vec(body.as_bytes())?; - - Ok(base64::encode(&sig)) +fn sign(body: &str, key: &RsaPrivateKey) -> Result { + let signing_key = SigningKey::::new(key.clone()); + let mut rng = rand::thread_rng(); + let signature = signing_key.sign_with_rng(&mut rng, body.as_bytes()); + Ok(base64::encode(signature.to_string())) } #[derive(Deserialize)] @@ -111,7 +113,7 @@ pub struct BunqConfig { } pub struct BunqConfigReady { token: String, - keypair: PKey, + keypair: RsaPrivateKey, user_id: i64, } impl BunqConfig { @@ -126,15 +128,14 @@ impl BunqConfig { let api_key = &self.api_key; let keypair = if let Some(state) = &self.state { - PKey::private_key_from_pem(state.pem_private.as_bytes())? + RsaPrivateKey::from_pkcs1_pem(&*state.pem_private)? } else { - let rsa = Rsa::generate(2048)?; - let pem_private = rsa.private_key_to_pem()?; - let pem_private = String::from_utf8(pem_private)?; + let mut rng = rand::thread_rng(); - let keypair = PKey::from_rsa(rsa)?; + let bits = 2048; + let keypair = RsaPrivateKey::new(&mut rng, bits).expect("failed to generate a key"); - let pem_public = String::from_utf8(keypair.public_key_to_pem()?)?; + let pem_public = keypair.to_public_key().to_public_key_pem(LineEnding::CRLF)?; let body = Installation { client_public_key: &pem_public, @@ -157,9 +158,15 @@ impl BunqConfig { .header("X-Bunq-Client-Authentication", &token) .body(body)? .send()?; - println!("{}", response.text()?); - self.state = Some(AppState { pem_private, token }); + let response_text = response.text()?; + println!("{}", response_text); + + if response.status() != StatusCode::OK { + return Err(anyhow!(response_text)); + } + + self.state = Some(AppState { pem_private: keypair.to_pkcs1_pem(LineEnding::CRLF)?.to_string(), token }); self.save()?; keypair @@ -175,6 +182,7 @@ impl BunqConfig { .send()? .text()?; let r: SessionServerResponse = deserialize_retarded_response(&response)?.response; + Ok(BunqConfigReady { keypair, token: r.token.token,