Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .ci/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def main(args = None):
print("ERROR: Unknown toolchain %s" % (toolchain))
return 1

features = [] if len(args) < 3 else args[2].split(',')
features = [] if len(args) < 3 else args[2].split('+')

for feat in features:
if feat not in KNOWN_FEATURES:
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,17 @@ jobs:
include:
- toolchain: stable
- toolchain: stable
features: no-std
features: no-std+git
- toolchain: stable
features: git
- toolchain: stable
features: vendored
- toolchain: 1.64.0 # MSRV no-std
features: no-std
features: no-std+git
- toolchain: 1.64.0 # MSRV
- toolchain: nightly
- toolchain: nightly
features: no-std
features: no-std+git

steps:
- run: sudo apt-get -qq install ccache libbotan-2-dev
Expand Down
5 changes: 4 additions & 1 deletion botan/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
#[macro_use]
extern crate alloc;

#[cfg(all(not(botan_ffi_20260303), not(feature = "std")))]
compile_error!("Building this crate no_std requires Botan 3.11.0 or higher");

extern crate botan_sys;

macro_rules! botan_call {
Expand Down Expand Up @@ -50,7 +53,7 @@ macro_rules! botan_init {
#[allow(unused)]
macro_rules! botan_init_at {
($fn:path, $($before:expr),* ; $($after:expr),*) => {{
let mut obj = std::ptr::null_mut();
let mut obj = ptr::null_mut();
let rc = unsafe {
$fn($($before,)* &mut obj $(, $after)*)
};
Expand Down
86 changes: 56 additions & 30 deletions botan/src/pubkey.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ use crate::rng::RandomNumberGenerator;
/// A public key object
pub struct Pubkey {
obj: botan_pubkey_t,
#[cfg(not(botan_ffi_20260303))]
op_lock: std::sync::Mutex<()>,
}

unsafe impl Sync for Pubkey {}
Expand All @@ -20,6 +22,8 @@ botan_impl_drop!(Pubkey, botan_pubkey_destroy);
/// A private key object
pub struct Privkey {
obj: botan_privkey_t,
#[cfg(not(botan_ffi_20260303))]
op_lock: std::sync::Mutex<()>,
}

unsafe impl Sync for Privkey {}
Expand All @@ -28,6 +32,14 @@ unsafe impl Send for Privkey {}
botan_impl_drop!(Privkey, botan_privkey_destroy);

impl Privkey {
fn from_obj(obj: botan_privkey_t) -> Self {
Self {
obj,
#[cfg(not(botan_ffi_20260303))]
op_lock: std::sync::Mutex::new(()),
}
}

pub(crate) fn handle(&self) -> botan_privkey_t {
self.obj
}
Expand All @@ -42,7 +54,7 @@ impl Privkey {
rng.handle()
)?;

Ok(Privkey { obj })
Ok(Privkey::from_obj(obj))
}

/// Create a new ElGamal private key with a random group
Expand All @@ -53,7 +65,7 @@ impl Privkey {
) -> Result<Self> {
let obj = botan_init!(botan_privkey_create_elgamal, rng.handle(), p_bits, q_bits)?;

Ok(Self { obj })
Ok(Privkey::from_obj(obj))
}

/// Create a new DSA private key with a random group
Expand All @@ -64,7 +76,7 @@ impl Privkey {
) -> Result<Self> {
let obj = botan_init!(botan_privkey_create_dsa, rng.handle(), p_bits, q_bits)?;

Ok(Self { obj })
Ok(Privkey::from_obj(obj))
}

/// Load an RSA private key (p,q,e)
Expand All @@ -80,7 +92,7 @@ impl Privkey {
/// ```
pub fn load_rsa(p: &MPI, q: &MPI, e: &MPI) -> Result<Privkey> {
let obj = botan_init!(botan_privkey_load_rsa, p.handle(), q.handle(), e.handle())?;
Ok(Privkey { obj })
Ok(Privkey::from_obj(obj))
}

/// Load an Ed25519 private key
Expand All @@ -96,7 +108,7 @@ impl Privkey {
return Err(Error::bad_parameter("Invalid input length"));
}
let obj = botan_init!(botan_privkey_load_ed25519, key.as_ptr())?;
Ok(Privkey { obj })
Ok(Privkey::from_obj(obj))
}

/// Load an X25519 private key
Expand All @@ -112,7 +124,7 @@ impl Privkey {
return Err(Error::bad_parameter("Invalid input length"));
}
let obj = botan_init!(botan_privkey_load_x25519, key.as_ptr())?;
Ok(Privkey { obj })
Ok(Privkey::from_obj(obj))
}

/// Load an X448 private key
Expand All @@ -128,20 +140,20 @@ impl Privkey {
pub fn load_x448(key: &[u8]) -> Result<Privkey> {
crate::ffi_version_guard!("load_x448", botan_ffi_20240408, [key], {
let obj = botan_init!(botan_privkey_load_x448, key.as_ptr())?;
Ok(Privkey { obj })
Ok(Privkey::from_obj(obj))
})
}

/// Load a PKCS#1 encoded RSA private key
pub fn load_rsa_pkcs1(pkcs1: &[u8]) -> Result<Privkey> {
let obj = botan_init!(botan_privkey_load_rsa_pkcs1, pkcs1.as_ptr(), pkcs1.len())?;
Ok(Privkey { obj })
Ok(Privkey::from_obj(obj))
}

/// Load an DH private key (p,g,x)
pub fn load_dh(p: &MPI, g: &MPI, x: &MPI) -> Result<Privkey> {
let obj = botan_init!(botan_privkey_load_dh, p.handle(), g.handle(), x.handle())?;
Ok(Privkey { obj })
Ok(Privkey::from_obj(obj))
}

/// Load an DSA private key (p,q,g,x)
Expand All @@ -153,7 +165,7 @@ impl Privkey {
g.handle(),
x.handle()
)?;
Ok(Privkey { obj })
Ok(Privkey::from_obj(obj))
}

/// Load an ElGamal private key (p,g,x)
Expand All @@ -164,21 +176,21 @@ impl Privkey {
g.handle(),
x.handle()
)?;
Ok(Privkey { obj })
Ok(Privkey::from_obj(obj))
}

/// Load an ECDSA private key with specified curve and secret scalar
pub fn load_ecdsa(s: &MPI, curve_name: &str) -> Result<Privkey> {
let curve_name = make_cstr(curve_name)?;
let obj = botan_init!(botan_privkey_load_ecdsa, s.handle(), curve_name.as_ptr())?;
Ok(Privkey { obj })
Ok(Privkey::from_obj(obj))
}

/// Load an ECDH private key with specified curve and secret scalar
pub fn load_ecdh(s: &MPI, curve_name: &str) -> Result<Privkey> {
let curve_name = make_cstr(curve_name)?;
let obj = botan_init!(botan_privkey_load_ecdh, s.handle(), curve_name.as_ptr())?;
Ok(Privkey { obj })
Ok(Privkey::from_obj(obj))
}

/// Load DER bytes as an unencrypted PKCS#8 private key
Expand All @@ -190,7 +202,7 @@ impl Privkey {
der.len(),
ptr::null()
)?;
Ok(Privkey { obj })
Ok(Privkey::from_obj(obj))
}

/// Load PEM string as an unencrypted PKCS#8 private key
Expand All @@ -204,7 +216,7 @@ impl Privkey {
ptr::null()
)?;

Ok(Privkey { obj })
Ok(Privkey::from_obj(obj))
}

/// Load DER bytes as an encrypted PKCS#8 private key
Expand All @@ -217,7 +229,7 @@ impl Privkey {
der.len(),
passphrase.as_ptr()
)?;
Ok(Privkey { obj })
Ok(Privkey::from_obj(obj))
}

