diff options
author | Chris Wolfe <chriswwolfe@gmail.com> | 2017-10-18 14:23:53 -0500 |
---|---|---|
committer | Paul Kehrer <paul.l.kehrer@gmail.com> | 2017-10-19 03:23:53 +0800 |
commit | af6f9900647c36224130270dab385d323ff7534d (patch) | |
tree | 68fae22e5533ed8c5fe00b34076f2beaf74e67f5 /src | |
parent | a0022ead7b986def1d01b8e8b468bcb3b5785c82 (diff) | |
download | cryptography-af6f9900647c36224130270dab385d323ff7534d.tar.gz cryptography-af6f9900647c36224130270dab385d323ff7534d.tar.bz2 cryptography-af6f9900647c36224130270dab385d323ff7534d.zip |
Add Multifernet.rotate method (#3979)
* add rotate method
* add some more tests for the failure modes
* start adding some documentation for the rotate method
* operate on a single token at a time, leave lists to the caller
* add versionadded
add versionadded, drop rotate from class doctest
* give rotate a doctest
* single level, not aligned
* add changelog for mf.rotate
* show that, once rotated, the old fernet instance can no longer decrypt the token
* add the instead of just the how
* update docs to reflect removal of ttl from rotate
* update tests
* refactor internal methods so that we can extract the timestamp
* implement rotate
* update wordlist (case sensitive?)
* lints
* consistent naming
* get_token_data/get_unverified_token_data -> better name
* doc changes
* use the static method, do not treat as imethod
* move up to MultiFernet docs
* add to authors
* alter wording
* monkeypatch time to make it less possible for the test to pass simply due to calls occuring in less than one second
* set the time after encryption to make sure that the time is preserved as part of re-encryption
Diffstat (limited to 'src')
-rw-r--r-- | src/cryptography/fernet.py | 25 |
1 files changed, 23 insertions, 2 deletions
diff --git a/src/cryptography/fernet.py b/src/cryptography/fernet.py index 99eb10e5..1f33a12d 100644 --- a/src/cryptography/fernet.py +++ b/src/cryptography/fernet.py @@ -71,11 +71,14 @@ class Fernet(object): return base64.urlsafe_b64encode(basic_parts + hmac) def decrypt(self, token, ttl=None): + timestamp, data = Fernet._get_unverified_token_data(token) + return self._decrypt_data(data, timestamp, ttl) + + @staticmethod + def _get_unverified_token_data(token): if not isinstance(token, bytes): raise TypeError("token must be bytes.") - current_time = int(time.time()) - try: data = base64.urlsafe_b64decode(token) except (TypeError, binascii.Error): @@ -88,6 +91,10 @@ class Fernet(object): timestamp, = struct.unpack(">Q", data[1:9]) except struct.error: raise InvalidToken + return timestamp, data + + def _decrypt_data(self, data, timestamp, ttl): + current_time = int(time.time()) if ttl is not None: if timestamp + ttl < current_time: raise InvalidToken @@ -134,6 +141,20 @@ class MultiFernet(object): def encrypt(self, msg): return self._fernets[0].encrypt(msg) + def rotate(self, msg): + timestamp, data = Fernet._get_unverified_token_data(msg) + for f in self._fernets: + try: + p = f._decrypt_data(data, timestamp, None) + break + except InvalidToken: + pass + else: + raise InvalidToken + + iv = os.urandom(16) + return self._fernets[0]._encrypt_from_parts(p, timestamp, iv) + def decrypt(self, msg, ttl=None): for f in self._fernets: try: |