use crate::utils::*;
use botan_sys::*;
use crate::mp::MPI;
use crate::pk_ops::*;
use crate::rng::RandomNumberGenerator;
#[derive(Debug)]
pub struct Pubkey {
obj: botan_pubkey_t,
}
unsafe impl Sync for Pubkey {}
unsafe impl Send for Pubkey {}
botan_impl_drop!(Pubkey, botan_pubkey_destroy);
#[derive(Debug)]
pub struct Privkey {
obj: botan_privkey_t,
}
unsafe impl Sync for Privkey {}
unsafe impl Send for Privkey {}
botan_impl_drop!(Privkey, botan_privkey_destroy);
impl Privkey {
pub(crate) fn handle(&self) -> botan_privkey_t {
self.obj
}
pub fn create(alg: &str, params: &str, rng: &mut RandomNumberGenerator) -> Result<Privkey> {
let obj = botan_init!(
botan_privkey_create,
make_cstr(alg)?.as_ptr(),
make_cstr(params)?.as_ptr(),
rng.handle()
)?;
Ok(Privkey { obj })
}
pub fn create_elgamal(
p_bits: usize,
q_bits: usize,
rng: &mut RandomNumberGenerator,
) -> Result<Self> {
let obj = botan_init!(botan_privkey_create_elgamal, rng.handle(), p_bits, q_bits)?;
Ok(Self { obj })
}
pub fn create_dsa(
p_bits: usize,
q_bits: usize,
rng: &mut RandomNumberGenerator,
) -> Result<Self> {
let obj = botan_init!(botan_privkey_create_dsa, rng.handle(), p_bits, q_bits)?;
Ok(Self { obj })
}
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 })
}
pub fn load_ed25519(key: &[u8]) -> Result<Privkey> {
if key.len() != 32 {
return Err(Error::bad_parameter("Invalid input length"));
}
let obj = botan_init!(botan_privkey_load_ed25519, key.as_ptr())?;
Ok(Privkey { obj })
}
pub fn load_x25519(key: &[u8]) -> Result<Privkey> {
if key.len() != 32 {
return Err(Error::bad_parameter("Invalid input length"));
}
let obj = botan_init!(botan_privkey_load_x25519, key.as_ptr())?;
Ok(Privkey { obj })
}
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 })
}
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 })
}
pub fn load_dsa(p: &MPI, q: &MPI, g: &MPI, x: &MPI) -> Result<Privkey> {
let obj = botan_init!(
botan_privkey_load_dsa,
p.handle(),
q.handle(),
g.handle(),
x.handle()
)?;
Ok(Privkey { obj })
}
pub fn load_elgamal(p: &MPI, g: &MPI, x: &MPI) -> Result<Privkey> {
let obj = botan_init!(
botan_privkey_load_elgamal,
p.handle(),
g.handle(),
x.handle()
)?;
Ok(Privkey { obj })
}
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 })
}
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 })
}
pub fn load_der(der: &[u8]) -> Result<Privkey> {
let obj = botan_init!(
botan_privkey_load,
ptr::null_mut(),
der.as_ptr(),
der.len(),
ptr::null()
)?;
Ok(Privkey { obj })
}
pub fn load_pem(pem: &str) -> Result<Privkey> {
let cpem = make_cstr(pem)?;
let obj = botan_init!(
botan_privkey_load,
ptr::null_mut(),
cpem.as_ptr() as *const u8,
pem.len(),
ptr::null()
)?;
Ok(Privkey { obj })
}
pub fn load_encrypted_der(der: &[u8], passphrase: &str) -> Result<Privkey> {
let passphrase = make_cstr(passphrase)?;
let obj = botan_init!(
botan_privkey_load,
ptr::null_mut(),
der.as_ptr(),
der.len(),
passphrase.as_ptr()
)?;
Ok(Privkey { obj })
}
pub fn load_encrypted_pem(pem: &str, passphrase: &str) -> Result<Privkey> {
let passphrase = make_cstr(passphrase)?;
let cpem = make_cstr(pem)?;
let obj = botan_init!(
botan_privkey_load,
ptr::null_mut(),
cpem.as_ptr() as *const u8,
pem.len(),
passphrase.as_ptr()
)?;
Ok(Privkey { obj })
}
pub fn check_key(&self, rng: &mut RandomNumberGenerator) -> Result<bool> {
let flags = 1u32;
let rc = unsafe { botan_privkey_check_key(self.obj, rng.handle(), flags) };
if rc == 0 {
Ok(true)
} else if rc == -1 {
Ok(false)
} else {
Err(Error::from_rc(rc))
}
}
pub fn pubkey(&self) -> Result<Pubkey> {
let obj = botan_init!(botan_privkey_export_pubkey, self.obj)?;
Ok(Pubkey { obj })
}
pub fn algo_name(&self) -> Result<String> {
call_botan_ffi_returning_string(32, &|out_buf, out_len| unsafe {
botan_privkey_algo_name(self.obj, out_buf as *mut c_char, out_len)
})
}
pub fn der_encode(&self) -> Result<Vec<u8>> {
#[cfg(feature = "botan3")]
{
call_botan_ffi_viewing_vec_u8(&|ctx, cb| unsafe {
botan_privkey_view_der(self.obj, ctx, cb)
})
}
#[cfg(not(feature = "botan3"))]
{
call_botan_ffi_returning_vec_u8(4096, &|out_buf, out_len| unsafe {
botan_privkey_export(self.obj, out_buf, out_len, 0u32)
})
}
}
pub fn pem_encode(&self) -> Result<String> {
#[cfg(feature = "botan3")]
{
call_botan_ffi_viewing_str_fn(&|ctx, cb| unsafe {
botan_privkey_view_pem(self.obj, ctx, cb)
})
}
#[cfg(not(feature = "botan3"))]
{
call_botan_ffi_returning_string(4096, &|out_buf, out_len| unsafe {
botan_privkey_export(self.obj, out_buf, out_len, 1u32)
})
}
}
pub fn der_encode_encrypted(
&self,
passphrase: &str,
rng: &mut RandomNumberGenerator,
) -> Result<Vec<u8>> {
let iterations = 150_000;
self.der_encode_encrypted_with_options(
passphrase,
"AES-256/CBC",
"SHA-512",
iterations,
rng,
)
}
pub fn der_encode_encrypted_with_options(
&self,
passphrase: &str,
cipher: &str,
pbkdf: &str,
pbkdf_iter: usize,
rng: &mut RandomNumberGenerator,
) -> Result<Vec<u8>> {
let passphrase = make_cstr(passphrase)?;
let cipher = make_cstr(cipher)?;
let pbkdf = make_cstr(pbkdf)?;
let rng_handle = rng.handle();
#[cfg(feature = "botan3")]
{
call_botan_ffi_viewing_vec_u8(&|ctx, cb| unsafe {
botan_privkey_view_encrypted_der(
self.obj,
rng_handle,
passphrase.as_ptr(),
cipher.as_ptr(),
pbkdf.as_ptr(),
pbkdf_iter,
ctx,
cb,
)
})
}
#[cfg(not(feature = "botan3"))]
{
call_botan_ffi_returning_vec_u8(4096, &|out_buf, out_len| unsafe {
botan_privkey_export_encrypted_pbkdf_iter(
self.obj,
out_buf,
out_len,
rng_handle,
passphrase.as_ptr(),
pbkdf_iter,
cipher.as_ptr(),
pbkdf.as_ptr(),
0u32,
)
})
}
}
pub fn pem_encode_encrypted(
&self,
passphrase: &str,
rng: &mut RandomNumberGenerator,
) -> Result<String> {
let iterations = 150_000;
self.pem_encode_encrypted_with_options(
passphrase,
"AES-256/CBC",
"SHA-512",
iterations,
rng,
)
}
pub fn pem_encode_encrypted_with_options(
&self,
passphrase: &str,
cipher: &str,
pbkdf: &str,
pbkdf_iter: usize,
rng: &mut RandomNumberGenerator,
) -> Result<String> {
let passphrase = make_cstr(passphrase)?;
let cipher = make_cstr(cipher)?;
let pbkdf = make_cstr(pbkdf)?;
let rng_handle = rng.handle();
#[cfg(feature = "botan3")]
{
call_botan_ffi_viewing_str_fn(&|ctx, cb| unsafe {
botan_privkey_view_encrypted_pem(
self.obj,
rng_handle,
passphrase.as_ptr(),
cipher.as_ptr(),
pbkdf.as_ptr(),
pbkdf_iter,
ctx,
cb,
)
})
}
#[cfg(not(feature = "botan3"))]
{
call_botan_ffi_returning_string(4096, &|out_buf, out_len| unsafe {
botan_privkey_export_encrypted_pbkdf_iter(
self.obj,
out_buf,
out_len,
rng_handle,
passphrase.as_ptr(),
pbkdf_iter,
cipher.as_ptr(),
pbkdf.as_ptr(),
1u32,
)
})
}
}
pub fn key_agreement_key(&self) -> Result<Vec<u8>> {
#[cfg(feature = "botan3")]
{
call_botan_ffi_viewing_vec_u8(&|ctx, cb| unsafe {
botan_pk_op_key_agreement_view_public(self.obj, ctx, cb)
})
}
#[cfg(not(feature = "botan3"))]
{
let ka_key_len = 512; call_botan_ffi_returning_vec_u8(ka_key_len, &|out_buf, out_len| unsafe {
botan_pk_op_key_agreement_export_public(self.obj, out_buf, out_len)
})
}
}
pub fn get_field(&self, which: &str) -> Result<MPI> {
let which = make_cstr(which)?;
let r = MPI::new()?;
botan_call!(
botan_privkey_get_field,
r.handle(),
self.obj,
which.as_ptr()
)?;
Ok(r)
}
pub fn get_ed25519_key(&self) -> Result<(Vec<u8>, Vec<u8>)> {
let mut out = vec![0; 64];
botan_call!(
botan_privkey_ed25519_get_privkey,
self.obj,
out.as_mut_ptr()
)?;
let pubkey = out.split_off(32);
Ok((pubkey, out))
}
pub fn get_x25519_key(&self) -> Result<Vec<u8>> {
let mut out = vec![0; 32];
botan_call!(botan_privkey_x25519_get_privkey, self.obj, out.as_mut_ptr())?;
Ok(out)
}
pub fn sign(
&self,
message: &[u8],
padding: &str,
rng: &mut RandomNumberGenerator,
) -> Result<Vec<u8>> {
let mut signer = Signer::new(self, padding)?;
signer.update(message)?;
signer.finish(rng)
}
pub fn decrypt(&self, ctext: &[u8], padding: &str) -> Result<Vec<u8>> {
let mut decryptor = Decryptor::new(self, padding)?;
decryptor.decrypt(ctext)
}
pub fn agree(
&self,
other_key: &[u8],
output_len: usize,
salt: &[u8],
kdf: &str,
) -> Result<Vec<u8>> {
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 }
}
pub(crate) fn handle(&self) -> botan_pubkey_t {
self.obj
}
pub fn load_der(der: &[u8]) -> Result<Pubkey> {
let obj = botan_init!(botan_pubkey_load, der.as_ptr(), der.len())?;
Ok(Pubkey { obj })
}
pub fn load_pem(pem: &str) -> Result<Pubkey> {
let obj = botan_init!(
botan_pubkey_load,
make_cstr(pem)?.as_ptr() as *const u8,
pem.len()
)?;
Ok(Pubkey { obj })
}
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 })
}
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 })
}
pub fn load_dsa(p: &MPI, q: &MPI, g: &MPI, y: &MPI) -> Result<Pubkey> {
let obj = botan_init!(
botan_pubkey_load_dsa,
p.handle(),
q.handle(),
g.handle(),
y.handle()
)?;
Ok(Pubkey { obj })
}
pub fn load_elgamal(p: &MPI, g: &MPI, y: &MPI) -> Result<Pubkey> {
let obj = botan_init!(
botan_pubkey_load_elgamal,
p.handle(),
g.handle(),
y.handle()
)?;
Ok(Pubkey { obj })
}
pub fn load_ecdsa(pub_x: &MPI, pub_y: &MPI, curve_name: &str) -> Result<Pubkey> {
let curve_name = make_cstr(curve_name)?;
let obj = botan_init!(
botan_pubkey_load_ecdsa,
pub_x.handle(),
pub_y.handle(),
curve_name.as_ptr()
)?;
Ok(Pubkey { obj })
}
pub fn load_ecdh(pub_x: &MPI, pub_y: &MPI, curve_name: &str) -> Result<Pubkey> {
let curve_name = make_cstr(curve_name)?;
let obj = botan_init!(
botan_pubkey_load_ecdh,
pub_x.handle(),
pub_y.handle(),
curve_name.as_ptr()
)?;
Ok(Pubkey { obj })
}
pub fn load_ed25519(key: &[u8]) -> Result<Pubkey> {
let obj = botan_init!(botan_pubkey_load_ed25519, key.as_ptr())?;
Ok(Pubkey { obj })
}
pub fn load_x25519(key: &[u8]) -> Result<Pubkey> {
let obj = botan_init!(botan_pubkey_load_x25519, key.as_ptr())?;
Ok(Pubkey { obj })
}
pub fn estimated_strength(&self) -> Result<usize> {
botan_usize!(botan_pubkey_estimated_strength, self.obj)
}
pub fn check_key(&self, rng: &mut RandomNumberGenerator) -> Result<bool> {
let flags = 1u32;
let rc = unsafe { botan_pubkey_check_key(self.obj, rng.handle(), flags) };
if rc == 0 {
Ok(true)
} else if rc == -1 {
Ok(false)
} else {
Err(Error::from_rc(rc))
}
}
pub fn fingerprint(&self, hash: &str) -> Result<Vec<u8>> {
let hash = make_cstr(hash)?;
let fprint_len = 64; call_botan_ffi_returning_vec_u8(fprint_len, &|out_buf, out_len| unsafe {
botan_pubkey_fingerprint(self.obj, hash.as_ptr(), out_buf, out_len)
})
}
pub fn der_encode(&self) -> Result<Vec<u8>> {
#[cfg(feature = "botan3")]
{
call_botan_ffi_viewing_vec_u8(&|ctx, cb| unsafe {
botan_pubkey_view_der(self.obj, ctx, cb)
})
}
#[cfg(not(feature = "botan3"))]
{
let der_len = 4096; call_botan_ffi_returning_vec_u8(der_len, &|out_buf, out_len| unsafe {
botan_pubkey_export(self.obj, out_buf, out_len, 0u32)
})
}
}
pub fn pem_encode(&self) -> Result<String> {
#[cfg(feature = "botan3")]
{
call_botan_ffi_viewing_str_fn(&|ctx, cb| unsafe {
botan_pubkey_view_pem(self.obj, ctx, cb)
})
}
#[cfg(not(feature = "botan3"))]
{
let pem_len = 4096; call_botan_ffi_returning_string(pem_len, &|out_buf, out_len| unsafe {
botan_pubkey_export(self.obj, out_buf, out_len, 1u32)
})
}
}
#[cfg(feature = "botan3")]
pub fn ec_public_point(&self) -> Result<Vec<u8>> {
call_botan_ffi_viewing_vec_u8(&|ctx, cb| unsafe {
botan_pubkey_view_ec_public_point(self.obj, ctx, cb)
})
}
pub fn algo_name(&self) -> Result<String> {
call_botan_ffi_returning_string(32, &|out_buf, out_len| unsafe {
botan_pubkey_algo_name(self.obj, out_buf as *mut c_char, out_len)
})
}
pub fn get_field(&self, which: &str) -> Result<MPI> {
let which = make_cstr(which)?;
let r = MPI::new()?;
botan_call!(botan_pubkey_get_field, r.handle(), self.obj, which.as_ptr())?;
Ok(r)
}
pub fn get_ed25519_key(&self) -> Result<Vec<u8>> {
let mut out = vec![0; 32];
botan_call!(botan_pubkey_ed25519_get_pubkey, self.obj, out.as_mut_ptr())?;
Ok(out)
}
pub fn get_x25519_key(&self) -> Result<Vec<u8>> {
let mut out = vec![0; 32];
botan_call!(botan_pubkey_x25519_get_pubkey, self.obj, out.as_mut_ptr())?;
Ok(out)
}
pub fn encrypt(
&self,
message: &[u8],
padding: &str,
rng: &mut RandomNumberGenerator,
) -> Result<Vec<u8>> {
let mut op = Encryptor::new(self, padding)?;
op.encrypt(message, rng)
}
pub fn verify(&self, message: &[u8], signature: &[u8], padding: &str) -> Result<bool> {
let mut op = Verifier::new(self, padding)?;
op.update(message)?;
op.finish(signature)
}
}
pub fn pkcs_hash_id(hash_algo: &str) -> Result<Vec<u8>> {
let hash_algo = make_cstr(hash_algo)?;
let id_len = 32; call_botan_ffi_returning_vec_u8(id_len, &|out_buf, out_len| unsafe {
botan_pkcs_hash_id(hash_algo.as_ptr(), out_buf, out_len)
})
}