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 <code@kiers.eu>
This commit is contained in:
Jacob Kiers 2024-02-29 19:20:24 +01:00
parent fc71b73ce2
commit 096ccec741
2 changed files with 34 additions and 25 deletions

View File

@ -11,10 +11,11 @@ edition = "2018"
[dependencies] [dependencies]
anyhow = "1.0.32" 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" base64 = "0.12.3"
confy = "0.4.0" 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"

View File

@ -1,9 +1,12 @@
use anyhow::Result; use anyhow::{anyhow, Result};
use isahc::http::StatusCode;
use isahc::prelude::*; use isahc::prelude::*;
use openssl::hash::MessageDigest; use rsa::pkcs1::{DecodeRsaPrivateKey, EncodeRsaPrivateKey};
use openssl::pkey::PKey; use rsa::RsaPrivateKey;
use openssl::rsa::Rsa; use rsa::pkcs1v15::SigningKey;
use openssl::sign::Signer; use rsa::pkcs8::{EncodePublicKey, LineEnding};
use rsa::signature::RandomizedSigner;
use rsa::sha2::Sha256;
use serde::{de::DeserializeOwned, Deserialize, Serialize}; use serde::{de::DeserializeOwned, Deserialize, Serialize};
const BASE: &str = "https://api.bunq.com"; const BASE: &str = "https://api.bunq.com";
@ -47,12 +50,11 @@ struct UserPerson {
id: i64, id: i64,
} }
fn sign<K: openssl::pkey::HasPrivate>(body: &str, key: &PKey<K>) -> Result<String> { fn sign(body: &str, key: &RsaPrivateKey) -> Result<String> {
let mut signer = Signer::new(MessageDigest::sha256(), key)?; let signing_key = SigningKey::<Sha256>::new(key.clone());
let mut rng = rand::thread_rng();
let sig = signer.sign_oneshot_to_vec(body.as_bytes())?; let signature = signing_key.sign_with_rng(&mut rng, body.as_bytes());
Ok(base64::encode(signature.to_string()))
Ok(base64::encode(&sig))
} }
#[derive(Deserialize)] #[derive(Deserialize)]
@ -111,7 +113,7 @@ pub struct BunqConfig {
} }
pub struct BunqConfigReady { pub struct BunqConfigReady {
token: String, token: String,
keypair: PKey<openssl::pkey::Private>, keypair: RsaPrivateKey,
user_id: i64, user_id: i64,
} }
impl BunqConfig { impl BunqConfig {
@ -126,15 +128,14 @@ impl BunqConfig {
let api_key = &self.api_key; let api_key = &self.api_key;
let keypair = if let Some(state) = &self.state { 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 { } else {
let rsa = Rsa::generate(2048)?; let mut rng = rand::thread_rng();
let pem_private = rsa.private_key_to_pem()?;
let pem_private = String::from_utf8(pem_private)?;
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 { let body = Installation {
client_public_key: &pem_public, client_public_key: &pem_public,
@ -157,9 +158,15 @@ impl BunqConfig {
.header("X-Bunq-Client-Authentication", &token) .header("X-Bunq-Client-Authentication", &token)
.body(body)? .body(body)?
.send()?; .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()?; self.save()?;
keypair keypair
@ -175,6 +182,7 @@ impl BunqConfig {
.send()? .send()?
.text()?; .text()?;
let r: SessionServerResponse = deserialize_retarded_response(&response)?.response; let r: SessionServerResponse = deserialize_retarded_response(&response)?.response;
Ok(BunqConfigReady { Ok(BunqConfigReady {
keypair, keypair,
token: r.token.token, token: r.token.token,