aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorChris Wolfe <chriswwolfe@gmail.com>2017-10-18 14:23:53 -0500
committerPaul Kehrer <paul.l.kehrer@gmail.com>2017-10-19 03:23:53 +0800
commitaf6f9900647c36224130270dab385d323ff7534d (patch)
tree68fae22e5533ed8c5fe00b34076f2beaf74e67f5 /src
parenta0022ead7b986def1d01b8e8b468bcb3b5785c82 (diff)
downloadcryptography-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.py25
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: