Quick answer: Python’s crypt interface is tied to Unix password functions and is not a portable Windows dependency. For new authentication code, use a maintained password-hashing or framework component that works on the supported platforms and includes salt, verification, and migration behavior.

The Python crypt module is not a cross-platform password hashing solution. It was tied to Unix crypt(3) behavior, was not available on Windows, and has been removed from the standard library in Python 3.13 after being deprecated in Python 3.11.
If code fails with a message such as The crypt module is not supported on Windows or No module named crypt, the long-term fix is to replace crypt with a supported password hashing approach. Do not try to copy Unix-only standard-library files into a Windows environment.
This is not just a platform inconvenience. Password hashing code should be portable, reviewable, and maintained. Depending on a module that is unavailable on Windows and removed from modern Python makes deployments harder and can block interpreter upgrades.
The official Python crypt documentation notes the deprecation and removal. For standard-library hashing primitives, see Python hashlib. For environment checks, see how to check your Python version.
Detect Whether crypt Exists
Start by checking whether the current interpreter can import crypt.
try:
import crypt
except ModuleNotFoundError as error:
print("crypt is unavailable:", error)
else:
print("crypt imported:", crypt.__name__)
This test only describes the current interpreter. Another Python version on the same computer may behave differently, especially across Linux, macOS, Windows, and Python 3.13 or newer.
If the import works on an old Unix server, that does not mean new code should keep using it. Treat a successful import as a sign that legacy behavior still exists, not as proof that the design is future-proof.
Check Platform And Python Version
Print the operating system and version before deciding which migration path to use.
import platform
import sys
print("Platform:", platform.system())
print("Python:", sys.version)
print("Executable:", sys.executable)
If the platform is Windows, avoid crypt. If the Python version is 3.13 or newer, avoid it everywhere because the module is no longer part of the standard library.
Checking both values helps explain confusing reports from teammates. One person may see a Windows platform issue, while another sees the same application fail after a Python upgrade on Linux.
Use hashlib For PBKDF2
For a standard-library replacement, hashlib.pbkdf2_hmac() can derive a password hash with a random salt and many iterations.
import hashlib
import os
password = b"example-password"
salt = os.urandom(16)
digest = hashlib.pbkdf2_hmac(
"sha256",
password,
salt,
600_000,
)
print(salt.hex())
print(digest.hex())
Store the salt, iteration count, algorithm, and digest together. The salt is not secret, but it must be available when verifying the password later.
The iteration count should be chosen for your environment and revisited over time. Higher counts slow attackers, but they also add login cost for your own application. Measure and document the choice.

Verify With compare_digest
Use hmac.compare_digest() when comparing stored and newly calculated password hashes.
import hashlib
import hmac
salt = bytes.fromhex("00112233445566778899aabbccddeeff")
stored = hashlib.pbkdf2_hmac("sha256", b"secret", salt, 600_000)
candidate = hashlib.pbkdf2_hmac("sha256", b"secret", salt, 600_000)
print(hmac.compare_digest(stored, candidate))
This avoids direct equality checks for sensitive digests. It is still important to use a strong password hashing configuration and protect the stored hash data.
Do not store plain passwords, and do not use a fast general-purpose hash alone for password storage. Password hashing needs a salt and a deliberately expensive derivation step.
Use secrets For Tokens
If the old code used crypt for reset links or random tokens, use secrets instead of password hashing.
import secrets
reset_token = secrets.token_urlsafe(32)
api_token = secrets.token_hex(32)
print(reset_token)
print(api_token)
Password hashing and token generation are different jobs. Use password hashing for stored passwords and secrets for random tokens.
This distinction prevents overloading one tool for every security task. Tokens should be random and short-lived when possible, while stored passwords need repeatable verification.

Consider Dedicated Password Libraries
For production password storage, dedicated libraries such as bcrypt or argon2 wrappers are often better than maintaining your own password-hashing policy.
try:
from passlib.hash import bcrypt
except ImportError:
print("Install passlib with bcrypt support before using this example.")
else:
hashed = bcrypt.hash("example-password")
print(bcrypt.verify("example-password", hashed))
Choose a maintained library, document the hash format, and plan migrations. Password storage decisions should be reviewed like security-sensitive infrastructure.
When adopting a third-party library, pin compatible versions, read its upgrade notes, and keep tests around hash creation and verification. That gives you confidence before changing production authentication code.
Migration Strategy
Do not downgrade Python only to keep crypt. That can postpone the failure while creating future maintenance and security problems. Instead, identify where crypt is used and replace each use with the correct modern purpose: password hashing, token generation, or legacy hash verification.
If existing user records already contain Unix crypt hashes, plan a migration. A common approach is to verify the old hash at login on a platform that still supports the old method, then rehash the password with the new method immediately after successful authentication.
The reliable fix is to treat crypt as legacy code. Use hashlib or a dedicated password library for cross-platform password hashing, use secrets for tokens, and remove platform-specific assumptions from new Python code.
Separate Legacy And New Code
First identify whether the project needs to verify legacy hashes or create new ones. Replacing an import without understanding the stored format can lock users out or weaken verification.

Use A Portable Hashing API
Choose a maintained library or framework integration that supports the required password-hashing scheme on Windows and Unix. Follow its documented parameters rather than hand-rolling salts or comparison logic.
Do Not Store Plain Passwords
When a legacy algorithm is unavailable, never fall back to plaintext, reversible encryption, or a fast unsalted digest. A migration flow can rehash a password after a successful legacy verification.

Handle Platform Checks Explicitly
If a legacy feature is truly Unix-only, isolate the import and provide a clear capability error or alternative. Avoid importing crypt at module load time when the rest of the application can run on Windows.
Protect Verification
Use constant-time comparison through the chosen library, rate-limit login attempts, and keep hash strings and passwords out of logs. Treat the password-hash format as sensitive configuration data.
Test Migration And Failure
Test new hash creation, verification, wrong passwords, malformed hashes, Windows and Unix environments, legacy migration, missing dependencies, and upgrade rollback behavior.
The official crypt documentation describes the platform-bound interface. Related Python Pool references include tests and safe logging.
For related authentication work, compare verification tests, redacted logging, and configuration storage before replacing crypt.
Frequently Asked Questions
Why is Python crypt not supported on Windows?
The module exposes operating-system password functions that are not a portable part of the Windows environment.
What should I use instead of crypt for passwords?
Use a maintained password-hashing library or framework integration designed for the application’s authentication requirements and supported platforms.
Can I install crypt with pip on Windows?
Installing a similarly named package does not automatically provide the operating-system API or make legacy code secure; evaluate the intended interface first.
Should I store a plain password if crypt is unavailable?
Never. Store a slow, salted password hash through a maintained authentication component and define a migration path for legacy records.