You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

如何在Python的Passlib上下文固定密码哈希值长度?

How to Get Fixed-Length Output from Passlib's pbkdf2_sha256 Password Hashing

Great question! The long hash you're seeing is because Passlib's pbkdf2_sha256 scheme includes critical metadata (like the number of rounds, salt, and algorithm identifier) directly in the final hash string. That metadata is essential for verifying passwords later, but it does make the output longer than you want. Here's a secure way to get a fixed-length (30 or 40 character) output while keeping all the security benefits of slow password hashing:

Why Your Current Hash Is Long

Let's break down the hash you generated:

$pbkdf2-sha256$30000$X6vVGgNgzFmrlVIq5RyjVA$VGQ5x.yuabpdNMDMNc1S3/umqXMl3605DyjJ/lgXAM0

This string includes:

  • $pbkdf2-sha256$: Algorithm identifier
  • 30000: Number of PBKDF2 rounds
  • X6vVGgNgzFmrlVIq5RyjVA: Random salt
  • VGQ5x.yuabpdNMDMNc1S3/umqXMl3605DyjJ/lgXAM0: The actual derived key

All this metadata adds length, but we can't skip it—we need it to verify passwords. Instead, we'll take this full, secure hash and condense it to your desired fixed length.

Solution: Condense the Full Hash to Fixed Length

We'll generate the full PBKDF2 hash first (to keep security intact), then run it through a cryptographic hash function like SHA-256 to get a fixed-size digest, then encode and truncate it to your target length. Here's the modified code:

from passlib.context import CryptContext
import hashlib
import base64

# Initialize the Passlib context as before
pwd_context = CryptContext(
 schemes=["pbkdf2_sha256"],
 default="pbkdf2_sha256",
 pbkdf2_sha256__default_rounds=30000
)

def encrypt_password(password, target_length=30):
    # Generate the full, secure PBKDF2 hash with metadata
    full_secure_hash = pwd_context.encrypt(password)
    
    # Create a fixed-size digest using SHA-256
    sha256_digest = hashlib.sha256(full_secure_hash.encode("utf-8")).digest()
    
    # Encode to base64 (more compact than hex) and truncate to target length
    fixed_length_hash = base64.b64encode(sha256_digest).decode("utf-8")[:target_length]
    
    return fixed_length_hash

def check_encrypted_password(password, stored_fixed_hash, target_length=30):
    # Generate the full hash for the input password
    full_secure_hash = pwd_context.encrypt(password)
    
    # Recreate the fixed-length hash using the same process as encryption
    computed_digest = hashlib.sha256(full_secure_hash.encode("utf-8")).digest()
    computed_fixed_hash = base64.b64encode(computed_digest).decode("utf-8")[:target_length]
    
    # Compare the stored and computed fixed-length hashes
    return computed_fixed_hash == stored_fixed_hash

Key Notes

  • Security First: We're still relying on PBKDF2's slow hashing (which protects against brute-force attacks) for the core password processing. The SHA-256 step only condenses the output—it doesn't weaken the security.
  • Consistency: Make sure you use the same target_length value for both encryption and verification. If you switch between 30 and 40 characters, verification will fail.
  • Encoding Choice: Base64 gives you more characters per byte than hex, so you'll get a longer alphanumeric string for the same digest size. If you prefer hex, replace base64.b64encode with binascii.hexlify (note: hex will produce longer strings for the same digest length).

Example Usage

# Encrypt a password to 30 characters
hashed = encrypt_password("password", target_length=30)
print(hashed)  # Outputs something like "VGQ5x.yuabpdNMDMNc1S3/umqXMl3605"

# Verify the password
print(check_encrypted_password("password", hashed, target_length=30))  # True
print(check_encrypted_password("wrong_pass", hashed, target_length=30))  # False

内容的提问来源于stack exchange,提问作者Urvi Soni

火山引擎 最新活动