| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135 |
- import Crypto.Cipher.AES
- import hashlib
- import os
- class secret_crypto:
- """
- This class is responsible for creation and manage of the secrets crypto.
- All of the secrets would have own IV. When new secret_crypto is creating,
- IV is random. It could be change by function set_iv. Set IV is necessary
- to decrypt secret.
- Password HAVE NOT being stored in database. It must be given from API,
- to protect database. Password from the user is hashed by SHA256 to use it
- as key. IV is random, and other for all of the keys.
-
- If database leaks, secrets are save, because keys is provided from user
- every request for the secret.
- """
- def __init__(
- self,
- password: str,
- __iv: bytes | None = None,
- __key: bytes | None = None
- ) -> None:
- """
- This function create new secret_crypto. It could be used encrypt new
- secret. To decrypt secret, app must set IV.
- password: str - Password to encrypt secrets
- __iv: bytes | None - IV, used to clone (default: None)
- __key: bytes | None - Key, used to clone (default: None)
- """
- if __key is None:
- encoded = password.encode("UTF-8")
- hashed = hashlib.sha256(encoded)
- __key = hashed.digest()
- if __iv is None:
- __iv = os.urandom(16)
- self.__iv = __iv
- self.__key = __key
- self.__password = password
- def encrypt(self, secret: str) -> bytes:
- """
- This function encrypt secret, using previously loaded password as key
- and IV. IV would be random, and own for all secrets.
- secret: str - Secret to encode
- return: bytes - Encrypted secret
- """
- return self.__cipher.encrypt(secret.encode("UTF-8"))
- def decrypt(self, crypted: bytes) -> str:
- """
- This function decrypt previously crypted secret using given password
- as key. IV must be restore. When random IV is used, then cipher would
- not decrypt secret.
-
- crypted: bytes - Crypted secret to decrypt
- return: str - Decrypted secret
- """
- return self.__cipher.decrypt(crypted).decode("UTF-8")
- def crypted(self, secret: str) -> [bytes, bytes]:
- """
- This function is complex version of encrypt. It do exacly the same,
- but it return also IV, which could make code look better.
- secret: str - Secret to encrypt
- return: [bytes, bytes] - [Encrypted secret, IV]
- """
- return self.encrypt(secret), self.iv
- @property
- def password(self) -> str:
- """
- return: str - Password to encrypt
- """
- return self.__password
- @property
- def key(self) -> bytes:
- """
- return: bytes - Password as 256 bit binary key
- """
- return self.__key
- @property
- def iv(self) -> bytes:
- """
- return: bytes - IV of the crypto, get it to save in database
- """
- return self.__iv
- def set_iv(self, iv: bytes) -> object:
- """
- This function set IV. IV must be save in database, to decrypt secret
- later. This function is used to restore IV, previously read from
- database.
- iv: bytes - IV read from database
- return: secret_crypto - Clone of crypto with set given iv
- """
- return secret_crypto(self.password, iv, self.key)
- @property
- def mode(self) -> int:
- """
- return: int - Mode of the AES used to crypt
- """
- return Crypto.Cipher.AES.MODE_CFB
- @property
- def __cipher(self) -> object:
- """
- return: object - New clean cipher, which could be used to work
- """
- return Crypto.Cipher.AES.new(
- self.key,
- self.mode,
- iv = self.iv
- )
|