1use crate::error::ErrorStack;
12use native_ossl_sys as sys;
13use std::ffi::CStr;
14
15pub struct KdfAlg {
21 ptr: *mut sys::EVP_KDF,
22}
23
24impl KdfAlg {
25 pub fn fetch(name: &CStr) -> Result<Self, ErrorStack> {
33 let ptr =
34 unsafe { sys::EVP_KDF_fetch(std::ptr::null_mut(), name.as_ptr(), std::ptr::null()) };
35 if ptr.is_null() {
36 return Err(ErrorStack::drain());
37 }
38 Ok(KdfAlg { ptr })
39 }
40
41 fn as_ptr(&self) -> *mut sys::EVP_KDF {
42 self.ptr
43 }
44}
45
46impl Drop for KdfAlg {
47 fn drop(&mut self) {
48 unsafe { sys::EVP_KDF_free(self.ptr) };
49 }
50}
51
52unsafe impl Send for KdfAlg {}
54unsafe impl Sync for KdfAlg {}
55
56pub struct KdfCtx {
62 ptr: *mut sys::EVP_KDF_CTX,
63}
64
65impl KdfCtx {
66 pub fn new(alg: &KdfAlg) -> Result<Self, ErrorStack> {
70 let ptr = unsafe { sys::EVP_KDF_CTX_new(alg.as_ptr()) };
71 if ptr.is_null() {
72 return Err(ErrorStack::drain());
73 }
74 Ok(KdfCtx { ptr })
75 }
76
77 pub fn derive(
83 &mut self,
84 out: &mut [u8],
85 params: &crate::params::Params<'_>,
86 ) -> Result<(), ErrorStack> {
87 crate::ossl_call!(sys::EVP_KDF_derive(
88 self.ptr,
89 out.as_mut_ptr(),
90 out.len(),
91 params.as_ptr()
92 ))
93 }
94}
95
96impl Drop for KdfCtx {
97 fn drop(&mut self) {
98 unsafe { sys::EVP_KDF_CTX_free(self.ptr) };
99 }
100}
101
102unsafe impl Send for KdfCtx {}
103
104#[derive(Default, Clone, Copy, PartialEq, Eq)]
108pub enum HkdfMode {
109 #[default]
113 ExtractAndExpand,
114 ExtractOnly,
116 ExpandOnly,
118}
119
120impl HkdfMode {
121 fn as_uint(self) -> u32 {
122 match self {
123 HkdfMode::ExtractAndExpand => 0,
124 HkdfMode::ExtractOnly => 1,
125 HkdfMode::ExpandOnly => 2,
126 }
127 }
128}
129
130pub struct HkdfBuilder<'a> {
142 digest: &'a crate::digest::DigestAlg,
143 key: Option<&'a [u8]>,
144 salt: Option<&'a [u8]>,
145 info: Option<&'a [u8]>,
146 mode: HkdfMode,
147}
148
149impl<'a> HkdfBuilder<'a> {
150 #[must_use]
154 pub fn new(digest: &'a crate::digest::DigestAlg) -> Self {
155 HkdfBuilder {
156 digest,
157 key: None,
158 salt: None,
159 info: None,
160 mode: HkdfMode::default(),
161 }
162 }
163
164 #[must_use]
166 pub fn key(mut self, key: &'a [u8]) -> Self {
167 self.key = Some(key);
168 self
169 }
170
171 #[must_use]
173 pub fn salt(mut self, salt: &'a [u8]) -> Self {
174 self.salt = Some(salt);
175 self
176 }
177
178 #[must_use]
180 pub fn info(mut self, info: &'a [u8]) -> Self {
181 self.info = Some(info);
182 self
183 }
184
185 #[must_use]
187 pub fn mode(mut self, mode: HkdfMode) -> Self {
188 self.mode = mode;
189 self
190 }
191
192 pub fn derive(self, out: &mut [u8]) -> Result<(), ErrorStack> {
196 let name_ptr = unsafe { sys::OBJ_nid2sn(self.digest.nid()) };
197 if name_ptr.is_null() {
198 return Err(ErrorStack::drain());
199 }
200 let name = unsafe { CStr::from_ptr(name_ptr) };
201
202 let mut builder = crate::params::ParamBuilder::new()?
203 .push_utf8_string(c"digest", name)?
204 .push_uint(c"mode", self.mode.as_uint())?;
205
206 if let Some(k) = self.key {
207 builder = builder.push_octet_slice(c"key", k)?;
208 }
209 if let Some(s) = self.salt {
210 builder = builder.push_octet_slice(c"salt", s)?;
211 }
212 if let Some(i) = self.info {
213 builder = builder.push_octet_slice(c"info", i)?;
214 }
215
216 let params = builder.build()?;
217 let alg = KdfAlg::fetch(c"HKDF")?;
218 KdfCtx::new(&alg)?.derive(out, ¶ms)
219 }
220
221 pub fn derive_to_vec(self, len: usize) -> Result<Vec<u8>, ErrorStack> {
225 let mut out = vec![0u8; len];
226 self.derive(&mut out)?;
227 Ok(out)
228 }
229}
230
231pub struct Pbkdf2Builder<'a> {
241 digest: &'a crate::digest::DigestAlg,
242 password: &'a [u8],
243 salt: &'a [u8],
244 iterations: u32,
245}
246
247impl<'a> Pbkdf2Builder<'a> {
248 #[must_use]
253 pub fn new(digest: &'a crate::digest::DigestAlg, password: &'a [u8], salt: &'a [u8]) -> Self {
254 Pbkdf2Builder {
255 digest,
256 password,
257 salt,
258 iterations: 600_000,
259 }
260 }
261
262 #[must_use]
264 pub fn iterations(mut self, n: u32) -> Self {
265 self.iterations = n;
266 self
267 }
268
269 pub fn derive(self, out: &mut [u8]) -> Result<(), ErrorStack> {
273 let name_ptr = unsafe { sys::OBJ_nid2sn(self.digest.nid()) };
274 if name_ptr.is_null() {
275 return Err(ErrorStack::drain());
276 }
277 let name = unsafe { CStr::from_ptr(name_ptr) };
278
279 let params = crate::params::ParamBuilder::new()?
280 .push_octet_slice(c"pass", self.password)?
281 .push_octet_slice(c"salt", self.salt)?
282 .push_uint(c"iter", self.iterations)?
283 .push_utf8_string(c"digest", name)?
284 .build()?;
285
286 let alg = KdfAlg::fetch(c"PBKDF2")?;
287 KdfCtx::new(&alg)?.derive(out, ¶ms)
288 }
289
290 pub fn derive_to_vec(self, len: usize) -> Result<Vec<u8>, ErrorStack> {
294 let mut out = vec![0u8; len];
295 self.derive(&mut out)?;
296 Ok(out)
297 }
298}
299
300pub struct ScryptParams {
309 pub n: u64,
311 pub r: u32,
313 pub p: u32,
315}
316
317impl Default for ScryptParams {
318 fn default() -> Self {
319 ScryptParams {
321 n: 16_384,
322 r: 8,
323 p: 1,
324 }
325 }
326}
327
328pub struct ScryptBuilder<'a> {
336 password: &'a [u8],
337 salt: &'a [u8],
338 params: ScryptParams,
339}
340
341impl<'a> ScryptBuilder<'a> {
342 #[must_use]
346 pub fn new(password: &'a [u8], salt: &'a [u8]) -> Self {
347 ScryptBuilder {
348 password,
349 salt,
350 params: ScryptParams::default(),
351 }
352 }
353
354 #[must_use]
356 pub fn params(mut self, params: ScryptParams) -> Self {
357 self.params = params;
358 self
359 }
360
361 pub fn derive(self, out: &mut [u8]) -> Result<(), ErrorStack> {
365 let params = crate::params::ParamBuilder::new()?
366 .push_octet_slice(c"pass", self.password)?
367 .push_octet_slice(c"salt", self.salt)?
368 .push_uint64(c"n", self.params.n)?
369 .push_uint(c"r", self.params.r)?
370 .push_uint(c"p", self.params.p)?
371 .build()?;
372
373 let alg = KdfAlg::fetch(c"SCRYPT")?;
374 KdfCtx::new(&alg)?.derive(out, ¶ms)
375 }
376
377 pub fn derive_to_vec(self, len: usize) -> Result<Vec<u8>, ErrorStack> {
381 let mut out = vec![0u8; len];
382 self.derive(&mut out)?;
383 Ok(out)
384 }
385}
386
387#[cfg(ossl350)]
391#[derive(Clone, Copy, Debug, PartialEq, Eq)]
392pub enum SshkdfKeyType {
393 InitialIvClientToServer,
395 InitialIvServerToClient,
397 EncryptionKeyClientToServer,
399 EncryptionKeyServerToClient,
401 IntegrityKeyClientToServer,
403 IntegrityKeyServerToClient,
405}
406
407#[cfg(ossl350)]
408impl SshkdfKeyType {
409 fn as_cstr(self) -> &'static CStr {
410 match self {
411 Self::InitialIvClientToServer => c"A",
412 Self::InitialIvServerToClient => c"B",
413 Self::EncryptionKeyClientToServer => c"C",
414 Self::EncryptionKeyServerToClient => c"D",
415 Self::IntegrityKeyClientToServer => c"E",
416 Self::IntegrityKeyServerToClient => c"F",
417 }
418 }
419}
420
421#[cfg(ossl350)]
429pub struct SshkdfBuilder<'a> {
430 digest: &'a crate::digest::DigestAlg,
431 key: &'a [u8],
432 xcghash: &'a [u8],
433 session_id: &'a [u8],
434 key_type: SshkdfKeyType,
435}
436
437#[cfg(ossl350)]
438impl<'a> SshkdfBuilder<'a> {
439 #[must_use]
447 pub fn new(
448 digest: &'a crate::digest::DigestAlg,
449 key: &'a [u8],
450 xcghash: &'a [u8],
451 session_id: &'a [u8],
452 key_type: SshkdfKeyType,
453 ) -> Self {
454 SshkdfBuilder {
455 digest,
456 key,
457 xcghash,
458 session_id,
459 key_type,
460 }
461 }
462
463 pub fn derive(self, out: &mut [u8]) -> Result<(), ErrorStack> {
467 let name_ptr = unsafe { sys::OBJ_nid2sn(self.digest.nid()) };
468 if name_ptr.is_null() {
469 return Err(ErrorStack::drain());
470 }
471 let name = unsafe { CStr::from_ptr(name_ptr) };
472
473 let params = crate::params::ParamBuilder::new()?
474 .push_utf8_string(c"digest", name)?
475 .push_octet_slice(c"key", self.key)?
476 .push_octet_slice(c"xcghash", self.xcghash)?
477 .push_octet_slice(c"session-id", self.session_id)?
478 .push_utf8_string(c"type", self.key_type.as_cstr())?
479 .build()?;
480
481 let alg = KdfAlg::fetch(c"SSHKDF")?;
482 KdfCtx::new(&alg)?.derive(out, ¶ms)
483 }
484
485 pub fn derive_to_vec(self, len: usize) -> Result<Vec<u8>, ErrorStack> {
489 let mut out = vec![0u8; len];
490 self.derive(&mut out)?;
491 Ok(out)
492 }
493}
494
495#[cfg(ossl350)]
499#[derive(Clone, Copy, Debug, PartialEq, Eq)]
500pub enum KbkdfMode {
501 Counter,
503 Feedback,
505}
506
507#[cfg(ossl350)]
508impl KbkdfMode {
509 fn as_cstr(self) -> &'static CStr {
510 match self {
511 KbkdfMode::Counter => c"counter",
512 KbkdfMode::Feedback => c"feedback",
513 }
514 }
515}
516
517#[cfg(ossl350)]
519#[derive(Clone, Copy, Debug, PartialEq, Eq)]
520#[cfg_attr(ossl350, derive(Default))]
521pub enum KbkdfCounterLen {
522 Bits8 = 8,
524 Bits16 = 16,
526 Bits24 = 24,
528 #[cfg_attr(ossl350, default)]
530 Bits32 = 32,
531}
532
533#[cfg(ossl350)]
545pub struct KbkdfBuilder<'a> {
546 mode: KbkdfMode,
547 mac: &'a crate::mac::MacAlg,
548 digest: Option<&'a crate::digest::DigestAlg>,
549 key: &'a [u8],
550 label: Option<&'a [u8]>,
551 context: Option<&'a [u8]>,
552 salt: Option<&'a [u8]>,
554 counter_len: KbkdfCounterLen,
555 use_l: Option<bool>,
556 use_separator: Option<bool>,
557}
558
559#[cfg(ossl350)]
560impl<'a> KbkdfBuilder<'a> {
561 #[must_use]
567 pub fn new(mode: KbkdfMode, mac: &'a crate::mac::MacAlg, key: &'a [u8]) -> Self {
568 KbkdfBuilder {
569 mode,
570 mac,
571 digest: None,
572 key,
573 label: None,
574 context: None,
575 salt: None,
576 counter_len: KbkdfCounterLen::default(),
577 use_l: None,
578 use_separator: None,
579 }
580 }
581
582 #[must_use]
584 pub fn digest(mut self, digest: &'a crate::digest::DigestAlg) -> Self {
585 self.digest = Some(digest);
586 self
587 }
588
589 #[must_use]
591 pub fn label(mut self, label: &'a [u8]) -> Self {
592 self.label = Some(label);
593 self
594 }
595
596 #[must_use]
598 pub fn context(mut self, context: &'a [u8]) -> Self {
599 self.context = Some(context);
600 self
601 }
602
603 #[must_use]
605 pub fn salt(mut self, salt: &'a [u8]) -> Self {
606 self.salt = Some(salt);
607 self
608 }
609
610 #[must_use]
612 pub fn counter_len(mut self, len: KbkdfCounterLen) -> Self {
613 self.counter_len = len;
614 self
615 }
616
617 #[must_use]
619 pub fn use_l(mut self, enabled: bool) -> Self {
620 self.use_l = Some(enabled);
621 self
622 }
623
624 #[must_use]
626 pub fn use_separator(mut self, enabled: bool) -> Self {
627 self.use_separator = Some(enabled);
628 self
629 }
630
631 pub fn derive(self, out: &mut [u8]) -> Result<(), ErrorStack> {
635 let mut builder = crate::params::ParamBuilder::new()?
636 .push_utf8_string(c"mode", self.mode.as_cstr())?
637 .push_utf8_string(c"mac", self.mac.name())?
638 .push_octet_slice(c"key", self.key)?
639 .push_uint(c"r", self.counter_len as u32)?;
640
641 if let Some(d) = self.digest {
642 let name_ptr = unsafe { sys::OBJ_nid2sn(d.nid()) };
643 if name_ptr.is_null() {
644 return Err(ErrorStack::drain());
645 }
646 let name = unsafe { CStr::from_ptr(name_ptr) };
647 builder = builder.push_utf8_string(c"digest", name)?;
648 }
649 if let Some(l) = self.label {
650 builder = builder.push_octet_slice(c"label", l)?;
651 }
652 if let Some(c) = self.context {
653 builder = builder.push_octet_slice(c"data", c)?;
654 }
655 if let Some(s) = self.salt {
656 builder = builder.push_octet_slice(c"salt", s)?;
657 }
658 if let Some(v) = self.use_l {
659 builder = builder.push_int(c"use-l", i32::from(v))?;
660 }
661 if let Some(v) = self.use_separator {
662 builder = builder.push_int(c"use-separator", i32::from(v))?;
663 }
664
665 let params = builder.build()?;
666 let alg = KdfAlg::fetch(c"KBKDF")?;
667 KdfCtx::new(&alg)?.derive(out, ¶ms)
668 }
669
670 pub fn derive_to_vec(self, len: usize) -> Result<Vec<u8>, ErrorStack> {
674 let mut out = vec![0u8; len];
675 self.derive(&mut out)?;
676 Ok(out)
677 }
678}
679
680#[derive(Clone, Copy, Debug, PartialEq, Eq)]
686pub enum Pkcs12KdfId {
687 Key = 1,
689 Iv = 2,
691 Mac = 3,
693}
694
695pub struct Pkcs12KdfBuilder<'a> {
708 md: &'a crate::digest::DigestAlg,
709 password: &'a [u8],
710 salt: &'a [u8],
711 id: Pkcs12KdfId,
712 iter: u32,
713}
714
715impl<'a> Pkcs12KdfBuilder<'a> {
716 #[must_use]
726 pub fn new(
727 md: &'a crate::digest::DigestAlg,
728 password: &'a [u8],
729 salt: &'a [u8],
730 id: Pkcs12KdfId,
731 ) -> Self {
732 Self {
733 md,
734 password,
735 salt,
736 id,
737 iter: 2048,
738 }
739 }
740
741 #[must_use]
743 pub fn iterations(mut self, n: u32) -> Self {
744 self.iter = n;
745 self
746 }
747
748 pub fn derive(&self, out: &mut [u8]) -> Result<(), ErrorStack> {
757 let rc = unsafe {
761 sys::PKCS12_key_gen_utf8(
762 self.password.as_ptr().cast(),
763 i32::try_from(self.password.len()).expect("password too long"),
764 self.salt.as_ptr().cast_mut(),
765 i32::try_from(self.salt.len()).expect("salt too long"),
766 self.id as std::ffi::c_int,
767 self.iter.cast_signed(),
768 i32::try_from(out.len()).expect("output too long"),
769 out.as_mut_ptr(),
770 self.md.as_ptr(),
771 )
772 };
773 if rc != 1 {
774 return Err(ErrorStack::drain());
775 }
776 Ok(())
777 }
778
779 pub fn derive_to_vec(&self, len: usize) -> Result<Vec<u8>, ErrorStack> {
784 let mut out = vec![0u8; len];
785 self.derive(&mut out)?;
786 Ok(out)
787 }
788}
789
790#[cfg(test)]
793mod tests {
794 use super::*;
795 use crate::digest::DigestAlg;
796
797 #[test]
804 fn hkdf_sha256_rfc5869_tc1() {
805 let digest = DigestAlg::fetch(c"SHA2-256", None).unwrap();
806
807 let ikm = [0x0b_u8; 22];
808 let salt = [
809 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c_u8,
810 ];
811 let info = [
812 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9_u8,
813 ];
814
815 let okm = HkdfBuilder::new(&digest)
816 .key(&ikm)
817 .salt(&salt)
818 .info(&info)
819 .derive_to_vec(42)
820 .unwrap();
821
822 assert_eq!(
823 hex::encode(&okm),
824 "3cb25f25faacd57a90434f64d0362f2a\
825 2d2d0a90cf1a5a4c5db02d56ecc4c5bf\
826 34007208d5b887185865"
827 );
828 }
829
830 #[test]
837 fn hkdf_sha256_no_salt_no_info() {
838 let digest = DigestAlg::fetch(c"SHA2-256", None).unwrap();
839 let ikm = [0x0b_u8; 22];
840
841 let okm = HkdfBuilder::new(&digest)
842 .key(&ikm)
843 .derive_to_vec(42)
844 .unwrap();
845
846 assert_eq!(
847 hex::encode(&okm),
848 "8da4e775a563c18f715f802a063c5a31\
849 b8a11f5c5ee1879ec3454e5f3c738d2d\
850 9d201395faa4b61a96c8"
851 );
852 }
853
854 #[test]
861 fn pbkdf2_sha256_known_answer() {
862 let digest = DigestAlg::fetch(c"SHA2-256", None).unwrap();
863
864 let dk = Pbkdf2Builder::new(&digest, b"password", b"salt")
865 .iterations(1)
866 .derive_to_vec(32)
867 .unwrap();
868
869 assert_eq!(
870 hex::encode(&dk),
871 "120fb6cffcf8b32c43e7225256c4f837\
872 a86548c92ccc35480805987cb70be17b"
873 );
874 }
875
876 #[test]
880 fn scrypt_derives_nonzero_output() {
881 let dk = ScryptBuilder::new(b"password", b"salt")
882 .params(ScryptParams { n: 32, r: 1, p: 1 })
883 .derive_to_vec(32)
884 .unwrap();
885
886 assert_eq!(dk.len(), 32);
887 assert_ne!(dk, vec![0u8; 32]);
888 }
889
890 #[test]
892 fn scrypt_different_passwords_differ() {
893 let p = ScryptParams { n: 32, r: 1, p: 1 };
894
895 let dk1 = ScryptBuilder::new(b"pass1", b"salt")
896 .params(ScryptParams {
897 n: p.n,
898 r: p.r,
899 p: p.p,
900 })
901 .derive_to_vec(32)
902 .unwrap();
903 let dk2 = ScryptBuilder::new(b"pass2", b"salt")
904 .params(ScryptParams {
905 n: p.n,
906 r: p.r,
907 p: p.p,
908 })
909 .derive_to_vec(32)
910 .unwrap();
911
912 assert_ne!(dk1, dk2);
913 }
914
915 #[test]
920 fn pkcs12_kdf_basic() {
921 let sha1 = DigestAlg::fetch(c"SHA1", None).unwrap();
922 let salt = b"saltsalt";
923
924 let key = Pkcs12KdfBuilder::new(&sha1, b"password", salt, Pkcs12KdfId::Key)
925 .iterations(2048)
926 .derive_to_vec(24)
927 .unwrap();
928 assert_eq!(key.len(), 24);
929 assert_ne!(key, vec![0u8; 24]);
930
931 let key2 = Pkcs12KdfBuilder::new(&sha1, b"password", salt, Pkcs12KdfId::Key)
933 .iterations(2048)
934 .derive_to_vec(24)
935 .unwrap();
936 assert_eq!(key, key2);
937
938 let iv = Pkcs12KdfBuilder::new(&sha1, b"password", salt, Pkcs12KdfId::Iv)
940 .iterations(2048)
941 .derive_to_vec(8)
942 .unwrap();
943 assert_ne!(key[..8], iv[..]);
944 }
945
946 #[test]
948 fn pkcs12_kdf_different_passwords_differ() {
949 let sha1 = DigestAlg::fetch(c"SHA1", None).unwrap();
950 let salt = b"saltsalt";
951
952 let k1 = Pkcs12KdfBuilder::new(&sha1, b"pass1", salt, Pkcs12KdfId::Key)
953 .derive_to_vec(24)
954 .unwrap();
955 let k2 = Pkcs12KdfBuilder::new(&sha1, b"pass2", salt, Pkcs12KdfId::Key)
956 .derive_to_vec(24)
957 .unwrap();
958 assert_ne!(k1, k2);
959 }
960}