{ "info": { "author": "Ofek Lev", "author_email": "ofekmeister@gmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "License :: OSI Approved :: MIT License", "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy" ], "description": "Privy\n=====\n\n.. image:: https://img.shields.io/pypi/v/privy.svg?style=flat-square\n :target: https://pypi.org/project/privy\n\n.. image:: https://img.shields.io/travis/ofek/privy/master.svg?style=flat-square\n :target: https://travis-ci.org/ofek/privy\n\n.. image:: https://img.shields.io/codecov/c/github/ofek/privy/master.svg?style=flat-square\n :target: https://codecov.io/gh/ofek/privy\n\n.. image:: https://img.shields.io/pypi/pyversions/privy.svg?style=flat-square\n :target: https://pypi.org/project/privy\n\n.. image:: https://img.shields.io/pypi/l/privy.svg?style=flat-square\n :target: https://choosealicense.com/licenses\n\n-----\n\nPrivy is a small and fast utility for password-protecting secret data such as\nAPI keys, cryptocurrency wallets, or seeds for digital signatures.\n\nTable of Contents\n~~~~~~~~~~~~~~~~~\n\n.. contents::\n :backlinks: top\n :local:\n\nUsage\n-----\n\nSay for example you are using GnuPG. You are about to sign a message but it first\nrequires your password. Does your password become the input to instantiate your\nprivate key? No, it is first hashed by a secure `key derivation function`_. That\nhash then becomes the input to a symmetric cipher such as AES which then decrypts\nyour stored private key. That is what Privy does.\n\nFear not! With Privy, this become trivially easy:\n\n.. code-block:: python\n\n >>> import privy\n >>>\n >>> # After creating secret, immediately encrypt it using Privy.\n >>> data = b'secret'\n >>>\n >>> hidden = privy.hide(data, ask_for_password())\n >>> hidden\n '1$2$fL7xRh8WKe...'\n\nNow you can safely store or transmit the hidden secret. Whenever your user needs\nto use their secret again, ask for their password to take a peek.\n\n.. code-block:: python\n\n >>> privy.peek(hidden, password)\n b'secret'\n\nInstallation\n------------\n\nPrivy is available on Linux/macOS and Windows and supports Python 2.7, 3.3+, PyPy, and PyPy3.3-5.5+.\n\n.. code-block:: bash\n\n $ pip install privy\n\nEncryption scheme\n-----------------\n\nSecrets are encrypted using the `Fernet`_ protocol. Specifically, it uses AES for\nencryption and has built-in authentication using HMAC. The private key used for\nencryption is derived from the password using a `key derivation function`_. The\nkey derivation function used is `Argon2`_, the winner of the `Password Hashing\nCompetition`_. Both Argon2i and Argon2d variants are supported.\n\nEncrypted format\n----------------\n\n``ascii(Argon2 algorithm || security level || base64(salt) || base64(Fernet token))``\n\nAPI\n---\n\nThere are 2 functions: ``hide`` and ``peek``.\n\nhide\n^^^^\n\n``hide(secret, password, security=2, salt=None, server=True)``\n\nEncrypts ``secret`` using ``password``. Returns the hidden secret as unicode.\n\n* Parameters\n\n - **secret** (``bytes``) - The secret to encrypt.\n - **password** (``bytes`` or ``unicode``) - The password used to access the secret.\n - **security** (``int``) - A number 0-20 inclusive. Higher values are more secure at\n the cost of slower computation and greater use of memory. See `security levels`_.\n - **salt** (``bytes``) - The salt used for the password hash. Defaults to ``os.urandom(32)``.\n - **server** (``bool``) - If ``True``, it is assumed side-channel attack protection is\n needed and therefore the Argon2i algorithm will be used. Otherwise, the password will\n be hashed using the Argon2d algorithm.\n\npeek\n^^^^\n\n``peek(hidden, password, expires=None)``\n\nDecrypts ``hidden`` using ``password``. Returns the secret as ``bytes``.\n\n* Parameters\n\n - **hidden** (``bytes`` or ``unicode``) - The hidden secret to decrypt.\n - **password** (``bytes`` or ``unicode``) - The password used to access the secret.\n - **expires** (``int``) - The maximum number of seconds since encryption that\n is allowed. The default is no expiration.\n\nA ``ValueError`` will be raised if the password is wrong, the password was attempted on a\ndifferent hidden secret, or the number of seconds since encryption is > ``expires`` argument.\n\nSecurity levels\n---------------\n\nAll expected times were taken from tests on an Intel Core i7-2670QM @ 2.2 GHz when decrypting\na 256 KiB secret.\n\nThis is the command, where ``SL`` is the desired security level:\n\n.. code-block:: bash\n\n $ python -m timeit -s \"import privy, os; pw = 'password'; s = os.urandom(1024 * 256); h = privy.hide(s, pw, SL)\" \"privy.peek(h, pw)\"\n\n+--------+-----------------+---------------+-----------------+\n| Levels | Argon2 settings | Expected time | Notes |\n+========+=================+===============+=================+\n| 0 | m=8 KiB, t=1 | 7 msec | Lowest possible |\n+--------+-----------------+---------------+-----------------+\n| 1 | m=4 MiB, t=10 | 54 msec | |\n+--------+-----------------+---------------+-----------------+\n| 2 | m=8 MiB, t=10 | 99 msec | Default |\n+--------+-----------------+---------------+-----------------+\n| 3 | m=32 MiB, t=10 | 367 msec | |\n+--------+-----------------+---------------+-----------------+\n| 4 | m=48 MiB, t=10 | 540 msec | |\n+--------+-----------------+---------------+-----------------+\n| 5 | m=96 MiB, t=10 | 1.1 sec | Good choice |\n+--------+-----------------+---------------+-----------------+\n| 6 | m=256 MiB, t=10 | 3 sec | |\n+--------+-----------------+---------------+-----------------+\n| 7 | m=512 MiB, t=10 | 6 sec | |\n+--------+-----------------+---------------+-----------------+\n| 8 | m=768 MiB, t=10 | 9 sec | |\n+--------+-----------------+---------------+-----------------+\n| 9 | m=1 GiB, t=10 | 12.2 sec | |\n+--------+-----------------+---------------+-----------------+\n| 10 | m=2 GiB, t=20 | 48 sec | For use on |\n+--------+-----------------+---------------+ users' machines |\n| 11 | m=3 GiB, t=30 | 107 | |\n+--------+-----------------+---------------+ |\n| 12 | m=4 GiB, t=40 | ? | |\n+--------+-----------------+---------------+ |\n| 13 | m=5 GiB, t=50 | ? | |\n+--------+-----------------+---------------+ |\n| 14 | m=6 GiB, t=60 | ? | |\n+--------+-----------------+---------------+ |\n| 15 | m=7 GiB, t=70 | ? | |\n+--------+-----------------+---------------+ |\n| 16 | m=8 GiB, t=80 | ? | |\n+--------+-----------------+---------------+ |\n| 17 | m=9 GiB, t=90 | ? | |\n+--------+-----------------+---------------+ |\n| 18 | m=10 GiB, t=100 | ? | |\n+--------+-----------------+---------------+ |\n| 19 | m=11 GiB, t=110 | ? | |\n+--------+-----------------+---------------+ |\n| 20 | m=12 GiB, t=120 | ? | |\n+--------+-----------------+---------------+-----------------+\n\nLicense\n-------\n\nPrivy is distributed under the terms of either\n\n- `MIT License `_\n- `Apache License, Version 2.0 `_\n\nat your option.\n\nChangelog\n---------\n\nImportant changes are emphasized.\n\n6.0.0\n^^^^^\n\n* **Breaking:** Support for Python 3.3 has been dropped.\n\n5.0.0\n^^^^^\n\n* **Breaking:** Privy is now dual-licensed under the terms of MIT and Apache v2.0.\n* Only documented methods ``hide`` and ``peek`` are now exposed in the root namespace.\n* Travis now runs tests with the latest versions of PyPy and PyPy3.\n* Improvements to documentation.\n\n4.0.0\n^^^^^\n\n* **Breaking:** For saner conformity, security level 7 now utilizes 512 MiB of RAM instead of 448.\n* Major improvements to documentation.\n\n3.0.0\n^^^^^\n\n* Added security levels 11-20. These are quite resource intensive and are therefore\n only acceptable for individual use.\n\n2.0.1\n^^^^^\n\n* **Breaking:** Due to requests, the encrypted format now uses url-safe base64 instead of hex.\n\n1.0.0\n^^^^^\n\n* Initial release\n\n.. _Fernet: https://github.com/fernet/spec/blob/master/Spec.md\n.. _key derivation function: https://en.wikipedia.org/wiki/Key_derivation_function\n.. _Argon2: https://github.com/p-h-c/phc-winner-argon2\n.. _Password Hashing Competition: https://en.wikipedia.org/wiki/Password_Hashing_Competition\n.. _security levels: https://github.com/ofek/privy#security-levels\n\n\n", "description_content_type": null, "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/ofek/privy", "keywords": "passwords,secrets,encryption,keys,aes,hmac", "license": "MIT/Apache-2.0", "maintainer": "", "maintainer_email": "", "name": "privy", "package_url": "https://pypi.org/project/privy/", "platform": "", "project_url": "https://pypi.org/project/privy/", "project_urls": { "Homepage": "https://github.com/ofek/privy" }, "release_url": "https://pypi.org/project/privy/6.0.0/", "requires_dist": [ "argon2-cffi", "cryptography" ], "requires_python": "", "summary": "Password-protected data made easy.", "version": "6.0.0" }, "last_serial": 3035599, "releases": { "1.0.0": [ { "comment_text": "", "digests": { "md5": "76888c18dff23d6fbfc3249e72a9b3a2", "sha256": "9a598204a8b216a97457e13a2732683fc91c5b519ee2c9fb6e04a447bb44efe8" }, "downloads": -1, "filename": "privy-1.0.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "76888c18dff23d6fbfc3249e72a9b3a2", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 8024, "upload_time": "2017-02-14T19:24:42", "url": "https://files.pythonhosted.org/packages/d0/dc/2c5793302a1f93443de58f5ebf9d5f739614291460624b6ca95907bb18ee/privy-1.0.0-py2.py3-none-any.whl" } ], "2.0.1": [ { "comment_text": "", "digests": { "md5": "8b6d22fe035e432d747772d10441c959", "sha256": "5b2fd0793d42c72ee16e8434fd3abedee0e69abfc995165527a340f931722a5d" }, "downloads": -1, "filename": "privy-2.0.1-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "8b6d22fe035e432d747772d10441c959", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 12065, "upload_time": "2017-02-15T04:12:21", "url": "https://files.pythonhosted.org/packages/2d/3e/7ae1b42708f450a7bd43d387ed0b306ececc18ef55bf54eb2a177e62ceda/privy-2.0.1-py2.py3-none-any.whl" } ], "3.0.0": [ { "comment_text": "", "digests": { "md5": "e7f3a0e0936be2299ccd74a121ab7838", "sha256": "6a5af37876a60a9e8986df9539bc38d09e059c74026290f8a8c454edfbdbc333" }, "downloads": -1, "filename": "privy-3.0.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "e7f3a0e0936be2299ccd74a121ab7838", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 12636, "upload_time": "2017-02-16T19:26:00", "url": "https://files.pythonhosted.org/packages/dd/65/a6429465693b8d2b61218141339552aaf6df8fe3768e23eed1e1892747be/privy-3.0.0-py2.py3-none-any.whl" } ], "4.0.0": [ { "comment_text": "", "digests": { "md5": "f95e744facb5740b87681c6b32ea8c11", "sha256": "e623c70360ae8913f9431dba34be9001e4a2d281f58cd076c811cde26ba62378" }, "downloads": -1, "filename": "privy-4.0.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "f95e744facb5740b87681c6b32ea8c11", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 13540, "upload_time": "2017-02-18T21:42:23", "url": "https://files.pythonhosted.org/packages/cb/59/ca88268c1d40ccf9522ed072412b4ef0d5c248df01bde9e356bfd82f6860/privy-4.0.0-py2.py3-none-any.whl" } ], "5.0.0": [ { "comment_text": "", "digests": { "md5": "3733439113edeecc47d03dcc6a024628", "sha256": "e64e24a359f746f67055bf3197ad9fd356fb9d7076f62b3a8b761e817e6e4029" }, "downloads": -1, "filename": "privy-5.0.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "3733439113edeecc47d03dcc6a024628", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 14187, "upload_time": "2017-06-30T22:39:10", "url": "https://files.pythonhosted.org/packages/69/14/467ff04fb2bf83f047ccc7d6eca96072c69aad9bdadbe6bcb444567da58d/privy-5.0.0-py2.py3-none-any.whl" } ], "6.0.0": [ { "comment_text": "", "digests": { "md5": "b2464c33e3874bace71824563455908b", "sha256": "e68679bb4006ce83206d9a7af1158cf4d56a2ed6861ee39276907be618dfb8d9" }, "downloads": -1, "filename": "privy-6.0.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "b2464c33e3874bace71824563455908b", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 14243, "upload_time": "2017-07-20T02:17:57", "url": "https://files.pythonhosted.org/packages/ef/ae/c3637856cdfe66518133f2cdbb820e30745cdb02b43ece41e7ccb9d7f818/privy-6.0.0-py2.py3-none-any.whl" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "b2464c33e3874bace71824563455908b", "sha256": "e68679bb4006ce83206d9a7af1158cf4d56a2ed6861ee39276907be618dfb8d9" }, "downloads": -1, "filename": "privy-6.0.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "b2464c33e3874bace71824563455908b", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 14243, "upload_time": "2017-07-20T02:17:57", "url": "https://files.pythonhosted.org/packages/ef/ae/c3637856cdfe66518133f2cdbb820e30745cdb02b43ece41e7ccb9d7f818/privy-6.0.0-py2.py3-none-any.whl" } ] }