module

Krikri::PluginHelpers::CryptHash

ansible-core 2.21's password_hash backend. module_utils/utils/encrypt.py swapped passlib for libxcrypt (libc crypt() + crypt_gensalt()), so a salted hash now comes from the controller's own C library instead of a Python reimplementation. That changes observable output for a user-supplied salt: libxcrypt re-encodes the salt bytes with crypt's base64 and always writes the scheme's rounds/cost marker, where passlib used the salt text verbatim.

This mirrors CryptHash from that module (algorithm table, salt/size rules, error strings) and calls the same libcrypt entry points, so the hashes match what real Ansible produces on the same host.

The library is loaded at RUNTIME (dlopen), never linked in: ansible's own _internal/_encryption/_crypt.py CryptFacade does exactly that (via ctypes), probes the same libraries in the same order, and DEGRADES gracefully when crypt_gensalt is missing (it builds the salt string by hand instead, and rejects yescrypt). A build-time @[Link("crypt")] instead broke every release build: macOS has no libcrypt at all (ld: library 'crypt' not found) and Alpine ships only an 8-byte empty libcrypt.a stub, so the musl-static Linux link died on undefined reference to crypt_gensalt.

Constants

ALGORITHMS = {"md5_crypt" => Algo.new("1", 8, nil, false, nil, nil, false), "bcrypt" => Algo.new("2b", 22, 12_i64, true, "2b", "cost", false), "sha256_crypt" => Algo.new("5", 16, 535000_i64, false, nil, "rounds", false), "sha512_crypt" => Algo.new("6", 16, 656000_i64, false, nil, "rounds", false), "yescrypt" => Algo.new("y", 16, 5_i64, true, nil, "cost", true)}

encrypt.py's BaseHash.algorithms + CryptHash's own addition.

FILTER_ERROR_LIST = "md5, blowfish, sha256, sha512"
FILTER_NAMES = {"md5" => "md5_crypt", "blowfish" => "bcrypt", "sha256" => "sha256_crypt", "sha512" => "sha512_crypt"}

The filter's own passlib-era name mapping (core.py's get_encrypted_password) and the message it raises for a name it does not know.

NO_CRYPT_MESSAGE = "crypt cannot be used as the 'libxcrypt' library is not installed or is unusable."

AnsibleError from CryptHash.init when nothing could be loaded.

SALT_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./"

ansible's _SALT_CHARS, used only by the no-gensalt fallback.

Class methods

filter_password_hash(secret : String, hashtype : String, salt : String | Nil = nil, salt_size : JSON::Any | Nil = nil, rounds : JSON::Any | Nil = nil, ident : String | Nil = nil) : String

get_encrypted_password(): the filter-level name mapping plus its own rejection of anything outside the passlib-era set (live-verified vs 2.21.6, whose controller has passlib installed - without it the name reaches do_encrypt and fails with the crypt wording instead).

Source
hash(secret : String, algorithm : String, salt : String | Nil = nil, salt_size : JSON::Any | Nil = nil, rounds : JSON::Any | Nil = nil, ident : String | Nil = nil) : String

CryptHash.init plus CryptHash.hash(): the crypt library and the algorithm are checked first, then libxcrypt's own crypt_gensalt (with ansible's fallback when only a libc crypt() is available), then crypt().

Source
supported?(algorithm : String) : Bool
Source

Nested types