@@ -55,6 +55,10 @@ use zeroize::Zeroizing;
5555
5656const VERSION : & str = env ! ( "CARGO_PKG_VERSION" ) ;
5757
58+ pub const PASSWORD_HASH_LATEST : u16 = 0 ;
59+ pub const PASSWORD_HASH_V1 : u16 = 1 ;
60+ pub const PASSWORD_HASH_V2 : u16 = 1 ;
61+
5862/// Encrypt a data blob
5963/// # Arguments
6064/// * `data` - Pointer to the data to encrypt.
@@ -744,6 +748,7 @@ pub extern "C" fn SignSize(_version: u16) -> i64 {
744748/// * `result` - Pointer to the buffer to write the hash to.
745749/// * `result_length` - Length of the buffer to write the hash to. You can get the value by
746750/// calling HashPasswordLength() beforehand.
751+ /// * `version` - Version to use. Use PASSWORD_HASH_LATEST for the latest one.
747752/// # Returns
748753/// This returns the length of the hash. If there is an error, it will return the
749754/// appropriate error code defined in DevoCryptoError.
@@ -755,19 +760,25 @@ pub unsafe extern "C" fn HashPassword(
755760 password_length : usize ,
756761 result : * mut u8 ,
757762 result_length : usize ,
763+ version : u16 ,
758764) -> i64 {
759765 if password. is_null ( ) || result. is_null ( ) {
760766 return Error :: NullPointer . error_code ( ) ;
761767 } ;
762768
763- if result_length != HashPasswordLength ( ) as usize {
769+ let version = match PasswordHashVersion :: try_from ( version) {
770+ Ok ( v) => v,
771+ Err ( _) => return Error :: UnknownVersion . error_code ( ) ,
772+ } ;
773+
774+ if result_length != HashPasswordLength ( version as u16 ) as usize {
764775 return Error :: InvalidOutputLength . error_code ( ) ;
765776 } ;
766777
767778 let password = slice:: from_raw_parts ( password, password_length) ;
768779 let result = slice:: from_raw_parts_mut ( result, result_length) ;
769780
770- let res: Zeroizing < Vec < u8 > > = match hash_password ( password, PasswordHashVersion :: Latest ) {
781+ let res: Zeroizing < Vec < u8 > > = match hash_password ( password, version ) {
771782 Ok ( x) => Zeroizing :: new ( x. into ( ) ) ,
772783 Err ( e) => return e. error_code ( ) ,
773784 } ;
@@ -778,17 +789,19 @@ pub unsafe extern "C" fn HashPassword(
778789}
779790
780791/// Returns the length of the hash to input as `result_length` in `HashPassword()`.
781- /// The size reflects the default Argon2id parameters.
792+ /// # Arguments
793+ /// * `version` - Version to use. Use 0 for the latest one.
782794/// # Returns
783- /// Returns the length of the hash.
795+ /// Returns the length of the hash, or a negative error code for an unknown version .
784796#[ no_mangle]
785- pub extern "C" fn HashPasswordLength ( ) -> i64 {
786- // 8 (PasswordHash header)
787- // + 4 (u32 params_len)
788- // + 8 (DerivationParameters header)
789- // + GetDefaultArgon2ParametersSize() (Argon2Parameters default)
790- // + 32 (Argon2 default output length)
791- 8 + 4 + 8 + GetDefaultArgon2ParametersSize ( ) + 32
797+ pub extern "C" fn HashPasswordLength ( version : u16 ) -> i64 {
798+ match version {
799+ // V1: PBKDF2 — fixed layout: 4 (iterations) + 32 (salt) + 32 (hash) = 68, plus 8-byte header
800+ 1 => 8 + 68 ,
801+ // V2 / Latest: Argon2id — header + params_len field + DerivationParameters + hash
802+ 0 | 2 => 8 + 4 + 8 + GetDefaultArgon2ParametersSize ( ) + 32 ,
803+ _ => Error :: UnknownVersion . error_code ( ) ,
804+ }
792805}
793806
794807/// Hash a password using caller-supplied serialized [`DerivationParameters`].
@@ -2419,8 +2432,8 @@ fn test_hash_password_length() {
24192432 . unwrap ( )
24202433 . into ( ) ;
24212434
2422- assert_eq ! ( HashPasswordLength ( ) as usize , small_password_hash. len( ) ) ;
2423- assert_eq ! ( HashPasswordLength ( ) as usize , long_password_hash. len( ) ) ;
2435+ assert_eq ! ( HashPasswordLength ( PASSWORD_HASH_LATEST ) as usize , small_password_hash. len( ) ) ;
2436+ assert_eq ! ( HashPasswordLength ( PASSWORD_HASH_LATEST ) as usize , long_password_hash. len( ) ) ;
24242437}
24252438
24262439#[ test]
0 commit comments