-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add classes to build and parse ciphers
- Loading branch information
Showing
10 changed files
with
282 additions
and
301 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
from .cipher import Cipher | ||
from .cipher_parser import CipherParser | ||
|
||
__all__ = ["Cipher", "CipherParser"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
from __future__ import annotations | ||
|
||
from typing import Callable | ||
|
||
from ..constants import CIPHER_PREFIX, HASH_PREFIX | ||
from ..utils import make_hash, safe_encode_utf8 | ||
|
||
__all__ = ["Cipher"] | ||
|
||
|
||
class Cipher: | ||
"""A class that given a value builds a cipher of the format | ||
hash_prefix + hashed_value + cipher_prefix + secret. | ||
The secret is encrypted using the passed `encrypt` callable. | ||
""" | ||
|
||
def __init__( | ||
self, | ||
value: str | bytes, | ||
salt_key: bytes, | ||
encrypt: Callable[[bytes], bytes] | None = None, | ||
): | ||
encoded_value = safe_encode_utf8(value) | ||
self.hash_prefix = b"" | ||
self.hashed_value = b"" | ||
self.cipher_prefix = b"" | ||
self.secret = b"" | ||
if salt_key: | ||
self.hash_prefix: bytes = safe_encode_utf8(HASH_PREFIX) | ||
self.hashed_value: bytes = make_hash(encoded_value, salt_key) | ||
if encrypt: | ||
self.secret = encrypt(encoded_value) | ||
self.cipher_prefix: bytes = safe_encode_utf8(CIPHER_PREFIX) | ||
|
||
@property | ||
def cipher(self) -> bytes: | ||
return self.hash_prefix + self.hashed_value + self.cipher_prefix + self.secret | ||
|
||
def hash_with_prefix(self) -> bytes: | ||
return self.hash_prefix + self.hashed_value | ||
|
||
def secret_with_prefix(self) -> bytes: | ||
return self.cipher_prefix + self.secret |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
from __future__ import annotations | ||
|
||
from ..constants import CIPHER_PREFIX, HASH_PREFIX | ||
from ..exceptions import MalformedCiphertextError | ||
from ..utils import make_hash, safe_encode_utf8 | ||
|
||
__all__ = ["CipherParser"] | ||
|
||
|
||
class CipherParser: | ||
def __init__(self, cipher: bytes, salt_key: bytes | None = None): | ||
self._cipher_prefix = None | ||
self._hash_prefix = None | ||
self._hashed_value = None | ||
self._secret = None | ||
self.cipher = safe_encode_utf8(cipher) | ||
self.salt_key = salt_key | ||
self.validate_hashed_value() | ||
self.validate_secret() | ||
|
||
@property | ||
def hash_prefix(self) -> bytes | None: | ||
if self.cipher: | ||
hash_prefix = safe_encode_utf8(HASH_PREFIX) | ||
self._hash_prefix = hash_prefix if self.cipher.startswith(hash_prefix) else None | ||
return self._hash_prefix | ||
|
||
@property | ||
def cipher_prefix(self) -> bytes | None: | ||
if self.cipher: | ||
cipher_prefix = safe_encode_utf8(CIPHER_PREFIX) | ||
self._cipher_prefix = cipher_prefix if cipher_prefix in self.cipher else None | ||
return self._cipher_prefix | ||
|
||
@property | ||
def hashed_value(self) -> bytes | None: | ||
if self.cipher and self.cipher.startswith(self.hash_prefix): | ||
self._hashed_value = self.cipher.split(self.hash_prefix)[1].split( | ||
self.cipher_prefix | ||
)[0] | ||
return self._hashed_value | ||
|
||
@property | ||
def secret(self) -> bytes | None: | ||
if self.cipher and safe_encode_utf8(CIPHER_PREFIX) in self.cipher: | ||
self._secret = self.cipher.split(self.cipher_prefix)[1] | ||
return self._secret | ||
|
||
def validate_hashed_value(self) -> None: | ||
if self.hash_prefix and not self.hashed_value: | ||
raise MalformedCiphertextError("Invalid hashed_value. Got None.") | ||
elif self.salt_key and len(self.hashed_value) != len(make_hash("Foo", self.salt_key)): | ||
raise MalformedCiphertextError("Invalid hashed_value. Incorrect size.") | ||
|
||
def validate_secret(self) -> None: | ||
if self.cipher_prefix and not self.secret: | ||
raise MalformedCiphertextError("Invalid secret. Got None.") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.