/// Load PEM string as an encrypted PKCS#8 private key
Expand All @@ -232,7 +244,7 @@ impl Privkey {
passphrase.as_ptr()
)?;

Ok(Privkey { obj })
Ok(Privkey::from_obj(obj))
}

/// Check if the key seems to be valid
Expand All @@ -252,7 +264,7 @@ impl Privkey {
/// Return the public key associated with this private key
pub fn pubkey(&self) -> Result<Pubkey> {
let obj = botan_init!(botan_privkey_export_pubkey, self.obj)?;
Ok(Pubkey { obj })
Ok(Pubkey::from_handle(obj))
}

/// Return the name of the algorithm
Expand Down Expand Up @@ -522,13 +534,17 @@ impl Privkey {
padding: &str,
rng: &mut RandomNumberGenerator,
) -> Result<Vec<u8>> {
#[cfg(not(botan_ffi_20260303))]
let _lock = self.op_lock.lock().expect("lock poisoned");
let mut signer = Signer::new(self, padding)?;
signer.update(message)?;
signer.finish(rng)
}

/// Decrypt a message that was encrypted using the specified padding method
pub fn decrypt(&self, ctext: &[u8], padding: &str) -> Result<Vec<u8>> {
#[cfg(not(botan_ffi_20260303))]
let _lock = self.op_lock.lock().expect("lock poisoned");
let mut decryptor = Decryptor::new(self, padding)?;
decryptor.decrypt(ctext)
}
Expand All @@ -541,14 +557,20 @@ impl Privkey {
salt: &[u8],
kdf: &str,
) -> Result<Vec<u8>> {
#[cfg(not(botan_ffi_20260303))]
let _lock = self.op_lock.lock().expect("lock poisoned");
let mut op = KeyAgreement::new(self, kdf)?;
op.agree(output_len, other_key, salt)
}
}

