|
|
@@ -0,0 +1,135 @@
|
|
|
+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
|
|
|
+ )
|