Alex Stapleton | c5fffd3 | 2014-03-18 15:29:00 +0000 | [diff] [blame] | 1 | Fernet (symmetric encryption) |
Alex Gaynor | e908329 | 2013-12-17 16:56:29 -0800 | [diff] [blame] | 2 | ============================= |
Alex Gaynor | 333fb10 | 2013-10-31 10:27:35 -0700 | [diff] [blame] | 3 | |
| 4 | .. currentmodule:: cryptography.fernet |
| 5 | |
Fran Fitzpatrick | 238c191 | 2015-08-25 21:22:30 -0400 | [diff] [blame] | 6 | Fernet guarantees that a message encrypted using it cannot be |
Alex Gaynor | 681fca8 | 2013-12-31 14:13:39 -0800 | [diff] [blame] | 7 | manipulated or read without the key. `Fernet`_ is an implementation of |
Alex Gaynor | e148d01 | 2014-10-19 19:18:59 -0700 | [diff] [blame] | 8 | symmetric (also known as "secret key") authenticated cryptography. Fernet also |
| 9 | has support for implementing key rotation via :class:`MultiFernet`. |
Alex Gaynor | 333fb10 | 2013-10-31 10:27:35 -0700 | [diff] [blame] | 10 | |
| 11 | .. class:: Fernet(key) |
| 12 | |
| 13 | This class provides both encryption and decryption facilities. |
| 14 | |
| 15 | .. doctest:: |
| 16 | |
| 17 | >>> from cryptography.fernet import Fernet |
Alex Gaynor | 36597b4 | 2013-11-22 10:25:13 -0800 | [diff] [blame] | 18 | >>> key = Fernet.generate_key() |
Alex Gaynor | 333fb10 | 2013-10-31 10:27:35 -0700 | [diff] [blame] | 19 | >>> f = Fernet(key) |
Alex Gaynor | 0d08963 | 2013-12-17 20:23:43 -0800 | [diff] [blame] | 20 | >>> token = f.encrypt(b"my deep dark secret") |
| 21 | >>> token |
Alex Gaynor | de475eb | 2013-10-31 10:35:19 -0700 | [diff] [blame] | 22 | '...' |
Alex Gaynor | 0d08963 | 2013-12-17 20:23:43 -0800 | [diff] [blame] | 23 | >>> f.decrypt(token) |
Alex Gaynor | 333fb10 | 2013-10-31 10:27:35 -0700 | [diff] [blame] | 24 | 'my deep dark secret' |
| 25 | |
Alex Gaynor | 7a121fc | 2013-11-22 10:18:30 -0800 | [diff] [blame] | 26 | :param bytes key: A URL-safe base64-encoded 32-byte key. This **must** be |
| 27 | kept secret. Anyone with this key is able to create and |
| 28 | read messages. |
Alex Gaynor | 333fb10 | 2013-10-31 10:27:35 -0700 | [diff] [blame] | 29 | |
Alex Gaynor | 36597b4 | 2013-11-22 10:25:13 -0800 | [diff] [blame] | 30 | .. classmethod:: generate_key() |
| 31 | |
| 32 | Generates a fresh fernet key. Keep this some place safe! If you lose it |
| 33 | you'll no longer be able to decrypt messages; if anyone else gains |
Alex Gaynor | 6cf242b | 2013-12-16 11:17:07 -0800 | [diff] [blame] | 34 | access to it, they'll be able to decrypt all of your messages, and |
Alex Stapleton | 63b3de2 | 2014-02-08 09:43:16 +0000 | [diff] [blame] | 35 | they'll also be able forge arbitrary messages that will be |
Alex Gaynor | 6cf242b | 2013-12-16 11:17:07 -0800 | [diff] [blame] | 36 | authenticated and decrypted. |
Alex Gaynor | 333fb10 | 2013-10-31 10:27:35 -0700 | [diff] [blame] | 37 | |
Ayrx | 6d69eab | 2014-05-17 16:59:31 +0800 | [diff] [blame] | 38 | .. method:: encrypt(data) |
Alex Gaynor | 333fb10 | 2013-10-31 10:27:35 -0700 | [diff] [blame] | 39 | |
Ayrx | 6d69eab | 2014-05-17 16:59:31 +0800 | [diff] [blame] | 40 | :param bytes data: The message you would like to encrypt. |
Alex Stapleton | 63b3de2 | 2014-02-08 09:43:16 +0000 | [diff] [blame] | 41 | :returns bytes: A secure message that cannot be read or altered |
Alex Gaynor | 0d08963 | 2013-12-17 20:23:43 -0800 | [diff] [blame] | 42 | without the key. It is URL-safe base64-encoded. This is |
Alex Gaynor | 3aa243c | 2014-01-06 13:13:18 -0800 | [diff] [blame] | 43 | referred to as a "Fernet token". |
Alex Gaynor | e148d01 | 2014-10-19 19:18:59 -0700 | [diff] [blame] | 44 | :raises TypeError: This exception is raised if ``data`` is not |
| 45 | ``bytes``. |
Alex Gaynor | 32dc4e4 | 2013-12-20 13:26:12 -0800 | [diff] [blame] | 46 | |
Alex Gaynor | 719eb6a | 2013-12-20 13:35:57 -0800 | [diff] [blame] | 47 | .. note:: |
Alex Gaynor | 32dc4e4 | 2013-12-20 13:26:12 -0800 | [diff] [blame] | 48 | |
| 49 | The encrypted message contains the current time when it was |
| 50 | generated in *plaintext*, the time a message was created will |
| 51 | therefore be visible to a possible attacker. |
Alex Gaynor | 333fb10 | 2013-10-31 10:27:35 -0700 | [diff] [blame] | 52 | |
Alex Gaynor | 0d08963 | 2013-12-17 20:23:43 -0800 | [diff] [blame] | 53 | .. method:: decrypt(token, ttl=None) |
Alex Gaynor | 333fb10 | 2013-10-31 10:27:35 -0700 | [diff] [blame] | 54 | |
Alex Gaynor | 0d08963 | 2013-12-17 20:23:43 -0800 | [diff] [blame] | 55 | :param bytes token: The Fernet token. This is the result of calling |
| 56 | :meth:`encrypt`. |
Alex Gaynor | 333fb10 | 2013-10-31 10:27:35 -0700 | [diff] [blame] | 57 | :param int ttl: Optionally, the number of seconds old a message may be |
| 58 | for it to be valid. If the message is older than |
| 59 | ``ttl`` seconds (from the time it was originally |
Alex Gaynor | 13e0d54 | 2013-10-31 10:38:04 -0700 | [diff] [blame] | 60 | created) an exception will be raised. If ``ttl`` is not |
| 61 | provided (or is ``None``), the age of the message is |
| 62 | not considered. |
Alex Gaynor | 333fb10 | 2013-10-31 10:27:35 -0700 | [diff] [blame] | 63 | :returns bytes: The original plaintext. |
Alex Gaynor | 719eb6a | 2013-12-20 13:35:57 -0800 | [diff] [blame] | 64 | :raises cryptography.fernet.InvalidToken: If the ``token`` is in any |
| 65 | way invalid, this exception |
| 66 | is raised. A token may be |
| 67 | invalid for a number of |
| 68 | reasons: it is older than the |
| 69 | ``ttl``, it is malformed, or |
| 70 | it does not have a valid |
| 71 | signature. |
Alex Gaynor | e148d01 | 2014-10-19 19:18:59 -0700 | [diff] [blame] | 72 | :raises TypeError: This exception is raised if ``token`` is not |
| 73 | ``bytes``. |
| 74 | |
| 75 | |
| 76 | .. class:: MultiFernet(fernets) |
| 77 | |
Alex Gaynor | 4c82513 | 2014-10-20 21:27:08 -0700 | [diff] [blame] | 78 | .. versionadded:: 0.7 |
| 79 | |
Alex Gaynor | e148d01 | 2014-10-19 19:18:59 -0700 | [diff] [blame] | 80 | This class implements key rotation for Fernet. It takes a ``list`` of |
| 81 | :class:`Fernet` instances, and implements the same API: |
| 82 | |
| 83 | .. doctest:: |
| 84 | |
| 85 | >>> from cryptography.fernet import Fernet, MultiFernet |
| 86 | >>> key1 = Fernet(Fernet.generate_key()) |
| 87 | >>> key2 = Fernet(Fernet.generate_key()) |
| 88 | >>> f = MultiFernet([key1, key2]) |
| 89 | >>> token = f.encrypt(b"Secret message!") |
| 90 | >>> token |
| 91 | '...' |
| 92 | >>> f.decrypt(token) |
| 93 | 'Secret message!' |
| 94 | |
Terry Chia | eab0d19 | 2015-03-26 08:56:28 +0800 | [diff] [blame] | 95 | MultiFernet performs all encryption options using the *first* key in the |
| 96 | ``list`` provided. MultiFernet attempts to decrypt tokens with each key in |
Terry Chia | 7ff9362 | 2015-03-28 02:01:34 +0800 | [diff] [blame] | 97 | turn. A :class:`cryptography.fernet.InvalidToken` exception is raised if |
Terry Chia | eab0d19 | 2015-03-26 08:56:28 +0800 | [diff] [blame] | 98 | the correct key is not found in the ``list`` provided. |
Alex Gaynor | e148d01 | 2014-10-19 19:18:59 -0700 | [diff] [blame] | 99 | |
| 100 | Key rotation makes it easy to replace old keys. You can add your new key at |
| 101 | the front of the list to start encrypting new messages, and remove old keys |
| 102 | as they are no longer needed. |
Alex Gaynor | 7a121fc | 2013-11-22 10:18:30 -0800 | [diff] [blame] | 103 | |
| 104 | |
| 105 | .. class:: InvalidToken |
| 106 | |
| 107 | See :meth:`Fernet.decrypt` for more information. |
Alex Gaynor | 333fb10 | 2013-10-31 10:27:35 -0700 | [diff] [blame] | 108 | |
Terry Chia | b964a5c | 2015-08-29 18:53:47 +0800 | [diff] [blame] | 109 | |
| 110 | Using passwords with Fernet |
| 111 | --------------------------- |
| 112 | |
| 113 | It is possible to use passwords with Fernet. To do this, you need to run the |
Terry Chia | 7126e61 | 2015-08-29 22:28:51 +0800 | [diff] [blame] | 114 | password through a key derivation function such as |
Terry Chia | b1903b0 | 2015-08-30 11:09:22 +0800 | [diff] [blame] | 115 | :class:`~cryptography.hazmat.primitives.kdf.pbkdf2.PBKDF2HMAC`, bcrypt or |
Alex Gaynor | 4e87cf4 | 2017-01-21 08:50:53 -0500 | [diff] [blame] | 116 | :class:`~cryptography.hazmat.primitives.kdf.scrypt.Scrypt`. |
Terry Chia | b964a5c | 2015-08-29 18:53:47 +0800 | [diff] [blame] | 117 | |
Paul Kehrer | 8d242c7 | 2015-09-04 14:08:10 -0500 | [diff] [blame] | 118 | .. doctest:: |
Terry Chia | b964a5c | 2015-08-29 18:53:47 +0800 | [diff] [blame] | 119 | |
Paul Kehrer | 8d242c7 | 2015-09-04 14:08:10 -0500 | [diff] [blame] | 120 | >>> import base64 |
| 121 | >>> import os |
| 122 | >>> from cryptography.fernet import Fernet |
| 123 | >>> from cryptography.hazmat.backends import default_backend |
| 124 | >>> from cryptography.hazmat.primitives import hashes |
| 125 | >>> from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC |
| 126 | >>> password = b"password" |
| 127 | >>> salt = os.urandom(16) |
| 128 | >>> kdf = PBKDF2HMAC( |
| 129 | ... algorithm=hashes.SHA256(), |
| 130 | ... length=32, |
| 131 | ... salt=salt, |
| 132 | ... iterations=100000, |
| 133 | ... backend=default_backend() |
| 134 | ... ) |
| 135 | >>> key = base64.urlsafe_b64encode(kdf.derive(password)) |
| 136 | >>> f = Fernet(key) |
| 137 | >>> token = f.encrypt(b"Secret message!") |
| 138 | >>> token |
| 139 | '...' |
| 140 | >>> f.decrypt(token) |
| 141 | 'Secret message!' |
Terry Chia | b964a5c | 2015-08-29 18:53:47 +0800 | [diff] [blame] | 142 | |
| 143 | In this scheme, the salt has to be stored in a retrievable location in order |
| 144 | to derive the same key from the password in the future. |
| 145 | |
| 146 | The iteration count used should be adjusted to be as high as your server can |
Terry Chia | 7126e61 | 2015-08-29 22:28:51 +0800 | [diff] [blame] | 147 | tolerate. A good default is at least 100,000 iterations which is what Django |
Alex Gaynor | 4e87cf4 | 2017-01-21 08:50:53 -0500 | [diff] [blame] | 148 | recommended in 2014. |
Terry Chia | b964a5c | 2015-08-29 18:53:47 +0800 | [diff] [blame] | 149 | |
Alex Gaynor | b32b491 | 2014-01-23 16:24:13 -0600 | [diff] [blame] | 150 | Implementation |
| 151 | -------------- |
| 152 | |
| 153 | Fernet is built on top of a number of standard cryptographic primitives. |
| 154 | Specifically it uses: |
| 155 | |
| 156 | * :class:`~cryptography.hazmat.primitives.ciphers.algorithms.AES` in |
| 157 | :class:`~cryptography.hazmat.primitives.ciphers.modes.CBC` mode with a |
| 158 | 128-bit key for encryption; using |
Alex Gaynor | 8e6b331 | 2014-06-30 11:39:27 -0700 | [diff] [blame] | 159 | :class:`~cryptography.hazmat.primitives.padding.PKCS7` padding. |
Alex Gaynor | b32b491 | 2014-01-23 16:24:13 -0600 | [diff] [blame] | 160 | * :class:`~cryptography.hazmat.primitives.hmac.HMAC` using |
| 161 | :class:`~cryptography.hazmat.primitives.hashes.SHA256` for authentication. |
| 162 | * Initialization vectors are generated using ``os.urandom()``. |
| 163 | |
| 164 | For complete details consult the `specification`_. |
| 165 | |
Alex Gaynor | 333fb10 | 2013-10-31 10:27:35 -0700 | [diff] [blame] | 166 | |
| 167 | .. _`Fernet`: https://github.com/fernet/spec/ |
Alex Gaynor | b32b491 | 2014-01-23 16:24:13 -0600 | [diff] [blame] | 168 | .. _`specification`: https://github.com/fernet/spec/blob/master/Spec.md |