impl Pubkey {
pub(crate) fn from_handle(obj: botan_pubkey_t) -> Pubkey {
Pubkey { obj }
Pubkey {
obj,
#[cfg(not(botan_ffi_20260303))]
op_lock: std::sync::Mutex::new(()),
}
}

pub(crate) fn handle(&self) -> botan_pubkey_t {
Expand All @@ -558,7 +580,7 @@ impl Pubkey {
/// Load a DER encoded public key
pub fn load_der(der: &[u8]) -> Result<Pubkey> {
let obj = botan_init!(botan_pubkey_load, der.as_ptr(), der.len())?;
Ok(Pubkey { obj })
Ok(Pubkey::from_handle(obj))
}

/// Load a PEM encoded public key
Expand All @@ -568,13 +590,13 @@ impl Pubkey {
make_cstr(pem)?.as_ptr() as *const u8,
pem.len()
)?;
Ok(Pubkey { obj })
Ok(Pubkey::from_handle(obj))
}

/// Load an RSA public key (n,e)
pub fn load_rsa(n: &MPI, e: &MPI) -> Result<Pubkey> {
let obj = botan_init!(botan_pubkey_load_rsa, n.handle(), e.handle())?;
Ok(Pubkey { obj })
Ok(Pubkey::from_handle(obj))
}

/// Load a PKCS#1 encoded RSA public key
Expand All @@ -587,7 +609,7 @@ impl Pubkey {
/// Load an DH public key (p,g,y)
pub fn load_dh(p: &MPI, g: &MPI, y: &MPI) -> Result<Pubkey> {
let obj = botan_init!(botan_pubkey_load_dh, p.handle(), g.handle(), y.handle())?;
Ok(Pubkey { obj })
Ok(Pubkey::from_handle(obj))
}

/// Load an DSA public key (p,q,g,y)
Expand All @@ -599,7 +621,7 @@ impl Pubkey {
g.handle(),
y.handle()
)?;
Ok(Pubkey { obj })
Ok(Pubkey::from_handle(obj))
}

/// Load an ElGamal public key (p,g,y)
Expand All @@ -610,7 +632,7 @@ impl Pubkey {
g.handle(),
y.handle()
)?;
Ok(Pubkey { obj })
Ok(Pubkey::from_handle(obj))
}

/// Load an ECDSA public key (x,y) for the specified curve
Expand All @@ -622,7 +644,7 @@ impl Pubkey {
pub_y.handle(),
curve_name.as_ptr()
)?;
Ok(Pubkey { obj })
Ok(Pubkey::from_handle(obj))
}

/// Load an ECDH public key (x,y) for the specified curve
Expand All @@ -634,19 +656,19 @@ impl Pubkey {
pub_y.handle(),
curve_name.as_ptr()
)?;
Ok(Pubkey { obj })
Ok(Pubkey::from_handle(obj))
}

/// Load an Ed25519 public key
pub fn load_ed25519(key: &[u8]) -> Result<Pubkey> {
let obj = botan_init!(botan_pubkey_load_ed25519, key.as_ptr())?;
Ok(Pubkey { obj })
Ok(Pubkey::from_handle(obj))
}

/// Load an X25519 key
pub fn load_x25519(key: &[u8]) -> Result<Pubkey> {
let obj = botan_init!(botan_pubkey_load_x25519, key.as_ptr())?;
Ok(Pubkey { obj })
Ok(Pubkey::from_handle(obj))
}

/// Load a ML-KEM public key from the raw byte encoding
Expand All @@ -669,7 +691,7 @@ impl Pubkey {
key.len(),
params.as_ptr()
)?;
Ok(Pubkey { obj })
Ok(Pubkey::from_handle(obj))
})
}

Expand Down Expand Up @@ -815,12 +837,16 @@ impl Pubkey {
padding: &str,
rng: &mut RandomNumberGenerator,
) -> Result<Vec<u8>> {
#[cfg(not(botan_ffi_20260303))]
let _lock = self.op_lock.lock().expect("lock poisoned");
let mut op = Encryptor::new(self, padding)?;
op.encrypt(message, rng)
}

/// Verify a message that was signed using the specified padding method
pub fn verify(&self, message: &[u8], signature: &[u8], padding: &str) -> Result<bool> {
#[cfg(not(botan_ffi_20260303))]
let _lock = self.op_lock.lock().expect("lock poisoned");
let mut op = Verifier::new(self, padding)?;
op.update(message)?;
op.finish(signature)
Expand Down
Loading
Loading