1#![doc(html_root_url = "https://docs.rs/abcrypt-py/0.3.0/")]
8#![forbid(unsafe_code)]
10#![deny(missing_docs)]
11#![allow(clippy::redundant_pub_crate)]
13
14mod error;
15mod params;
16
17use std::borrow::Cow;
18
19use abcrypt::argon2::{self, Algorithm, Version};
20use pyo3::{
21 Bound, PyResult, exceptions::PyValueError, prelude::PyModuleMethods, pyclass, pyfunction,
22 pymethods, pymodule, types::PyModule, wrap_pyfunction,
23};
24
25use crate::error::Error;
26pub use crate::params::Params;
27
28#[derive(Clone, Copy, Debug)]
30#[pyclass]
31pub struct Format;
32
33#[pymethods]
34impl Format {
35 #[classattr]
37 pub const HEADER_SIZE: usize = abcrypt::HEADER_SIZE;
38
39 #[classattr]
41 pub const TAG_SIZE: usize = abcrypt::TAG_SIZE;
42}
43
44#[inline]
54#[pyfunction]
55pub fn encrypt<'a>(plaintext: &[u8], passphrase: &[u8]) -> PyResult<Cow<'a, [u8]>> {
56 let ciphertext = abcrypt::encrypt(plaintext, passphrase).map_err(Error::from)?;
57 Ok(ciphertext.into())
58}
59
60#[inline]
73#[pyfunction]
74pub fn encrypt_with_params<'a>(
75 plaintext: &[u8],
76 passphrase: &[u8],
77 memory_cost: u32,
78 time_cost: u32,
79 parallelism: u32,
80) -> PyResult<Cow<'a, [u8]>> {
81 let params = argon2::Params::new(memory_cost, time_cost, parallelism, None)
82 .map_err(|e| PyValueError::new_err(e.to_string()))?;
83 let ciphertext =
84 abcrypt::encrypt_with_params(plaintext, passphrase, params).map_err(Error::from)?;
85 Ok(ciphertext.into())
86}
87
88#[inline]
100#[pyfunction]
101pub fn encrypt_with_context<'a>(
102 plaintext: &[u8],
103 passphrase: &[u8],
104 argon2_type: u32,
105 argon2_version: u32,
106 memory_cost: u32,
107 time_cost: u32,
108 parallelism: u32,
109) -> PyResult<Cow<'a, [u8]>> {
110 let argon2_type = match argon2_type {
111 0 => Ok(Algorithm::Argon2d),
112 1 => Ok(Algorithm::Argon2i),
113 2 => Ok(Algorithm::Argon2id),
114 t => Err(abcrypt::Error::InvalidArgon2Type(t)),
115 }
116 .map_err(Error::from)?;
117 let argon2_version =
118 Version::try_from(argon2_version).map_err(|e| PyValueError::new_err(e.to_string()))?;
119 let params = argon2::Params::new(memory_cost, time_cost, parallelism, None)
120 .map_err(|e| PyValueError::new_err(e.to_string()))?;
121 let ciphertext =
122 abcrypt::encrypt_with_context(plaintext, passphrase, argon2_type, argon2_version, params)
123 .map_err(Error::from)?;
124 Ok(ciphertext.into())
125}
126
127#[inline]
144#[pyfunction]
145pub fn decrypt<'a>(ciphertext: &[u8], passphrase: &[u8]) -> PyResult<Cow<'a, [u8]>> {
146 let plaintext = abcrypt::decrypt(ciphertext, passphrase).map_err(Error::from)?;
147 Ok(plaintext.into())
148}
149
150#[pymodule]
152fn abcrypt_py(m: &Bound<'_, PyModule>) -> PyResult<()> {
153 m.add_function(wrap_pyfunction!(encrypt, m)?)?;
154 m.add_function(wrap_pyfunction!(encrypt_with_params, m)?)?;
155 m.add_function(wrap_pyfunction!(encrypt_with_context, m)?)?;
156 m.add_function(wrap_pyfunction!(decrypt, m)?)?;
157 m.add_class::<Params>()?;
158 m.add_class::<Format>()?;
159 Ok(())
160}