In the design of a system, there will certainly be user authentication issues, the general verification of the user, are the user exists in the database to determine the total password hash value, so as to avoid password leakage and reverse decryption, then in the Python development, we can introduce bcrypt or Passlib on the system to the user password hash and verify the processing, as well as the introduction of using the other libraries to realize regular encryption and decryption processing operations. This essay mainly introduces the differences between bcrypt and Passlib, as well as some code for reference in actual use.
1、bcrypt
cap (a poem)Introduction to Passlib
bcrypt
cap (a poem)Passlib
are both Python libraries for password hashing and authentication, but they have some significant differences:
-
bcrypt:
-
bcrypt
is a program specifically designed to implement thebcrypt
A library of hash algorithms. It is relatively simple and focuses on a single function, i.e., performing a password on thebcrypt
Hash processing and validation. - Ideal for those who only need
bcrypt
Scenarios for hash algorithms. - The API provided is simple and straightforward, with fewer features.
-
-
Passlib:
-
Passlib
is a more advanced cryptographic hash library that supports a variety of hash algorithms (e.g.bcrypt
、PBKDF2
、Argon2
etc.) and provides richer functionality. - Ideal for scenarios that require support for multiple cryptographic hash algorithms and policies.
- offered
CryptContext
class makes it easy to manage and migrate multiple hash algorithms. It also provides an automatic upgrade mechanism for cryptographic hashes, as well as deprecation handling of old algorithms.
-
When you are sure that you only need to use thebcrypt
algorithms, and when no additional complexity is required, thebcrypt
It is a suitable choice. It is suitable for simple projects or when direct control is required of thesalt
used in the case of parameters such as.
Passlib is suitable for complex projects, especially in scenarios where multiple hash algorithms need to be supported or where hash algorithms need to be migrated. Suitable for projects that require long-term maintenance, as it provides more configuration and security features.
bcrypt: Less flexible because it only supportsbcrypt
Algorithm.No multiple hash algorithm selection or password policy management features. Easy to use and more intuitive code. If you only needbcrypt
Algorithm.bcrypt
The library may be easier to get started.
Passlib:Provides a high degree of flexibility and scalability. Different hash algorithms can be switched and configured as needed to manage complex password policies.pass (a bill or inspection etc)CryptContext
, can easily manage transitions between different algorithms. Powerful but relatively complex, it requires more in-depth learning and understanding. However, its high-level API is designed to be user-friendly and can simplify many common tasks once familiarized.CryptContext
is one of the classes used to manage multiple hash algorithms and cryptographic hash policies.
Sample code comparison:
bcrypt Example of use:
import bcrypt password = b"supersecretpassword" hashed = (password, ()) # Verify Password if (password, hashed): print("Password matches!") else: print("Password does not match.")
Passlib Example of use:
from import CryptContext # Create a CryptContext object pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") # hash password password = "my_secret_password" hashed_password = pwd_context.hash(password) print("Hashed password:", hashed_password) # Verify Password is_correct = pwd_context.verify(password, hashed_password) if is_correct: print("The password is correct.") else: print("incorrect password")
Defines aCryptContext
object for managing password hash algorithms.schemes=["bcrypt"]
indicates that you want to use thebcrypt
algorithm, and thedeprecated="auto"
Indicates the automatic management of obsolete hash schemes.
utilizationpwd_context.hash()
method hashes the password. The hash value generated is unique each time, and different hashes are generated even for the same password.
utilizationpwd_context.verify()
method verifies that the given password matches the stored hash.
You can also createCryptContext
object when passing more parameters to customize the password hash behavior, this approach can enhance the security of password storage. For example:
pwd_context = CryptContext( schemes=["bcrypt"], bcrypt__rounds=12 # bcrypt's hash rounds, default is 12 )
2、Use the specified salt for encryption
existPasslib
Middle.bcrypt
By default, the algorithm automatically generates a randomsalt
It's alsobcrypt
A security feature of the If you want to use the specifiedsalt
To perform encryption, it is important to note thatPasslib
does not directly support the adoption of the specifiedsalt
to perform hashing, as this may reduce security.
However, if you do need to use the specifiedsalt
To perform hashing, you can use the following:
-
Manual splicing
salt
and passwords: Can be spliced manuallysalt
and passwords and then hashing the results. However, this approach is only suitable for scenarios where risks are understood and security measures are ensured. -
utilization
bcrypt
storehouse: Direct usebcrypt
library for processing, which allows you to pass a specifiedsalt
. However, note that this can be a security risk.
1) Usebcrypt
library designationsalt
If you do need to specifysalt
You can use thebcrypt
Coop.
import bcrypt # Specified salt (must be 16 bytes, prefixed with b"$2b$") salt = (rounds=12) # Or use a custom 16-byte salt print(f"Generated salt: {salt}") # Password to be encrypted password = "my_secret_password" # Encrypt with the specified salt hashed_password = (('utf-8'), salt) print(f"Hashed password: {hashed_password}")
2) Manual splicingsalt
and passwords
If you use thePasslib
and would like to use the specifiedsalt
The splicing can be done manually.salt
and the password, and then hash this combined result. This approach is generally not recommended because it breaks thebcrypt
The safety design principles of the
from import CryptContext # Create a CryptContext object pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") # Customizing salt custom_salt = "my_custom_salt" # Splicing salt and password password = "my_secret_password" password_with_salt = custom_salt + password # Hashing the spliced string hashed_password = pwd_context.hash(password_with_salt) print("Hashed password with custom salt:", hashed_password)
caveat
- Use of fixed
salt
would reduce the security of the password hash because the samesalt
and the same password will generate the same hash. -
bcrypt
was originally designed so that each generatedsalt
All different, as a way to increase security. - If you need to use a fixed in a specific scenario
salt
, always make sure that your system has adequate other security measures in place.
For the same password, the hash value obtained each time will be different, so some people will ask if the hash value obtained through pwd_context.hash can be compared correctly next time?
The answer is yes, usingpwd_context.hash()
The generated hashes can be matched correctly in subsequent comparisons, even if the generated hashes look different each time.Passlib
cap (a poem)bcrypt
The design ensures this.
-
automatic
salt
: Every time you usepwd_context.hash()
When generating a new hash, thebcrypt
Both automatically generate a randomsalt
and embed it in the generated hash. As a result, even if the same password is hashed multiple times, the generated hash will be different each time. -
verification process: During the validation process, the
pwd_context.verify()
will automatically extract the hash value from the storedsalt
and recalculates the hash and then compares it to the provided hash. This means that even if the hashes are different, the validation still manages to match successfully.
Even if you run it every timepwd_context.hash(password)
The hash values obtained are different (becausesalt
different).pwd_context.verify(password, hashed_password)
will still returnTrue
, indicating successful password verification.
3. Encryption and decryption processing
Passlib
It is mainly used for password hash processing and does not support encryption and decryption operations. If you need to encrypt and decrypt strings, or use asymmetric encryption, you need to use other libraries such ascryptography
maybePyCryptodome
。
1)Symmetric encryption and decryption
For symmetric encryption, you can use thecryptography
libraryFernet
It is an encryption scheme based on the AES algorithm.
mountingcryptography
storehouse
pip install cryptography
Symmetric Encryption and Decryption Examples
from import Fernet # Generate key (note: key needs to be stored securely) key = Fernet.generate_key() cipher = Fernet(key) # encrypted message = "This is a secret message" encrypted_message = (()) print("Encrypted:", encrypted_message) # declassification decrypted_message = (encrypted_message).decode() print("Decrypted:", decrypted_message)
2) asymmetric encryption and decryption
For asymmetric encryption, you can use thecryptography
libraryRSA
Algorithm. Typically, asymmetric encryption is used to encrypt shorter messages or to encrypt symmetric keys.
Asymmetric Encryption and Decryption Examples
from import rsa, padding from import serialization, hashes # Generate private and public keys private_key = rsa.generate_private_key( public_exponent=65537, key_size=2048, ) public_key = private_key.public_key() # encrypted message = b"This is a secret message" encrypted_message = public_key.encrypt( message, ( mgf=padding.MGF1(algorithm=hashes.SHA256()), algorithm=hashes.SHA256(), label=None ) ) print("Encrypted:", encrypted_message) # declassification decrypted_message = private_key.decrypt( encrypted_message, ( mgf=padding.MGF1(algorithm=hashes.SHA256()), algorithm=hashes.SHA256(), label=None ) ) print("Decrypted:", decrypted_message.decode())
3) Save and Load Keys
Keeping the private key:
private_pem = private_key.private_bytes( encoding=, format=, encryption_algorithm=() ) with open('private_key.pem', 'wb') as f: (private_pem)
Load private key:
with open('private_key.pem', 'rb') as f: private_key = serialization.load_pem_private_key( (), password=None, )
Keeping the public key:
public_pem = public_key.public_bytes( encoding=, format= ) with open('public_key.pem', 'wb') as f: (public_pem)
Load public key:
with open('public_key.pem', 'rb') as f: public_key = serialization.load_pem_public_key(())
We can choose the appropriate encryption methods and libraries according to the requirements and manage the keys properly during the total development process.