Encryption and Hashing¶
Encryption is the method of transforming data. This process changes the original information, referred to as plaintext, into an alternative form called ciphertext. The goal is to ensure that only authorized parties possess the capability to decrypt ciphertext back into plaintext and access the original information. Encryption doesn't inherently prevent interference but rather restricts the intelligible content from potential interceptors. Encryption is a bidirectional operation; what's encrypted can be decrypted using the correct key.
Hashing is the process of converting a given key into another value. A hash function is employed to create this new value following a mathematical algorithm. After hashing is applied, it should be practically impossible to reverse the process and derive the original input from the output.
Encryption¶
In Python, the cryptography
library provides a user-friendly way to implement encryption. One common encryption scheme is Fernet, which offers symmetric key encryption.
For example,
from cryptography.fernet import Fernet
# Generate a random encryption key
key = Fernet.generate_key()
# Create a Fernet cipher object with the key
cipher_suite = Fernet(key)
# Text to be encrypted
plaintext = b"Hello, this is a secret message!"
# Encrypt the plaintext
cipher_text = cipher_suite.encrypt(plaintext)
# Decrypt the ciphertext
decrypted_text = cipher_suite.decrypt(cipher_text)
# Convert bytes to string for printing
original_message = decrypted_text.decode("utf-8")
print("Original Message: ", plaintext)
print("Encrypted Message: ", cipher_text)
print("Decrypted Message: ", original_message)
Hashing¶
For hashing, Ellar works with passlib and hashlib to create a wrapper around some hashing algorithms listed below,
- PBKDF2Hasher:
pbkdf2_sha256
hashing algorithm wrapper - PBKDF2SHA1Hasher:
pbkdf2_sha1
hashing algorithm wrapper - Argon2Hasher:
argon2
hashing algorithm wrapper - BCryptSHA256Hasher:
bcrypt_sha256
hashing algorithm wrapper - BCryptHasher:
bcrypt
hashing algorithm wrapper - ScryptHasher:
scrypt
hashing algorithm wrapper - MD5Hasher:
md5
hashing algorithm wrapper
Password Hashing¶
Ellar provides two important utility functions: make_password
for password hashing and check_password
for password validation. Both of these functions are available in the ellar.core.security.hashers
package.
def make_password(
password: str|bytes,
algorithm: str = "pbkdf2_sha256",
salt: str|None = None,
) -> str:
pass
def check_password(
password: str|bytes,
encoded: str,
setter: Callable[..., Any]|None = None,
preferred_algorithm: str = "pbkdf2_sha256",
) -> bool:
pass
The make_password
function takes plain text and generates a hashed result based on the provided hash algorithm. In the code snippet above, the default algorithm for make_password
is pbkdf2_sha256
.
The PBKDF2 algorithm with a SHA256 hash is a password stretching mechanism recommended by NIST. This should be sufficient for most users as it is quite secure and requires massive amounts of computing time to break.
Note
All hashing wrappers are registered as key-value
pairs and can be accessed by the algorithm names using the get_hasher utility function in the ellar.core.security.hashers
package.
For an example,
from ellar.core.security.hashers import make_password
## Using pbkdf2_sha256 - PBKDF2Hasher
password_hash = make_password('mypassword1234', algorithm="pbkdf2_sha256", salt='seasalt')
print(password_hash)
# pbkdf2_sha256$870000$seasalt$XE8bb8u57rxvyv2SThRFtMg9mzJLff2wjm3J8kGgFVI=
## Using bcrypt_sha256 - BCryptSHA256Hasher
password_hash = make_password('mypassword1234', algorithm="bcrypt_sha256", salt='20AmWL1wKJZAHPiI1HEk4k')
print(password_hash)
# bcrypt_sha256$$2b$12$20AmWL1wKJZAHPiI1HEk4eZuAlMGHkK1rw4oou26bnwGmAE8F0JGK
On the other hand, you can check or validate a password using the check_password
function.
from ellar.core.security.hashers import check_password
hash_secret = "bcrypt_sha256$$2b$12$20AmWL1wKJZAHPiI1HEk4eZuAlMGHkK1rw4oou26bnwGmAE8F0JGK"
assert check_password('mypassword1234', hash_secret) # True