1extern crate argon2;
48extern crate libc;
49
50use argon2::{Config, Error, ThreadMode, Variant, Version};
51use libc::{c_char, size_t, uint8_t, int32_t, uint32_t};
52use std::{ptr, slice};
53use std::ffi::CStr;
54use std::io::{Cursor, Write};
55
56
57#[no_mangle]
59pub static ARGON2D: uint32_t = Variant::Argon2d as uint32_t;
60
61#[no_mangle]
63pub static ARGON2I: uint32_t = Variant::Argon2i as uint32_t;
64
65#[no_mangle]
67pub static ARGON2ID: uint32_t = Variant::Argon2id as uint32_t;
68
69#[no_mangle]
71pub static VERSION10: uint32_t = Version::Version10 as uint32_t;
72
73#[no_mangle]
75pub static VERSION13: uint32_t = Version::Version13 as uint32_t;
76
77
78const DEF_HASH_LEN: usize = 32;
79const DEF_LANES: u32 = 1;
80const DEF_MEMORY: u32 = 4096;
81const DEF_PARALLELISM: u32 = 1;
82const DEF_THREADS: u32 = 1;
83const DEF_TIME: u32 = 3;
84const DEF_VARIANT: u32 = Variant::Argon2i as u32;
85const DEF_VERSION: u32 = Version::Version13 as u32;
86
87
88#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)]
89enum ReturnValue {
90 Ok = 0,
91 OutputPtrNull = -1,
92 OutputTooShort = -2,
93 OutputTooLong = -3,
94 PwdTooShort = -4,
95 PwdTooLong = -5,
96 SaltTooShort = -6,
97 SaltTooLong = -7,
98 AdTooShort = -8,
99 AdTooLong = -9,
100 SecretTooShort = -10,
101 SecretTooLong = -11,
102 TimeTooSmall = -12,
103 TimeTooLarge = -13,
104 MemoryTooLittle = -14,
105 MemoryTooMuch = -15,
106 LanesTooFew = -16,
107 LanesTooMany = -17,
108 PwdPtrMismatch = -18,
109 SaltPtrMismatch = -19,
110 SecretPtrMismatch = -20,
111 AdPtrMismatch = -21,
112 IncorrectType = -26,
113 EncodingFail = -31,
114 DecodingFail = -32,
115 VerifyMismatch = -35,
116 HashPtrMismatch = -36,
117}
118
119impl ReturnValue {
120 pub fn from_error(error: Error) -> ReturnValue {
121 match error {
122 Error::OutputTooShort => ReturnValue::OutputTooShort,
123 Error::OutputTooLong => ReturnValue::OutputTooLong,
124 Error::PwdTooShort => ReturnValue::PwdTooShort,
125 Error::PwdTooLong => ReturnValue::PwdTooLong,
126 Error::SaltTooShort => ReturnValue::SaltTooShort,
127 Error::SaltTooLong => ReturnValue::SaltTooLong,
128 Error::AdTooShort => ReturnValue::AdTooShort,
129 Error::AdTooLong => ReturnValue::AdTooLong,
130 Error::SecretTooShort => ReturnValue::SecretTooShort,
131 Error::SecretTooLong => ReturnValue::SecretTooLong,
132 Error::TimeTooSmall => ReturnValue::TimeTooSmall,
133 Error::TimeTooLarge => ReturnValue::TimeTooLarge,
134 Error::MemoryTooLittle => ReturnValue::MemoryTooLittle,
135 Error::MemoryTooMuch => ReturnValue::MemoryTooMuch,
136 Error::LanesTooFew => ReturnValue::LanesTooFew,
137 Error::LanesTooMany => ReturnValue::LanesTooMany,
138 Error::IncorrectType => ReturnValue::IncorrectType,
139 Error::IncorrectVersion => ReturnValue::IncorrectType,
140 Error::DecodingFail => ReturnValue::DecodingFail,
141 }
142 }
143}
144
145#[no_mangle]
147pub extern "C" fn encoded_len(
148 variant: uint32_t,
149 mem_cost: uint32_t,
150 time_cost: uint32_t,
151 parallelism: uint32_t,
152 salt_len: uint32_t,
153 hash_len: uint32_t
154) -> uint32_t {
155 let variant = match Variant::from_u32(variant) {
156 Ok(val) => val,
157 Err(_) => Variant::Argon2id,
158 };
159 argon2::encoded_len(variant, mem_cost, time_cost, parallelism, salt_len, hash_len) + 1
160}
161
162#[no_mangle]
164pub extern "C" fn encoded_len_simple(salt_len: uint32_t) -> uint32_t {
165 encoded_len(DEF_VARIANT, DEF_MEMORY, DEF_TIME, DEF_PARALLELISM, salt_len, DEF_HASH_LEN as u32)
166}
167
168#[no_mangle]
170pub extern "C" fn hash_encoded(
171 variant: uint32_t,
172 version: uint32_t,
173 mem_cost: uint32_t,
174 time_cost: uint32_t,
175 lanes: uint32_t,
176 threads: uint32_t,
177 pwd: *const uint8_t,
178 pwd_len: size_t,
179 salt: *const uint8_t,
180 salt_len: size_t,
181 secret: *const uint8_t,
182 secret_len: size_t,
183 ad: *const uint8_t,
184 ad_len: size_t,
185 hash_len: size_t,
186 encoded: *mut c_char,
187 encoded_len: size_t
188) -> int32_t {
189 let pwd = match mk_slice(pwd, pwd_len, ReturnValue::PwdPtrMismatch) {
190 Ok(val) => val,
191 Err(err) => return err as i32,
192 };
193
194 let salt = match mk_slice(salt, salt_len, ReturnValue::SaltPtrMismatch) {
195 Ok(val) => val,
196 Err(err) => return err as i32,
197 };
198
199 if encoded.is_null() {
200 return ReturnValue::EncodingFail as i32;
201 }
202
203 let config = match mk_config(variant,
204 version,
205 mem_cost,
206 time_cost,
207 lanes,
208 threads,
209 secret,
210 secret_len,
211 ad,
212 ad_len,
213 hash_len) {
214 Ok(val) => val,
215 Err(err) => return err as i32,
216 };
217
218 match argon2::hash_encoded(pwd, salt, &config) {
219 Ok(string) => {
220 let bytes = string.into_bytes();
221 let null = [0u8];
222 if bytes.len() + null.len() != encoded_len {
223 return ReturnValue::EncodingFail as i32;
224 }
225
226 let out = unsafe { slice::from_raw_parts_mut(encoded as *mut u8, encoded_len) };
227
228 let mut cursor = Cursor::new(out);
229 if cursor.write(&bytes).is_err() {
230 return ReturnValue::EncodingFail as i32;
231 }
232 if cursor.write(&null).is_err() {
233 return ReturnValue::EncodingFail as i32;
234 }
235 ReturnValue::Ok as i32
236 }
237 Err(err) => ReturnValue::from_error(err) as i32,
238 }
239}
240
241#[no_mangle]
243pub extern "C" fn hash_encoded_argon2d(
244 mem_cost: uint32_t,
245 time_cost: uint32_t,
246 parallelism: uint32_t,
247 pwd: *const uint8_t,
248 pwd_len: size_t,
249 salt: *const uint8_t,
250 salt_len: size_t,
251 hash_len: size_t,
252 encoded: *mut c_char,
253 encoded_len: size_t
254) -> int32_t {
255 hash_encoded(Variant::Argon2d as u32,
256 DEF_VERSION,
257 mem_cost,
258 time_cost,
259 parallelism,
260 parallelism,
261 pwd,
262 pwd_len,
263 salt,
264 salt_len,
265 ptr::null(),
266 0,
267 ptr::null(),
268 0,
269 hash_len,
270 encoded,
271 encoded_len)
272}
273
274#[no_mangle]
276pub extern "C" fn hash_encoded_argon2i(
277 mem_cost: uint32_t,
278 time_cost: uint32_t,
279 parallelism: uint32_t,
280 pwd: *const uint8_t,
281 pwd_len: size_t,
282 salt: *const uint8_t,
283 salt_len: size_t,
284 hash_len: size_t,
285 encoded: *mut c_char,
286 encoded_len: size_t
287) -> int32_t {
288 hash_encoded(Variant::Argon2i as u32,
289 DEF_VERSION,
290 mem_cost,
291 time_cost,
292 parallelism,
293 parallelism,
294 pwd,
295 pwd_len,
296 salt,
297 salt_len,
298 ptr::null(),
299 0,
300 ptr::null(),
301 0,
302 hash_len,
303 encoded,
304 encoded_len)
305}
306
307#[no_mangle]
309pub extern "C" fn hash_encoded_argon2id(
310 mem_cost: uint32_t,
311 time_cost: uint32_t,
312 parallelism: uint32_t,
313 pwd: *const uint8_t,
314 pwd_len: size_t,
315 salt: *const uint8_t,
316 salt_len: size_t,
317 hash_len: size_t,
318 encoded: *mut c_char,
319 encoded_len: size_t
320) -> int32_t {
321 hash_encoded(Variant::Argon2id as u32,
322 DEF_VERSION,
323 mem_cost,
324 time_cost,
325 parallelism,
326 parallelism,
327 pwd,
328 pwd_len,
329 salt,
330 salt_len,
331 ptr::null(),
332 0,
333 ptr::null(),
334 0,
335 hash_len,
336 encoded,
337 encoded_len)
338}
339
340#[no_mangle]
342pub extern "C" fn hash_encoded_simple(
343 pwd: *const uint8_t,
344 pwd_len: size_t,
345 salt: *const uint8_t,
346 salt_len: size_t,
347 encoded: *mut c_char,
348 encoded_len: size_t
349) -> int32_t {
350 hash_encoded(DEF_VARIANT,
351 DEF_VERSION,
352 DEF_MEMORY,
353 DEF_TIME,
354 DEF_LANES,
355 DEF_THREADS,
356 pwd,
357 pwd_len,
358 salt,
359 salt_len,
360 ptr::null(),
361 0,
362 ptr::null(),
363 0,
364 DEF_HASH_LEN,
365 encoded,
366 encoded_len)
367}
368
369#[no_mangle]
371pub extern "C" fn hash_raw(
372 variant: uint32_t,
373 version: uint32_t,
374 mem_cost: uint32_t,
375 time_cost: uint32_t,
376 lanes: uint32_t,
377 threads: uint32_t,
378 pwd: *const uint8_t,
379 pwd_len: size_t,
380 salt: *const uint8_t,
381 salt_len: size_t,
382 secret: *const uint8_t,
383 secret_len: size_t,
384 ad: *const uint8_t,
385 ad_len: size_t,
386 out: *mut uint8_t,
387 out_len: size_t
388) -> int32_t {
389 let pwd = match mk_slice(pwd, pwd_len, ReturnValue::PwdPtrMismatch) {
390 Ok(val) => val,
391 Err(err) => return err as i32,
392 };
393
394 let salt = match mk_slice(salt, salt_len, ReturnValue::SaltPtrMismatch) {
395 Ok(val) => val,
396 Err(err) => return err as i32,
397 };
398
399 if out.is_null() {
400 return ReturnValue::OutputPtrNull as i32;
401 }
402
403 let config = match mk_config(variant,
404 version,
405 mem_cost,
406 time_cost,
407 lanes,
408 threads,
409 secret,
410 secret_len,
411 ad,
412 ad_len,
413 out_len) {
414 Ok(val) => val,
415 Err(err) => return err as i32,
416 };
417
418 match argon2::hash_raw(pwd, salt, &config) {
419 Ok(vec) => {
420 if vec.len() != out_len {
421 return ReturnValue::EncodingFail as i32;
422 }
423 unsafe {
424 ptr::copy_nonoverlapping(vec.as_ptr(), out, vec.len());
425 }
426 ReturnValue::Ok as i32
427 }
428 Err(err) => ReturnValue::from_error(err) as i32,
429 }
430}
431
432#[no_mangle]
434pub extern "C" fn hash_raw_argon2d(
435 mem_cost: uint32_t,
436 time_cost: uint32_t,
437 parallelism: uint32_t,
438 pwd: *const uint8_t,
439 pwd_len: size_t,
440 salt: *const uint8_t,
441 salt_len: size_t,
442 out: *mut uint8_t,
443 out_len: size_t
444) -> int32_t {
445 hash_raw(Variant::Argon2d as u32,
446 DEF_VERSION,
447 mem_cost,
448 time_cost,
449 parallelism,
450 parallelism,
451 pwd,
452 pwd_len,
453 salt,
454 salt_len,
455 ptr::null(),
456 0,
457 ptr::null(),
458 0,
459 out,
460 out_len)
461}
462
463#[no_mangle]
465pub extern "C" fn hash_raw_argon2i(
466 mem_cost: uint32_t,
467 time_cost: uint32_t,
468 parallelism: uint32_t,
469 pwd: *const uint8_t,
470 pwd_len: size_t,
471 salt: *const uint8_t,
472 salt_len: size_t,
473 out: *mut uint8_t,
474 out_len: size_t
475) -> int32_t {
476 hash_raw(Variant::Argon2i as u32,
477 DEF_VERSION,
478 mem_cost,
479 time_cost,
480 parallelism,
481 parallelism,
482 pwd,
483 pwd_len,
484 salt,
485 salt_len,
486 ptr::null(),
487 0,
488 ptr::null(),
489 0,
490 out,
491 out_len)
492}
493
494#[no_mangle]
496pub extern "C" fn hash_raw_argon2id(
497 mem_cost: uint32_t,
498 time_cost: uint32_t,
499 parallelism: uint32_t,
500 pwd: *const uint8_t,
501 pwd_len: size_t,
502 salt: *const uint8_t,
503 salt_len: size_t,
504 out: *mut uint8_t,
505 out_len: size_t
506) -> int32_t {
507 hash_raw(Variant::Argon2id as u32,
508 DEF_VERSION,
509 mem_cost,
510 time_cost,
511 parallelism,
512 parallelism,
513 pwd,
514 pwd_len,
515 salt,
516 salt_len,
517 ptr::null(),
518 0,
519 ptr::null(),
520 0,
521 out,
522 out_len)
523}
524
525#[no_mangle]
527pub extern "C" fn hash_raw_simple(
528 pwd: *const uint8_t,
529 pwd_len: size_t,
530 salt: *const uint8_t,
531 salt_len: size_t,
532 out: *mut uint8_t,
533 out_len: size_t
534) -> int32_t {
535 hash_raw(DEF_VARIANT,
536 DEF_VERSION,
537 DEF_MEMORY,
538 DEF_TIME,
539 DEF_LANES,
540 DEF_THREADS,
541 pwd,
542 pwd_len,
543 salt,
544 salt_len,
545 ptr::null(),
546 0,
547 ptr::null(),
548 0,
549 out,
550 out_len)
551}
552
553#[no_mangle]
555pub extern "C" fn verify_encoded(
556 encoded: *const c_char,
557 pwd: *const uint8_t,
558 pwd_len: size_t
559) -> int32_t {
560 let encoded = match mk_str(encoded, ReturnValue::DecodingFail) {
561 Ok(val) => val,
562 Err(err) => return err as i32,
563 };
564
565 let pwd = match mk_slice(pwd, pwd_len, ReturnValue::PwdPtrMismatch) {
566 Ok(val) => val,
567 Err(err) => return err as i32,
568 };
569
570 match argon2::verify_encoded(encoded, pwd) {
571 Ok(true) => ReturnValue::Ok as i32,
572 Ok(false) => ReturnValue::VerifyMismatch as i32,
573 Err(err) => ReturnValue::from_error(err) as i32,
574 }
575}
576
577#[no_mangle]
579pub extern "C" fn verify_raw(
580 variant: uint32_t,
581 version: uint32_t,
582 mem_cost: uint32_t,
583 time_cost: uint32_t,
584 lanes: uint32_t,
585 threads: uint32_t,
586 pwd: *const uint8_t,
587 pwd_len: size_t,
588 salt: *const uint8_t,
589 salt_len: size_t,
590 secret: *const uint8_t,
591 secret_len: size_t,
592 ad: *const uint8_t,
593 ad_len: size_t,
594 hash: *const uint8_t,
595 hash_len: size_t
596) -> int32_t {
597 let pwd = match mk_slice(pwd, pwd_len, ReturnValue::PwdPtrMismatch) {
598 Ok(val) => val,
599 Err(err) => return err as i32,
600 };
601
602 let salt = match mk_slice(salt, salt_len, ReturnValue::SaltPtrMismatch) {
603 Ok(val) => val,
604 Err(err) => return err as i32,
605 };
606
607 let hash = match mk_slice(hash, hash_len, ReturnValue::HashPtrMismatch) {
608 Ok(val) => val,
609 Err(err) => return err as i32,
610 };
611
612 let config = match mk_config(variant,
613 version,
614 mem_cost,
615 time_cost,
616 lanes,
617 threads,
618 secret,
619 secret_len,
620 ad,
621 ad_len,
622 hash_len) {
623 Ok(val) => val,
624 Err(err) => return err as i32,
625 };
626 match argon2::verify_raw(pwd, salt, hash, &config) {
627 Ok(true) => ReturnValue::Ok as i32,
628 Ok(false) => ReturnValue::VerifyMismatch as i32,
629 Err(err) => ReturnValue::from_error(err) as i32,
630 }
631}
632
633#[no_mangle]
635pub extern "C" fn verify_raw_argon2d(
636 mem_cost: uint32_t,
637 time_cost: uint32_t,
638 parallelism: uint32_t,
639 pwd: *const uint8_t,
640 pwd_len: size_t,
641 salt: *const uint8_t,
642 salt_len: size_t,
643 hash: *const uint8_t,
644 hash_len: size_t
645) -> int32_t {
646 verify_raw(Variant::Argon2d as u32,
647 DEF_VERSION,
648 mem_cost,
649 time_cost,
650 parallelism,
651 parallelism,
652 pwd,
653 pwd_len,
654 salt,
655 salt_len,
656 ptr::null(),
657 0,
658 ptr::null(),
659 0,
660 hash,
661 hash_len)
662}
663
664#[no_mangle]
666pub extern "C" fn verify_raw_argon2i(
667 mem_cost: uint32_t,
668 time_cost: uint32_t,
669 parallelism: uint32_t,
670 pwd: *const uint8_t,
671 pwd_len: size_t,
672 salt: *const uint8_t,
673 salt_len: size_t,
674 hash: *const uint8_t,
675 hash_len: size_t
676) -> int32_t {
677 verify_raw(Variant::Argon2i as u32,
678 DEF_VERSION,
679 mem_cost,
680 time_cost,
681 parallelism,
682 parallelism,
683 pwd,
684 pwd_len,
685 salt,
686 salt_len,
687 ptr::null(),
688 0,
689 ptr::null(),
690 0,
691 hash,
692 hash_len)
693}
694
695#[no_mangle]
697pub extern "C" fn verify_raw_argon2id(
698 mem_cost: uint32_t,
699 time_cost: uint32_t,
700 parallelism: uint32_t,
701 pwd: *const uint8_t,
702 pwd_len: size_t,
703 salt: *const uint8_t,
704 salt_len: size_t,
705 hash: *const uint8_t,
706 hash_len: size_t
707) -> int32_t {
708 verify_raw(Variant::Argon2id as u32,
709 DEF_VERSION,
710 mem_cost,
711 time_cost,
712 parallelism,
713 parallelism,
714 pwd,
715 pwd_len,
716 salt,
717 salt_len,
718 ptr::null(),
719 0,
720 ptr::null(),
721 0,
722 hash,
723 hash_len)
724}
725
726#[no_mangle]
728pub extern "C" fn verify_raw_simple(
729 pwd: *const uint8_t,
730 pwd_len: size_t,
731 salt: *const uint8_t,
732 salt_len: size_t,
733 hash: *const uint8_t,
734 hash_len: size_t
735) -> int32_t {
736 verify_raw(DEF_VARIANT,
737 DEF_VERSION,
738 DEF_MEMORY,
739 DEF_TIME,
740 DEF_LANES,
741 DEF_THREADS,
742 pwd,
743 pwd_len,
744 salt,
745 salt_len,
746 ptr::null(),
747 0,
748 ptr::null(),
749 0,
750 hash,
751 hash_len)
752}
753
754fn mk_config<'a>(
755 variant: u32,
756 version: u32,
757 mem_cost: u32,
758 time_cost: u32,
759 lanes: u32,
760 threads: u32,
761 secret: *const uint8_t,
762 secret_len: size_t,
763 ad: *const uint8_t,
764 ad_len: size_t,
765 hash_len: size_t
766) -> Result<Config<'a>, ReturnValue> {
767 let variant = match Variant::from_u32(variant) {
768 Ok(val) => val,
769 Err(err) => return Err(ReturnValue::from_error(err)),
770 };
771
772 let version = match Version::from_u32(version) {
773 Ok(val) => val,
774 Err(err) => return Err(ReturnValue::from_error(err)),
775 };
776
777 let secret = match mk_slice(secret, secret_len, ReturnValue::SecretPtrMismatch) {
778 Ok(val) => val,
779 Err(err) => return Err(err),
780 };
781
782 let ad = match mk_slice(ad, ad_len, ReturnValue::AdPtrMismatch) {
783 Ok(val) => val,
784 Err(err) => return Err(err),
785 };
786
787 Ok(Config {
788 variant: variant,
789 version: version,
790 secret: secret,
791 ad: ad,
792 mem_cost: mem_cost,
793 time_cost: time_cost,
794 lanes: lanes,
795 thread_mode: ThreadMode::from_threads(threads),
796 hash_length: hash_len as u32,
797 })
798}
799
800fn mk_slice<'a>(p: *const uint8_t, len: size_t, err: ReturnValue) -> Result<&'a [u8], ReturnValue> {
801 if p.is_null() && len != 0 {
802 return Err(err);
803 } else {
804 Ok(unsafe { slice::from_raw_parts(p, len) })
805 }
806}
807
808fn mk_str<'a>(p: *const c_char, err: ReturnValue) -> Result<&'a str, ReturnValue> {
809 if p.is_null() {
810 return Err(err);
811 } else {
812 let c_str = unsafe { CStr::from_ptr(p) };
813 match c_str.to_str() {
814 Ok(str) => Ok(str),
815 Err(_) => Err(err),
816 }
817 }
818}
819
820
821#[cfg(test)]
822mod tests {
823
824 use argon2::{Error, ThreadMode, Variant, Version};
825 use std::ptr;
826 use std::ffi::CString;
827 use super::*;
828
829 const ARGON2D_ENC: &'static [u8] = b"$argon2d$v=19$m=4096,t=3,p=1$c29tZXNhbHQ\
830 $2+JCoQtY/2x5F0VB9pEVP3xBNguWP1T25Ui0PtZuk8o";
831
832 const ARGON2I_ENC: &'static [u8] = b"$argon2i$v=19$m=4096,t=3,p=1$c29tZXNhbHQ\
833 $iWh06vD8Fy27wf9npn6FXWiCX4K6pW6Ue1Bnzz07Z8A";
834
835 const ARGON2ID_ENC: &'static [u8] = b"$argon2id$v=19$m=4096,t=3,p=1$c29tZXNhbHQ\
836 $qLml5cbqFAO6YxVHhrSBHP0UWdxrIxkNcM8aMX3blzU";
837
838 const ARGON2D_HASH: [u8; 32] = [219, 226, 66, 161, 11, 88, 255, 108, 121, 23, 69, 65, 246,
839 145, 21, 63, 124, 65, 54, 11, 150, 63, 84, 246, 229, 72, 180,
840 62, 214, 110, 147, 202];
841
842 const ARGON2I_HASH: [u8; 32] = [137, 104, 116, 234, 240, 252, 23, 45, 187, 193, 255, 103, 166,
843 126, 133, 93, 104, 130, 95, 130, 186, 165, 110, 148, 123, 80,
844 103, 207, 61, 59, 103, 192];
845
846 const ARGON2ID_HASH: [u8; 32] = [168, 185, 165, 229, 198, 234, 20, 3, 186, 99, 21, 71, 134,
847 180, 129, 28, 253, 20, 89, 220, 107, 35, 25, 13, 112, 207,
848 26, 49, 125, 219, 151, 53];
849
850 const PWD: &'static [u8] = b"password";
851
852 const PWD_INCORRECT: &'static [u8] = b"wrong";
853
854 const SALT: &'static [u8] = b"somesalt";
855
856 const SALT_SHORT: &'static [u8] = b"salt";
857
858 #[test]
859 fn return_value_from_error_returns_correct_value() {
860 let tuples = vec![(Error::OutputTooShort, ReturnValue::OutputTooShort),
861 (Error::OutputTooLong, ReturnValue::OutputTooLong),
862 (Error::PwdTooShort, ReturnValue::PwdTooShort),
863 (Error::PwdTooLong, ReturnValue::PwdTooLong),
864 (Error::SaltTooShort, ReturnValue::SaltTooShort),
865 (Error::SaltTooLong, ReturnValue::SaltTooLong),
866 (Error::AdTooShort, ReturnValue::AdTooShort),
867 (Error::AdTooLong, ReturnValue::AdTooLong),
868 (Error::SecretTooShort, ReturnValue::SecretTooShort),
869 (Error::SecretTooLong, ReturnValue::SecretTooLong),
870 (Error::TimeTooSmall, ReturnValue::TimeTooSmall),
871 (Error::TimeTooLarge, ReturnValue::TimeTooLarge),
872 (Error::MemoryTooLittle, ReturnValue::MemoryTooLittle),
873 (Error::MemoryTooMuch, ReturnValue::MemoryTooMuch),
874 (Error::LanesTooFew, ReturnValue::LanesTooFew),
875 (Error::LanesTooMany, ReturnValue::LanesTooMany),
876 (Error::IncorrectType, ReturnValue::IncorrectType),
877 (Error::IncorrectVersion, ReturnValue::IncorrectType),
878 (Error::DecodingFail, ReturnValue::DecodingFail)];
879 for tuple in tuples {
880 assert_eq!(ReturnValue::from_error(tuple.0), tuple.1);
881 }
882 }
883
884 #[test]
885 fn encoded_len_returns_correct_length() {
886 let expected = 85;
887 let actual = encoded_len(1, 4096, 3, 1, 8, 32);
888 assert_eq!(actual, expected);
889 }
890
891 #[test]
892 fn encoded_len_simple_returns_correct_length() {
893 let expected = 85;
894 let actual = encoded_len_simple(8);
895 assert_eq!(actual, expected);
896 }
897
898 #[test]
899 fn hash_encoded_with_correct_params_returns_ok() {
900 let encoded = CString::new(vec![1u8; 84]).unwrap().into_raw();
901 let result = hash_encoded(1,
902 0x13,
903 4096,
904 3,
905 1,
906 1,
907 PWD.as_ptr(),
908 PWD.len(),
909 SALT.as_ptr(),
910 SALT.len(),
911 ptr::null(),
912 0,
913 ptr::null(),
914 0,
915 32,
916 encoded,
917 85);
918 assert_eq!(result, 0);
919
920 let expected = CString::new(ARGON2I_ENC).unwrap();
921 let actual = unsafe { CString::from_raw(encoded) };
922 assert_eq!(actual, expected);
923 }
924
925 #[test]
926 fn hash_encoded_with_too_short_salt_returns_error() {
927 let encoded = CString::new(vec![1u8; 84]).unwrap().into_raw();
928 let result = hash_encoded(1,
929 0x13,
930 4096,
931 3,
932 1,
933 1,
934 PWD.as_ptr(),
935 PWD.len(),
936 SALT_SHORT.as_ptr(),
937 SALT_SHORT.len(),
938 ptr::null(),
939 0,
940 ptr::null(),
941 0,
942 32,
943 encoded,
944 85);
945 assert_eq!(result, -6);
946 }
947
948 #[test]
949 fn hash_encoded_argon2d_with_correct_params_returns_ok() {
950 let encoded = CString::new(vec![1u8; 84]).unwrap().into_raw();
951 let result = hash_encoded_argon2d(4096,
952 3,
953 1,
954 PWD.as_ptr(),
955 PWD.len(),
956 SALT.as_ptr(),
957 SALT.len(),
958 32,
959 encoded,
960 85);
961 assert_eq!(result, 0);
962
963 let expected = CString::new(ARGON2D_ENC).unwrap();
964 let actual = unsafe { CString::from_raw(encoded) };
965 assert_eq!(actual, expected);
966 }
967
968 #[test]
969 fn hash_encoded_argon2i_with_correct_params_returns_ok() {
970 let encoded = CString::new(vec![1u8; 84]).unwrap().into_raw();
971 let result = hash_encoded_argon2i(4096,
972 3,
973 1,
974 PWD.as_ptr(),
975 PWD.len(),
976 SALT.as_ptr(),
977 SALT.len(),
978 32,
979 encoded,
980 85);
981 assert_eq!(result, 0);
982
983 let expected = CString::new(ARGON2I_ENC).unwrap();
984 let actual = unsafe { CString::from_raw(encoded) };
985 assert_eq!(actual, expected);
986 }
987
988 #[test]
989 fn hash_encoded_argon2id_with_correct_params_returns_ok() {
990 let encoded = CString::new(vec![1u8; 85]).unwrap().into_raw();
991 let result = hash_encoded_argon2id(4096,
992 3,
993 1,
994 PWD.as_ptr(),
995 PWD.len(),
996 SALT.as_ptr(),
997 SALT.len(),
998 32,
999 encoded,
1000 86);
1001 assert_eq!(result, 0);
1002
1003 let expected = CString::new(ARGON2ID_ENC).unwrap();
1004 let actual = unsafe { CString::from_raw(encoded) };
1005 assert_eq!(actual, expected);
1006 }
1007
1008 #[test]
1009 fn hash_encoded_simple_with_correct_params_returns_ok() {
1010 let encoded = CString::new(vec![1u8; 84]).unwrap().into_raw();
1011 let result =
1012 hash_encoded_simple(PWD.as_ptr(), PWD.len(), SALT.as_ptr(), SALT.len(), encoded, 85);
1013 assert_eq!(result, 0);
1014
1015 let expected = CString::new(ARGON2I_ENC).unwrap();
1016 let actual = unsafe { CString::from_raw(encoded) };
1017 assert_eq!(actual, expected);
1018 }
1019
1020 #[test]
1021 fn hash_raw_with_correct_params_returns_ok() {
1022 let mut out = [0u8; 32];
1023 let result = hash_raw(1,
1024 0x13,
1025 4096,
1026 3,
1027 1,
1028 1,
1029 PWD.as_ptr(),
1030 PWD.len(),
1031 SALT.as_ptr(),
1032 SALT.len(),
1033 ptr::null(),
1034 0,
1035 ptr::null(),
1036 0,
1037 out.as_mut_ptr(),
1038 out.len());
1039 assert_eq!(result, 0);
1040 assert_eq!(out, ARGON2I_HASH);
1041 }
1042
1043 #[test]
1044 fn hash_raw_with_too_short_salt_returns_error() {
1045 let mut out = [0u8; 32];
1046 let result = hash_raw(1,
1047 0x13,
1048 4096,
1049 3,
1050 1,
1051 1,
1052 PWD.as_ptr(),
1053 PWD.len(),
1054 SALT_SHORT.as_ptr(),
1055 SALT_SHORT.len(),
1056 ptr::null(),
1057 0,
1058 ptr::null(),
1059 0,
1060 out.as_mut_ptr(),
1061 out.len());
1062 assert_eq!(result, -6);
1063 }
1064
1065 #[test]
1066 fn hash_raw_argon2d_with_correct_params_returns_ok() {
1067 let mut out = [0u8; 32];
1068 let result = hash_raw_argon2d(4096,
1069 3,
1070 1,
1071 PWD.as_ptr(),
1072 PWD.len(),
1073 SALT.as_ptr(),
1074 SALT.len(),
1075 out.as_mut_ptr(),
1076 out.len());
1077 assert_eq!(result, 0);
1078 assert_eq!(out, ARGON2D_HASH);
1079 }
1080
1081 #[test]
1082 fn hash_raw_argon2i_with_correct_params_returns_ok() {
1083 let mut out = [0u8; 32];
1084 let result = hash_raw_argon2i(4096,
1085 3,
1086 1,
1087 PWD.as_ptr(),
1088 PWD.len(),
1089 SALT.as_ptr(),
1090 SALT.len(),
1091 out.as_mut_ptr(),
1092 out.len());
1093 assert_eq!(result, 0);
1094 assert_eq!(out, ARGON2I_HASH);
1095 }
1096
1097 #[test]
1098 fn hash_raw_argon2id_with_correct_params_returns_ok() {
1099 let mut out = [0u8; 32];
1100 let result = hash_raw_argon2id(4096,
1101 3,
1102 1,
1103 PWD.as_ptr(),
1104 PWD.len(),
1105 SALT.as_ptr(),
1106 SALT.len(),
1107 out.as_mut_ptr(),
1108 out.len());
1109 assert_eq!(result, 0);
1110 assert_eq!(out, ARGON2ID_HASH);
1111 }
1112
1113 #[test]
1114 fn hash_raw_simple_with_correct_params_returns_ok() {
1115 let mut out = [0u8; 32];
1116 let result = hash_raw_simple(PWD.as_ptr(),
1117 PWD.len(),
1118 SALT.as_ptr(),
1119 SALT.len(),
1120 out.as_mut_ptr(),
1121 out.len());
1122 assert_eq!(result, 0);
1123 assert_eq!(out, ARGON2I_HASH);
1124 }
1125
1126 #[test]
1127 fn verify_encoded_with_correct_password_returns_ok() {
1128 let encoded = CString::new(ARGON2I_ENC).unwrap();
1129 let result = verify_encoded(encoded.as_ptr(), PWD.as_ptr(), PWD.len());
1130 assert_eq!(result, 0);
1131 }
1132
1133 #[test]
1134 fn verify_encoded_with_incorrect_password_returns_error() {
1135 let encoded = CString::new(ARGON2I_ENC).unwrap();
1136 let result = verify_encoded(encoded.as_ptr(), PWD_INCORRECT.as_ptr(), PWD_INCORRECT.len());
1137 assert_eq!(result, -35);
1138 }
1139
1140 #[test]
1141 fn verify_raw_with_correct_password_returns_ok() {
1142 let result = verify_raw(1,
1143 0x13,
1144 4096,
1145 3,
1146 1,
1147 1,
1148 PWD.as_ptr(),
1149 PWD.len(),
1150 SALT.as_ptr(),
1151 SALT.len(),
1152 ptr::null(),
1153 0,
1154 ptr::null(),
1155 0,
1156 ARGON2I_HASH.as_ptr(),
1157 ARGON2I_HASH.len());
1158 assert_eq!(result, 0);
1159 }
1160
1161 #[test]
1162 fn verify_raw_with_incorrect_password_returns_error() {
1163 let result = verify_raw(1,
1164 0x13,
1165 4096,
1166 3,
1167 1,
1168 1,
1169 PWD_INCORRECT.as_ptr(),
1170 PWD_INCORRECT.len(),
1171 SALT.as_ptr(),
1172 SALT.len(),
1173 ptr::null(),
1174 0,
1175 ptr::null(),
1176 0,
1177 ARGON2I_HASH.as_ptr(),
1178 ARGON2I_HASH.len());
1179 assert_eq!(result, -35);
1180 }
1181
1182 #[test]
1183 fn verify_raw_with_too_sort_salt_returns_error() {
1184 let result = verify_raw(1,
1185 0x13,
1186 4096,
1187 3,
1188 1,
1189 1,
1190 PWD.as_ptr(),
1191 PWD.len(),
1192 SALT_SHORT.as_ptr(),
1193 SALT_SHORT.len(),
1194 ptr::null(),
1195 0,
1196 ptr::null(),
1197 0,
1198 ARGON2I_HASH.as_ptr(),
1199 ARGON2I_HASH.len());
1200 assert_eq!(result, -6);
1201 }
1202
1203 #[test]
1204 fn verify_raw_argon2d_with_correct_password_returns_ok() {
1205 let result = verify_raw_argon2d(4096,
1206 3,
1207 1,
1208 PWD.as_ptr(),
1209 PWD.len(),
1210 SALT.as_ptr(),
1211 SALT.len(),
1212 ARGON2D_HASH.as_ptr(),
1213 ARGON2D_HASH.len());
1214 assert_eq!(result, 0);
1215 }
1216
1217 #[test]
1218 fn verify_raw_argon2i_with_correct_password_returns_ok() {
1219 let result = verify_raw_argon2i(4096,
1220 3,
1221 1,
1222 PWD.as_ptr(),
1223 PWD.len(),
1224 SALT.as_ptr(),
1225 SALT.len(),
1226 ARGON2I_HASH.as_ptr(),
1227 ARGON2I_HASH.len());
1228 assert_eq!(result, 0);
1229 }
1230
1231 #[test]
1232 fn verify_raw_argon2id_with_correct_password_returns_ok() {
1233 let result = verify_raw_argon2id(4096,
1234 3,
1235 1,
1236 PWD.as_ptr(),
1237 PWD.len(),
1238 SALT.as_ptr(),
1239 SALT.len(),
1240 ARGON2ID_HASH.as_ptr(),
1241 ARGON2ID_HASH.len());
1242 assert_eq!(result, 0);
1243 }
1244
1245 #[test]
1246 fn verify_raw_simple_with_correct_password_returns_ok() {
1247 let result = verify_raw_simple(PWD.as_ptr(),
1248 PWD.len(),
1249 SALT.as_ptr(),
1250 SALT.len(),
1251 ARGON2I_HASH.as_ptr(),
1252 ARGON2I_HASH.len());
1253 assert_eq!(result, 0);
1254 }
1255
1256 #[test]
1257 fn mk_config_with_correct_data_returns_correct_config() {
1258 let variant = 1;
1259 let version = 0x13;
1260 let mem_cost = 1024;
1261 let time_cost = 2;
1262 let lanes = 4;
1263 let threads = 4;
1264 let secret = b"secret";
1265 let ad = b"ad";
1266 let hash_len = 32;
1267 let result = mk_config(variant,
1268 version,
1269 mem_cost,
1270 time_cost,
1271 lanes,
1272 threads,
1273 secret.as_ptr(),
1274 secret.len(),
1275 ad.as_ptr(),
1276 ad.len(),
1277 hash_len);
1278 assert!(result.is_ok());
1279
1280 let config = result.unwrap();
1281 assert_eq!(config.variant, Variant::Argon2i);
1282 assert_eq!(config.version, Version::Version13);
1283 assert_eq!(config.mem_cost, mem_cost);
1284 assert_eq!(config.time_cost, time_cost);
1285 assert_eq!(config.lanes, lanes);
1286 assert_eq!(config.thread_mode, ThreadMode::Parallel);
1287 assert_eq!(config.secret, secret);
1288 assert_eq!(config.ad, ad);
1289 assert_eq!(config.hash_length, hash_len as u32);
1290 }
1291
1292 #[test]
1293 fn mk_config_with_incorrect_variant_returns_error() {
1294 let variant = 3;
1295 let secret = b"secret";
1296 let ad = b"ad";
1297 let result = mk_config(variant,
1298 0x13,
1299 1024,
1300 2,
1301 4,
1302 4,
1303 secret.as_ptr(),
1304 secret.len(),
1305 ad.as_ptr(),
1306 ad.len(),
1307 32);
1308 assert_eq!(result, Err(ReturnValue::IncorrectType));
1309 }
1310
1311 #[test]
1312 fn mk_config_with_incorrect_version_returns_error() {
1313 let version = 0;
1314 let secret = b"secret";
1315 let ad = b"ad";
1316 let result = mk_config(1,
1317 version,
1318 1024,
1319 2,
1320 4,
1321 4,
1322 secret.as_ptr(),
1323 secret.len(),
1324 ad.as_ptr(),
1325 ad.len(),
1326 32);
1327 assert_eq!(result, Err(ReturnValue::IncorrectType));
1328 }
1329
1330 #[test]
1331 fn mk_config_with_incorrect_secret_returns_error() {
1332 let ad = b"ad";
1333 let result = mk_config(1, 0x13, 1024, 2, 4, 4, ptr::null(), 1, ad.as_ptr(), ad.len(), 32);
1334 assert_eq!(result, Err(ReturnValue::SecretPtrMismatch));
1335 }
1336
1337 #[test]
1338 fn mk_config_with_incorrect_ad_returns_error() {
1339 let secret = b"secret";
1340 let result =
1341 mk_config(1, 0x13, 1024, 2, 4, 4, secret.as_ptr(), secret.len(), ptr::null(), 1, 32);
1342 assert_eq!(result, Err(ReturnValue::AdPtrMismatch));
1343 }
1344
1345 #[test]
1346 fn mk_slice_with_null_pointer_returns_empty_slice() {
1347 let expected: Result<&[u8], ReturnValue> = Ok(&[]);
1348 let actual = mk_slice(ptr::null(), 0, ReturnValue::Ok);
1349 assert_eq!(actual, expected);
1350 }
1351
1352 #[test]
1353 fn mk_slice_with_correct_pointer_returns_slice() {
1354 let slice = b"test";
1355 let expected: Result<&[u8], ReturnValue> = Ok(slice);
1356 let actual = mk_slice(slice.as_ptr(), slice.len(), ReturnValue::Ok);
1357 assert_eq!(actual, expected);
1358 }
1359
1360 #[test]
1361 fn mk_slice_with_incorrect_pointer_returns_error() {
1362 let expected = Err(ReturnValue::PwdPtrMismatch);
1363 let actual = mk_slice(ptr::null(), 1, ReturnValue::PwdPtrMismatch);
1364 assert_eq!(actual, expected);
1365 }
1366
1367 #[test]
1368 fn mk_str_with_null_pointer_returns_error() {
1369 let expected = Err(ReturnValue::DecodingFail);
1370 let actual = mk_str(ptr::null(), ReturnValue::DecodingFail);
1371 assert_eq!(actual, expected);
1372 }
1373
1374 #[test]
1375 fn mk_str_with_correct_pointer_returns_str() {
1376 let str = "String";
1377 let c_str = CString::new(str).unwrap();
1378 let expected = Ok(str);
1379 let actual = mk_str(c_str.as_ptr(), ReturnValue::Ok);
1380 assert_eq!(actual, expected);
1381 }
1382}