def generate_secure_text(self, origin_text: str) -> str: """ Encrypt and sign the origin text by ``cryptography`` library using AES GCM algorithm. :arg origin_text: is a string that will be encrypted by the provided security secret. """ iv = os.urandom(16) content = struct.pack( "l", int(time.time())) + ensure_bytes(origin_text) encryptor = AESCipher( aes_algorithms.AES(ensure_bytes(self.__security_secret)), aes_modes.GCM(iv), backend=aes_backend() ).encryptor() ciphertext = encryptor.update(content) + encryptor.finalize() final_encrypted_text = iv final_encrypted_text += struct.pack("l", len(ciphertext)) final_encrypted_text += ciphertext final_encrypted_text += encryptor.tag return ensure_str(base64.b64encode(final_encrypted_text))
def lookup_origin_text( self, secure_text: str, valid_length: Optional[int]=None) -> str: try: encrypted_text_reader = io.BytesIO(base64.b64decode(secure_text)) except: # Unable to decode the data. return None try: iv = encrypted_text_reader.read(16) length = struct.unpack("l", encrypted_text_reader.read(8))[0] ciphertext = encrypted_text_reader.read(length) tag = encrypted_text_reader.read(16) except: # Unable to split the data. return None decryptor = AESCipher( aes_algorithms.AES(self._security_secret), aes_modes.GCM(iv, tag), backend=aes_backend() ).decryptor() try: content = decryptor.update(ciphertext) + decryptor.finalize() except: # Unable to decrypt and/or verify the data. return None timestamp = struct.unpack("l", content[:8])[0] text = content[8:] if valid_length and int(time.time()) - timestamp > valid_length: return None # Data Expired. return ensure_str(text)
def lookup_origin_text(self, secure_text: str, valid_length: int=None) -> str: """ Decrypt the encrypted text, validate the signature and return the origin text. If the content and the signature mismatches, ``None`` will be returned. :arg secure_text: is a base64 encoded string, which contains the generated time, the content, and a AES GCM tag. :arg valid_length: the length that the content should be valid. The unit is second. It you want the content be always valid, set the length to ``None``. """ encrypted_text_reader = io.BytesIO(base64.b64decode(secure_text)) iv = encrypted_text_reader.read(16) length = struct.unpack("l", encrypted_text_reader.read(8))[0] ciphertext = encrypted_text_reader.read(length) tag = encrypted_text_reader.read(16) decryptor = AESCipher( aes_algorithms.AES(ensure_bytes(self.__security_secret)), aes_modes.GCM(iv, tag), backend=aes_backend() ).decryptor() try: content = decryptor.update(ciphertext) + decryptor.finalize() except: return None timestamp = struct.unpack("l", content[:8])[0] text = content[8:] if valid_length and int(time.time()) - timestamp > valid_length: return None try: return ensure_str(text) except: return None
def generate_secure_text(self, origin_text: str) -> str: if not isinstance(origin_text, str): raise TypeError("origin_text should be a string.") iv = os.urandom(16) content = struct.pack("l", int(time.time())) content += ensure_bytes(origin_text) encryptor = AESCipher( aes_algorithms.AES(self._security_secret), aes_modes.GCM(iv), backend=aes_backend() ).encryptor() ciphertext = encryptor.update(content) + encryptor.finalize() final_encrypted_text = iv final_encrypted_text += struct.pack("l", len(ciphertext)) final_encrypted_text += ciphertext final_encrypted_text += encryptor.tag return ensure_str(base64.b64encode(final_encrypted_text))