argon2/
types.rs

1use super::sys;
2
3/// Error type returned by all Rust wrappers of Argon2 functions.
4#[derive(Debug, PartialEq, Eq)]
5pub enum Error {
6    /// This error is returned whenever a bad parameter is passed in but doesn't make it past the
7    /// wrapper layer. e.g. a parameter that cannot be converted to the type required by the argon2
8    /// C library.
9    BadParam(&'static str),
10
11    /// An error returned from the argon2 C library in the form of an error code.
12    Code(ErrorCode),
13
14    /// An error occurred an argon2 but it has no Rust wrapper.
15    /// These are bugs in the library itself.
16    Unknown,
17}
18
19impl Error {
20    pub(crate) fn check_code(code: sys::Argon2_ErrorCodes) -> Result<(), Error> {
21        if code == 0 {
22            Ok(())
23        } else {
24            if let Some(err_code) = ErrorCode::from_c(code as sys::Argon2_ErrorCodes) {
25                Err(Error::Code(err_code))
26            } else {
27                Err(Error::Unknown)
28            }
29        }
30    }
31}
32
33/// Error code returned by failed Argon2 C functions.
34#[derive(Debug, Clone, Copy, PartialEq, Eq)]
35#[repr(i32)]
36pub enum ErrorCode {
37    OutputPtrNull = sys::Argon2_ErrorCodes_ARGON2_OUTPUT_PTR_NULL,
38    OutputTooShort = sys::Argon2_ErrorCodes_ARGON2_OUTPUT_TOO_SHORT,
39    OutputTooLong = sys::Argon2_ErrorCodes_ARGON2_OUTPUT_TOO_LONG,
40    PwdTooShort = sys::Argon2_ErrorCodes_ARGON2_PWD_TOO_SHORT,
41    PwdTooLong = sys::Argon2_ErrorCodes_ARGON2_PWD_TOO_LONG,
42    SaltTooShort = sys::Argon2_ErrorCodes_ARGON2_SALT_TOO_SHORT,
43    SaltTooLong = sys::Argon2_ErrorCodes_ARGON2_SALT_TOO_LONG,
44    AdTooShort = sys::Argon2_ErrorCodes_ARGON2_AD_TOO_SHORT,
45    AdTooLong = sys::Argon2_ErrorCodes_ARGON2_AD_TOO_LONG,
46    SecretTooShort = sys::Argon2_ErrorCodes_ARGON2_SECRET_TOO_SHORT,
47    SecretTooLong = sys::Argon2_ErrorCodes_ARGON2_SECRET_TOO_LONG,
48    TimeTooSmall = sys::Argon2_ErrorCodes_ARGON2_TIME_TOO_SMALL,
49    TimeTooLarge = sys::Argon2_ErrorCodes_ARGON2_TIME_TOO_LARGE,
50    MemoryTooLittle = sys::Argon2_ErrorCodes_ARGON2_MEMORY_TOO_LITTLE,
51    MemoryTooMuch = sys::Argon2_ErrorCodes_ARGON2_MEMORY_TOO_MUCH,
52    LanesTooFew = sys::Argon2_ErrorCodes_ARGON2_LANES_TOO_FEW,
53    LanesTooMany = sys::Argon2_ErrorCodes_ARGON2_LANES_TOO_MANY,
54    PwdPtrMismatch = sys::Argon2_ErrorCodes_ARGON2_PWD_PTR_MISMATCH,
55    SaltPtrMismatch = sys::Argon2_ErrorCodes_ARGON2_SALT_PTR_MISMATCH,
56    SecretPtrMismatch = sys::Argon2_ErrorCodes_ARGON2_SECRET_PTR_MISMATCH,
57    AdPtrMismatch = sys::Argon2_ErrorCodes_ARGON2_AD_PTR_MISMATCH,
58    MemoryAllocationError = sys::Argon2_ErrorCodes_ARGON2_MEMORY_ALLOCATION_ERROR,
59    FreeMemoryCbkNull = sys::Argon2_ErrorCodes_ARGON2_FREE_MEMORY_CBK_NULL,
60    AllocateMemoryCbkNull = sys::Argon2_ErrorCodes_ARGON2_ALLOCATE_MEMORY_CBK_NULL,
61    IncorrectParameter = sys::Argon2_ErrorCodes_ARGON2_INCORRECT_PARAMETER,
62    IncorrectType = sys::Argon2_ErrorCodes_ARGON2_INCORRECT_TYPE,
63    OutPtrMismatch = sys::Argon2_ErrorCodes_ARGON2_OUT_PTR_MISMATCH,
64    ThreadsTooFew = sys::Argon2_ErrorCodes_ARGON2_THREADS_TOO_FEW,
65    ThreadsTooMany = sys::Argon2_ErrorCodes_ARGON2_THREADS_TOO_MANY,
66    MissingArgs = sys::Argon2_ErrorCodes_ARGON2_MISSING_ARGS,
67    EncodingFail = sys::Argon2_ErrorCodes_ARGON2_ENCODING_FAIL,
68    DecodingFail = sys::Argon2_ErrorCodes_ARGON2_DECODING_FAIL,
69    ThreadFail = sys::Argon2_ErrorCodes_ARGON2_THREAD_FAIL,
70    DecodingLengthFail = sys::Argon2_ErrorCodes_ARGON2_DECODING_LENGTH_FAIL,
71    VerifyMismatch = sys::Argon2_ErrorCodes_ARGON2_VERIFY_MISMATCH,
72}
73
74impl ErrorCode {
75    /// Get the associated message for this error code.
76    pub fn message(self) -> &'static str {
77        super::error_message(self)
78    }
79
80    /// Converts an Argon2 error code into a Rust representation.
81    fn from_c(c_error_code: sys::Argon2_ErrorCodes) -> Option<ErrorCode> {
82        match c_error_code {
83            sys::Argon2_ErrorCodes_ARGON2_OUTPUT_PTR_NULL => Some(ErrorCode::OutputPtrNull),
84            sys::Argon2_ErrorCodes_ARGON2_OUTPUT_TOO_SHORT => Some(ErrorCode::OutputTooShort),
85            sys::Argon2_ErrorCodes_ARGON2_OUTPUT_TOO_LONG => Some(ErrorCode::OutputTooLong),
86            sys::Argon2_ErrorCodes_ARGON2_PWD_TOO_SHORT => Some(ErrorCode::PwdTooShort),
87            sys::Argon2_ErrorCodes_ARGON2_PWD_TOO_LONG => Some(ErrorCode::PwdTooLong),
88            sys::Argon2_ErrorCodes_ARGON2_SALT_TOO_SHORT => Some(ErrorCode::SaltTooShort),
89            sys::Argon2_ErrorCodes_ARGON2_SALT_TOO_LONG => Some(ErrorCode::SaltTooLong),
90            sys::Argon2_ErrorCodes_ARGON2_AD_TOO_SHORT => Some(ErrorCode::AdTooShort),
91            sys::Argon2_ErrorCodes_ARGON2_AD_TOO_LONG => Some(ErrorCode::AdTooLong),
92            sys::Argon2_ErrorCodes_ARGON2_SECRET_TOO_SHORT => Some(ErrorCode::SecretTooShort),
93            sys::Argon2_ErrorCodes_ARGON2_SECRET_TOO_LONG => Some(ErrorCode::SecretTooLong),
94            sys::Argon2_ErrorCodes_ARGON2_TIME_TOO_SMALL => Some(ErrorCode::TimeTooSmall),
95            sys::Argon2_ErrorCodes_ARGON2_TIME_TOO_LARGE => Some(ErrorCode::TimeTooLarge),
96            sys::Argon2_ErrorCodes_ARGON2_MEMORY_TOO_LITTLE => Some(ErrorCode::MemoryTooLittle),
97            sys::Argon2_ErrorCodes_ARGON2_MEMORY_TOO_MUCH => Some(ErrorCode::MemoryTooMuch),
98            sys::Argon2_ErrorCodes_ARGON2_LANES_TOO_FEW => Some(ErrorCode::LanesTooFew),
99            sys::Argon2_ErrorCodes_ARGON2_LANES_TOO_MANY => Some(ErrorCode::LanesTooMany),
100            sys::Argon2_ErrorCodes_ARGON2_PWD_PTR_MISMATCH => Some(ErrorCode::PwdPtrMismatch),
101            sys::Argon2_ErrorCodes_ARGON2_SALT_PTR_MISMATCH => Some(ErrorCode::SaltPtrMismatch),
102            sys::Argon2_ErrorCodes_ARGON2_SECRET_PTR_MISMATCH => Some(ErrorCode::SecretPtrMismatch),
103            sys::Argon2_ErrorCodes_ARGON2_AD_PTR_MISMATCH => Some(ErrorCode::AdPtrMismatch),
104            sys::Argon2_ErrorCodes_ARGON2_MEMORY_ALLOCATION_ERROR => Some(ErrorCode::MemoryAllocationError),
105            sys::Argon2_ErrorCodes_ARGON2_FREE_MEMORY_CBK_NULL => Some(ErrorCode::FreeMemoryCbkNull),
106            sys::Argon2_ErrorCodes_ARGON2_ALLOCATE_MEMORY_CBK_NULL => Some(ErrorCode::AllocateMemoryCbkNull),
107            sys::Argon2_ErrorCodes_ARGON2_INCORRECT_PARAMETER => Some(ErrorCode::IncorrectParameter),
108            sys::Argon2_ErrorCodes_ARGON2_INCORRECT_TYPE => Some(ErrorCode::IncorrectType),
109            sys::Argon2_ErrorCodes_ARGON2_OUT_PTR_MISMATCH => Some(ErrorCode::OutPtrMismatch),
110            sys::Argon2_ErrorCodes_ARGON2_THREADS_TOO_FEW => Some(ErrorCode::ThreadsTooFew),
111            sys::Argon2_ErrorCodes_ARGON2_THREADS_TOO_MANY => Some(ErrorCode::ThreadsTooMany),
112            sys::Argon2_ErrorCodes_ARGON2_MISSING_ARGS => Some(ErrorCode::MissingArgs),
113            sys::Argon2_ErrorCodes_ARGON2_ENCODING_FAIL => Some(ErrorCode::EncodingFail),
114            sys::Argon2_ErrorCodes_ARGON2_DECODING_FAIL => Some(ErrorCode::DecodingFail),
115            sys::Argon2_ErrorCodes_ARGON2_THREAD_FAIL => Some(ErrorCode::ThreadFail),
116            sys::Argon2_ErrorCodes_ARGON2_DECODING_LENGTH_FAIL => Some(ErrorCode::DecodingLengthFail),
117            sys::Argon2_ErrorCodes_ARGON2_VERIFY_MISMATCH => Some(ErrorCode::VerifyMismatch),
118
119            _ => None,
120        }
121    }
122
123    /// Converts a Rust representation of an Argon2 error code into the C error code.
124    pub(crate) fn to_c(self: ErrorCode) -> sys::Argon2_ErrorCodes {
125        match self {
126            ErrorCode::OutputPtrNull => sys::Argon2_ErrorCodes_ARGON2_OUTPUT_PTR_NULL,
127            ErrorCode::OutputTooShort => sys::Argon2_ErrorCodes_ARGON2_OUTPUT_TOO_SHORT,
128            ErrorCode::OutputTooLong => sys::Argon2_ErrorCodes_ARGON2_OUTPUT_TOO_LONG,
129            ErrorCode::PwdTooShort => sys::Argon2_ErrorCodes_ARGON2_PWD_TOO_SHORT,
130            ErrorCode::PwdTooLong => sys::Argon2_ErrorCodes_ARGON2_PWD_TOO_LONG,
131            ErrorCode::SaltTooShort => sys::Argon2_ErrorCodes_ARGON2_SALT_TOO_SHORT,
132            ErrorCode::SaltTooLong => sys::Argon2_ErrorCodes_ARGON2_SALT_TOO_LONG,
133            ErrorCode::AdTooShort => sys::Argon2_ErrorCodes_ARGON2_AD_TOO_SHORT,
134            ErrorCode::AdTooLong => sys::Argon2_ErrorCodes_ARGON2_AD_TOO_LONG,
135            ErrorCode::SecretTooShort => sys::Argon2_ErrorCodes_ARGON2_SECRET_TOO_SHORT,
136            ErrorCode::SecretTooLong => sys::Argon2_ErrorCodes_ARGON2_SECRET_TOO_LONG,
137            ErrorCode::TimeTooSmall => sys::Argon2_ErrorCodes_ARGON2_TIME_TOO_SMALL,
138            ErrorCode::TimeTooLarge => sys::Argon2_ErrorCodes_ARGON2_TIME_TOO_LARGE,
139            ErrorCode::MemoryTooLittle => sys::Argon2_ErrorCodes_ARGON2_MEMORY_TOO_LITTLE,
140            ErrorCode::MemoryTooMuch => sys::Argon2_ErrorCodes_ARGON2_MEMORY_TOO_MUCH,
141            ErrorCode::LanesTooFew => sys::Argon2_ErrorCodes_ARGON2_LANES_TOO_FEW,
142            ErrorCode::LanesTooMany => sys::Argon2_ErrorCodes_ARGON2_LANES_TOO_MANY,
143            ErrorCode::PwdPtrMismatch => sys::Argon2_ErrorCodes_ARGON2_PWD_PTR_MISMATCH,
144            ErrorCode::SaltPtrMismatch => sys::Argon2_ErrorCodes_ARGON2_SALT_PTR_MISMATCH,
145            ErrorCode::SecretPtrMismatch => sys::Argon2_ErrorCodes_ARGON2_SECRET_PTR_MISMATCH,
146            ErrorCode::AdPtrMismatch => sys::Argon2_ErrorCodes_ARGON2_AD_PTR_MISMATCH,
147            ErrorCode::MemoryAllocationError => sys::Argon2_ErrorCodes_ARGON2_MEMORY_ALLOCATION_ERROR,
148            ErrorCode::FreeMemoryCbkNull => sys::Argon2_ErrorCodes_ARGON2_FREE_MEMORY_CBK_NULL,
149            ErrorCode::AllocateMemoryCbkNull => sys::Argon2_ErrorCodes_ARGON2_ALLOCATE_MEMORY_CBK_NULL,
150            ErrorCode::IncorrectParameter => sys::Argon2_ErrorCodes_ARGON2_INCORRECT_PARAMETER,
151            ErrorCode::IncorrectType => sys::Argon2_ErrorCodes_ARGON2_INCORRECT_TYPE,
152            ErrorCode::OutPtrMismatch => sys::Argon2_ErrorCodes_ARGON2_OUT_PTR_MISMATCH,
153            ErrorCode::ThreadsTooFew => sys::Argon2_ErrorCodes_ARGON2_THREADS_TOO_FEW,
154            ErrorCode::ThreadsTooMany => sys::Argon2_ErrorCodes_ARGON2_THREADS_TOO_MANY,
155            ErrorCode::MissingArgs => sys::Argon2_ErrorCodes_ARGON2_MISSING_ARGS,
156            ErrorCode::EncodingFail => sys::Argon2_ErrorCodes_ARGON2_ENCODING_FAIL,
157            ErrorCode::DecodingFail => sys::Argon2_ErrorCodes_ARGON2_DECODING_FAIL,
158            ErrorCode::ThreadFail => sys::Argon2_ErrorCodes_ARGON2_THREAD_FAIL,
159            ErrorCode::DecodingLengthFail => sys::Argon2_ErrorCodes_ARGON2_DECODING_LENGTH_FAIL,
160            ErrorCode::VerifyMismatch => sys::Argon2_ErrorCodes_ARGON2_VERIFY_MISMATCH,
161        }
162    }
163}
164
165/// Argon2 primitive type.
166#[derive(Debug, Clone, Copy)]
167pub enum Variant {
168    D   = 0,
169    I   = 1,
170    ID  = 2,
171}
172
173impl Variant {
174    /// Converts from the C Variant type to the Rust Variant Type.
175    #[inline]
176    #[allow(dead_code)]
177    fn from_c(c_variant: sys::Argon2_type) -> Variant {
178        match c_variant {
179            sys::Argon2_type_Argon2_d   => Variant::D,
180            sys::Argon2_type_Argon2_i   => Variant::I,
181            sys::Argon2_type_Argon2_id  => Variant::ID,
182            _ => panic!("Unimplemented version {}", c_variant),
183        }
184    }
185
186    /// Converts from the Rust Variant type to the C Variant Type.
187    #[inline]
188    pub(crate) fn to_c(self) -> sys::Argon2_type {
189        match self {
190            Variant::D  => sys::Argon2_type_Argon2_d,
191            Variant::I  => sys::Argon2_type_Argon2_i,
192            Variant::ID => sys::Argon2_type_Argon2_id,
193        }
194    }
195}
196
197/// Version of the algorithm.
198#[derive(Debug, Clone, Copy)]
199pub enum Version {
200    /// Argon2 Version 0x10
201    Version10 = 0x10,
202
203    /// Argon2 Version 0x13
204    Version13 = 0x13,
205}
206
207impl Version {
208    /// Converts the version to an integer.
209    pub fn to_int(self) -> u32 {
210        match self {
211            Version::Version10 => 0x10,
212            Version::Version13 => 0x13,
213        }
214    }
215
216    /// Converts an integer to a Version if possible.
217    pub fn from_int(n: u32) -> Option<Version> {
218        match n {
219            0x10 => Some(Version::Version10),
220            0x13 => Some(Version::Version13),
221            _ => None,
222        }
223    }
224
225    /// Converts the C version type to the Rust version type.
226    #[inline]
227    #[allow(dead_code)]
228    pub(crate) fn from_c(c_version: sys::Argon2_version) -> Version {
229        match c_version {
230            sys::Argon2_version_ARGON2_VERSION_10 => Version::Version10,
231            sys::Argon2_version_ARGON2_VERSION_13 => Version::Version13,
232            _ => panic!("Unimplemented version 0x{:X}", c_version),
233        }
234    }
235
236    /// Converts the Rust version type to the C version type.
237    #[inline]
238    pub(crate) fn to_c(self) -> sys::Argon2_version {
239        match self {
240            Version::Version10 => sys::Argon2_version_ARGON2_VERSION_10,
241            Version::Version13 => sys::Argon2_version_ARGON2_VERSION_13,
242        }
243    }
244}
245
246impl Default for Version {
247    /// Returns the latest version of the algorithm.
248    fn default() -> Version {
249        Version::Version13
250    }
251}
252
253bitflags::bitflags! {
254    /// Flags which control fields are securely wiped (zeroed).
255    pub struct Flags: u32 {
256        /// No wipe.
257        const DEFAULT           = 0;
258        /// Wipe the password field.
259        const CLEAR_PASSWORD    = 1 << 0;
260        /// Wipe the secret field.
261        const CLEAR_SECRET      = 1 << 1;
262    }
263}
264
265/// Structure to hold Argon2 inputs.
266pub struct Context<'o, 'p, 'sa, 'se, 'ad> {
267    /// Output array.
268    pub out:    &'o mut [u8],
269    /// Password array.
270    pub pwd:    Option<&'p mut [u8]>,
271    /// Salt array.
272    pub salt:   Option<&'sa mut [u8]>,
273    /// Secret array.
274    pub secret: Option<&'se mut [u8]>,
275    /// Associated data array.
276    pub ad:     Option<&'ad mut [u8]>,
277
278    /// Number of passes.
279    pub t_cost: u32,
280    /// Amount of memory requested (KB)
281    pub m_cost: u32,
282    /// Number of lanes.
283    pub lanes:  u32,
284    /// Maximum number of threads.
285    pub threads:u32,
286
287    /// Version number.
288    pub version: Version,
289
290    /// Array of bool options
291    pub flags: Flags,
292}
293
294impl<'o, 'p, 'sa, 'se, 'ad> Context<'o, 'p, 'sa, 'se, 'ad> {
295    /// Minimum number of lanes (degree of parallelism).
296    pub const MIN_LANES: u32 = 1;
297    /// Maximum number of lanes (degree of parallelism).
298    pub const MAX_LANES: u32 = 0xFFFFFF;
299
300    /// Number of synchronization points between lanes per pass.
301    pub const SYNC_POINTS: u32 = 4;
302
303    /// Minimum number of threads.
304    pub const MIN_THREADS: u32 = 1;
305    /// Maximum number of threads.
306    pub const MAX_THREADS: u32 = 0xFFFFFF;
307
308    /// Minimum digest size in bytes.
309    pub const MIN_OUTLEN: u32 = 4;
310    /// Maximum digest size in bytes.
311    pub const MAX_OUTLEN: u32 = 0xFFFFFFFF;
312
313    /// Minimum number of passes.
314    pub const MIN_TIME: u32 = 1;
315    /// Maximum number of passes.
316    pub const MAX_TIME: u32 = 0xFFFFFFFF;
317
318    /// Minimum password length in bytes.
319    pub const MIN_PWD_LENGTH: u32 = 0;
320    /// Maximum password length in bytes.
321    pub const MAX_PWD_LENGTH: u32 = 0xFFFFFFFF;
322
323    /// Minimum associated data length in bytes.
324    pub const MIN_AD_LENGTH: u32 = 0;
325    /// Maximum associated data length in bytes.
326    pub const MAX_AD_LENGTH: u32 = 0xFFFFFFFF;
327
328    /// Minimum salt length in bytes.
329    pub const MIN_SALT_LENGTH: u32 = 8;
330    /// Maximum salt length in bytes.
331    pub const MAX_SALT_LENGTH: u32 = 0xFFFFFFFF;
332
333    /// Minimum key length in bytes.
334    pub const MIN_SECRET_LENGTH: u32 = 0;
335    /// Maximum key length in bytes.
336    pub const MAX_SECRET_LENGTH: u32 = 0xFFFFFFFF;
337
338    pub(crate) fn try_to_c(&mut self) -> Result<sys::Argon2_Context, Error> {
339        Ok(sys::Argon2_Context {
340            out: self.out.as_mut_ptr(),
341            outlen: try_conv("context.out.len", self.out.len())?,
342            pwd: opt_slice_ptr_mut(&mut self.pwd),
343            pwdlen: opt_slice_len_u32("context.pwd.len", &self.pwd)?,
344            salt: opt_slice_ptr_mut(&mut self.salt),
345            saltlen: opt_slice_len_u32("context.salt.len", &self.salt)?,
346            secret: opt_slice_ptr_mut(&mut self.secret),
347            secretlen: opt_slice_len_u32("context.secret.len", &self.secret)?,
348            ad: opt_slice_ptr_mut(&mut self.ad),
349            adlen: opt_slice_len_u32("context.ad.len", &self.ad)?,
350            t_cost: self.t_cost,
351            m_cost: self.m_cost,
352            lanes: self.lanes,
353            threads: self.threads,
354            version: self.version.to_c() as _,
355            allocate_cbk: None,
356            free_cbk: None,
357            flags: self.flags.bits(),
358        })
359    }
360}
361
362/// Structure to hold Argon2 inputs. Unlike `Context`, this version owns all of the input values.
363pub struct OwnedContext {
364    /// Output array.
365    pub out:    Vec<u8>,
366    /// Password array.
367    pub pwd:    Option<Vec<u8>>,
368    /// Salt array.
369    pub salt:   Option<Vec<u8>>,
370    /// Secret array.
371    pub secret: Option<Vec<u8>>,
372    /// Associated data array.
373    pub ad:     Option<Vec<u8>>,
374
375    /// Number of passes.
376    pub t_cost: u32,
377    /// Amount of memory requested (KB)
378    pub m_cost: u32,
379    /// Number of lanes.
380    pub lanes:  u32,
381    /// Maximum number of threads.
382    pub threads:u32,
383
384    /// Version number.
385    pub version: Version,
386
387    /// Array of bool options
388    pub flags: Flags,
389}
390
391impl OwnedContext {
392    pub fn borrowed<'a>(&'a mut self) -> Context<'a, 'a, 'a, 'a, 'a> {
393        Context {
394            out: &mut self.out,
395            pwd: self.pwd.as_mut().map(|v| &mut v[0..]),
396            salt: self.salt.as_mut().map(|v| &mut v[0..]),
397            secret: self.secret.as_mut().map(|v| &mut v[0..]),
398            ad: self.ad.as_mut().map(|v| &mut v[0..]),
399            t_cost: self.t_cost,
400            m_cost: self.m_cost,
401            lanes: self.lanes,
402            threads: self.threads,
403            version: self.version,
404            flags: self.flags.clone(),
405        }
406    }
407
408    pub(crate) fn try_to_c(&mut self) -> Result<sys::Argon2_Context, Error> {
409        Ok(sys::Argon2_Context {
410            out: self.out.as_mut_ptr(),
411            outlen: try_conv("context.out.len", self.out.len())?,
412            pwd: opt_slice_ptr_mut(&mut self.pwd),
413            pwdlen: opt_slice_len_u32("context.pwd.len", &self.pwd)?,
414            salt: opt_slice_ptr_mut(&mut self.salt),
415            saltlen: opt_slice_len_u32("context.salt.len", &self.salt)?,
416            secret: opt_slice_ptr_mut(&mut self.secret),
417            secretlen: opt_slice_len_u32("context.secret.len", &self.secret)?,
418            ad: opt_slice_ptr_mut(&mut self.ad),
419            adlen: opt_slice_len_u32("context.ad.len", &self.ad)?,
420            t_cost: self.t_cost,
421            m_cost: self.m_cost,
422            lanes: self.lanes,
423            threads: self.threads,
424            version: self.version.to_c() as _,
425            allocate_cbk: None,
426            free_cbk: None,
427            flags: self.flags.bits(),
428        })
429    }
430}
431
432impl<'o, 'p, 'sa, 'se, 'ad> std::convert::TryFrom<&mut Context<'o, 'p, 'sa, 'se, 'ad>> for sys::Argon2_Context {
433    type Error = self::Error;
434
435    fn try_from(context: &mut Context<'o, 'p, 'sa, 'se, 'ad>) -> Result<Self, Self::Error> {
436        context.try_to_c()
437    }
438}
439
440impl std::convert::TryFrom<&mut OwnedContext> for sys::Argon2_Context {
441    type Error = self::Error;
442
443    fn try_from(context: &mut OwnedContext) -> Result<Self, Self::Error> {
444        context.try_to_c()
445    }
446}
447
448/// Tries to convert between two types and returns a BadParam error on failure.
449#[inline]
450pub(crate) fn try_conv<T, U: std::convert::TryFrom<T>>(param: &'static str, input: T) -> Result<U, Error> {
451    U::try_from(input).map_err(|_| Error::BadParam(param))
452}
453
454/// Gets the length of a slice contained an in option (0 if none).
455#[inline]
456pub(crate) fn opt_slice_len<T, S: AsRef<[T]>>(opt: &Option<S>) -> usize {
457    opt.as_ref().map(|s| s.as_ref().len()).unwrap_or(0)
458}
459
460/// Gets the length of a slice contained in an option (0 if none) and tries to convert the size to
461/// a u32, returning an error on failure.
462#[inline]
463pub(crate) fn opt_slice_len_u32<T, S: AsRef<[T]>>(param: &'static str, opt: &Option<S>) -> Result<u32, Error> {
464    try_conv(param, opt.as_ref().map(|s| s.as_ref().len()).unwrap_or(0))
465}
466
467/// Converts an option containing a slice into a mutable pointer that is null if the option is
468/// None.
469#[inline]
470pub(crate) fn opt_slice_ptr_mut<T, S: AsMut<[T]>>(opt: &mut Option<S>) -> *mut T {
471    opt.as_mut()
472        .map(|s| s.as_mut().as_mut_ptr())
473        .unwrap_or(std::ptr::null_mut())
474}
475
476/// Converts an option containing a slice into a mutable pointer that is null if the option is
477/// None.
478#[inline]
479pub(crate) fn opt_slice_ptr<T, S: AsRef<[T]>>(opt: &Option<S>) -> *const T {
480    opt.as_ref()
481        .map(|s| s.as_ref().as_ptr())
482        .unwrap_or(std::ptr::null())
483}