11import ctypes
22import ctypes .util
3+ from pathlib import Path
4+
5+ from .output import debug
36
47libcrypt = ctypes .CDLL ("libcrypt.so" )
58
912libcrypt .crypt_gensalt .argtypes = [ctypes .c_char_p , ctypes .c_ulong , ctypes .c_char_p , ctypes .c_int ]
1013libcrypt .crypt_gensalt .restype = ctypes .c_char_p
1114
15+ LOGIN_DEFS = Path ('/etc/login.defs' )
16+
17+
18+ def _search_login_defs (key : str ) -> str | None :
19+ defs = LOGIN_DEFS .read_text ()
20+ for line in defs .split ('\n ' ):
21+ line = line .strip ()
22+
23+ if line .startswith ('#' ):
24+ continue
25+
26+ if line .startswith (key ):
27+ value = line .split (' ' )[1 ]
28+ return value
29+
30+ return None
31+
1232
1333def crypt_gen_salt (prefix : str | bytes , rounds : int ) -> bytes :
1434 if isinstance (prefix , str ):
@@ -27,11 +47,19 @@ def crypt_yescrypt(plaintext: str) -> str:
2747 By default chpasswd in Arch uses PAM to to hash the password with crypt_yescrypt
2848 the PAM code https://github.com/linux-pam/linux-pam/blob/master/modules/pam_unix/support.c
2949 shows that the hashing rounds are determined from YESCRYPT_COST_FACTOR in /etc/login.defs
30- If no value was specified (or commented out) a default of 5 is choosen, given that the default
31- /etc/login.defs file from the ISO has the variable commented out 5 would be the default value
32- determined by the PAM in chpasswd
50+ If no value was specified (or commented out) a default of 5 is choosen
3351 """
34- rounds = 5
52+ value = _search_login_defs ('YESCRYPT_COST_FACTOR' )
53+ if value is not None :
54+ rounds = int (value )
55+ if rounds < 3 :
56+ rounds = 3
57+ elif rounds > 11 :
58+ rounds = 11
59+ else :
60+ rounds = 5
61+
62+ debug (f'Creating yescrypt hash with rounds { rounds } ' )
3563
3664 enc_plaintext = plaintext .encode ('utf-8' )
3765 salt = crypt_gen_salt ('$y$' , rounds )
0 commit comments