Skip to main content

Simple, strong and standardized keyed password storage

Project description

# porridge [![PyPI](https://img.shields.io/pypi/v/porridge.svg)](https://pypi.org/project/porridge) [![Build Status](https://travis-ci.org/thusoy/porridge.svg?branch=master)](https://travis-ci.org/thusoy/porridge) [![Windows build status](https://ci.appveyor.com/api/projects/status/y51rewx877d522b5/branch/master?svg=true)](https://ci.appveyor.com/project/thusoy/porridge/branch/master)

Simple, strong and standardized keyed password storage.

Keyed password storage utilizes server-side secrets to ensure passwords cannot be brute-forced offline if your database is leaked. A leak could happen through a SQL injection or a compromised backup, or a host of other sadly quite common webapp vulnerabilities.

While many password storage schemes like PBKDF2, bcrypt, scrypt and the likes will make recovering the passwords offline slow, a resourceful and patient attacker will eventually be able to recover most of them. Porridge makes this entirely impossible unless your secret is also leaked, which is often not the case for many common vulnerabilities.

Note that utilizing porridge is not magical solution to passwords on the internet, a complete solution should still enforce at least a password policy, secure password resets, rate-limiting and U2F/2FA. Have experienced security engineers set up something for you, or use high-level libraries that take care of it for you.


Installing
----------

$ pip install porridge

Pre-built wheels is available for Windows, Linux and macOS. Building from source requires cffi >= 1.0.0, which in turn requires libffi and python headers to compile.


Usage
-----

```python
from porridge import Porridge

porridge = Porridge('myfirstkey:myfirstsecret')

boiled_password = porridge.boil('password')
if porridge.verify('password', boiled_password):
print('Success!')
else:
print('Fail!')
```

This setup ensures that even if your database is leaked, your users' passwords are irrecoverable by an attacker that does not also possess the `myfirstsecret` value. Load it securely like you would other credentials like API keys, database passwords, session tokens and similar.

This shell snippet is handy to create strong secrets:

```bash
$ echo "$(date +%Y%m%d):$(openssl rand -base64 30)"
```

This string will thus grow regularly. After some time, it'll look something like

keyid3:key3,keyid2:key2,keyid1:key1

The first key in the list (in this case, keyid3) will be used to boil new passwords.

Old keys are necessary to verify the passwords of users who haven't logged in since the secret was rotated. Secrets can be dropped from the config when no users have passwords using that id anymore, which you can tell from the `keyid` field in the boiled password.

**Note**: Create a `Porridge` instance once and re-use it across your application, it does some parameter validation and stuff on startup you'd rather not want to redo for every passord you process.


Local development
-----------------

$ ./configure
$ ./test

Continually running tests whenever source changes:

$ ./tools/watch_and_run_tests.sh


Motivation
----------

I couldn't find any existing solutions that utilizes argon2's server-side secret feature, as most libraries only wrap the high-level interfaces, which sadly don't enable setting secrets.

Some guiding principles for this project:

- People should not have to configure cryptographic parameters
- UX is a security feature
- The database is not trusted, neither to keep things secret, nor to keep things sane
- Following nothing more than the quickstart should result in a very secure implementation
- Migrating from existing solutions should be easy


Maintenance
-----------

Keeping this running over an extended period requires two things:
- Adding new secrets regularly (twice a year is probably fine), and whenever you suspect a breach
- Using `needs_update()` to store new boils where the password was stored with old parameters

The first is to ensure that if your servers at one point is compromised, future passwords are not impacted.

The second point ensures that every time one of your users log in, the parameters their existing boiled password is stored under are still strong and the secret current, otherwise it'll be re-stored.

The only thing you need to do this is to check `needs_update()` after a password has been verified, and to store the updated one if that's the case:

```python
from porridge import Porridge

porridge = Porridge('keyid2:key2,keyid1:key1')

password = ... # get this from the user
old_boiled_password = ... # Get this from your database

if porridge.verify(password, old_boiled_password):
print('Success!')
if porridge.needs_update(old_boiled_password):
# update the password in the database
new_boiled_password = porridge.boil(password)
print('Storing new boiled password to database')
else:
print('Fail!')
```

The default parameters will be bumped regularly with new releases of porridge, thus as long as you install updates this should keep everything fresh.

Note that to avoid DDoS itself, a Porridge instance will refuse to verify passwords boiled with parameters that are stronger than a given threshold of it's own parameters. This is to ensure that if you by accident try to verify a password with a time cost or memory cost in the millions, you will not have to wait for the heat death of the universe to regain control of your computer. But we also want to ensure that we can upgrade parameters gradually across a fleet of instances without some suddenly starting to fail, thus when you're increasing the cost parameters you should ensure you increase them with less than the `parameter_threshold`. The default threshold is 4, thus you'll be fine if you double parameters, but if you want to bump parameters with more than 4x you should increase `default_threshold` across your fleet first.


FAQ
---

*Q: I notice the word "hash" isn't used much by porridge, why?*
A: Because it's too easy to get stuff wrong when communicated to people who are not cryptographers, which include most of us. Experienced cryptographers do a mental translation of "hash" to "memory-hard key stretching" whenever they're in a password context, but the rest of us don't. Thus it's too easy for non-cryptographers to write password storage solutions that either store passwords in plaintext, or just use an actual "hash", leading to puppies dying left and right. Thus for porridge, passwords are "boiled". If non-cryptographers hear that they're supposed to boil passwords, any decent search engine will ensure they end up with a very robust solution. This project is named porridge, as it's one dish that requires salt and a long boil, but also avoids squatting a "password-boiler" package that makes it hard for other packages to attempt to solve the same problem. Eran Hammer has some [more thoughts on this](https://hueniverse.com/the-myth-of-descriptive-module-names-d34d5feaa273).

*Q: How do I migrate to porridge from pbkdf2/bcrypt/scrypt/plain argon2?*
A: Add a new column in your database to store the boiled passwords, add porridge and boil passwords with it in addition to your existing scheme and store them to the new column. When verifying, verify with both your existing scheme and porridge if there's anything in the new column. When you deem that few enough users haven't gotten their passwords boiled by porridge yet, drop the old password column and stop using the old scheme. The users who hasn't gotten new boiled passwords will be forced through password reset, but otherwise no one will notice any difference. If you are already using argon2 but without server-side secrets, porridge can dropped in directly. Note that the max length of a boiled password is *265* characters, but that requires using the associated data feature that is not exposed through porridge, so you're probably fine if your existing columns only allows 255 characters.

*Q: Why "porridge"?*
A: Because good porridge requires more than just salt, takes a long time to boil, and you cannot separate its ingredients after they've been boiled. And I was hungry when starting writing this. And we need better terminology for password storage, see the first question.

*Q: Could you release wheels for platform X?*
A: All releases of Porridge use wheels built by Travis CI and AppVeyor (see `./tools/release.py` for how it's done). If you need another platform supported, like a specific version of PyPy on some platform, open a PR adding it to the build matrix, and it'll automatically be part of the next release.


Security
--------

Porridge wraps the reference implementation of [argon2](https://github.com/P-H-C/phc-winner-argon2), the winner of the Password Hashing Competition, which means it has been studied in detail by very experienced cryptanalysts.

The default parameters aims for ~1ms boiling time with 512kB memory usage, adjust these to suit your environment and your requirements. If you run on very performant hardware you should be able to sustain higher costs:

```python
porridge = Porridge('key1:secret1', time_cost=8, memory_cost=1024, parallelism=16)
```

`time_cost` gives the number of iterations of the core algorithm, measure to see the impact in your environment.
`memory_cost` is how many kibibytes of memory to use for each password boiled.
`parallelism` is how many threads to use for each password boiled.

If you find a security-critical bug that you'd rather not disclose openly in the issues, shoot an email to hello at thusoy.com. This project does not have a bug bounty, but you will be credited (if you wish) here in the README and in the changelog.


Alternatives
------------

If you can't apply server-side secrets, plain [argon2](https://github.com/hynek/argon2_cffi) is the recommended way to store your passwords as of best practices in 2017. To utilize server-side secrets with other schemes you can HMAC the password with your secret before passing it to your key stretching function, but it'll be very hard to rotate this secret without invalidating all your passwords.


Credits
-------

Many thanks to [argon2_cffi](https://github.com/hynek/argon2_cffi) for a great starting point for wrapping argon2.


Troubleshooting
---------------

### Import fails with libpython shared object not found

If you get a traceback similar to this when trying to import the module:

```
from ._ffi import ffi, lib
ImportError: libpython2.7.so.1.0: cannot open shared object file: No such file or directory
```

You are probably missing the `python-dev` package. On ubuntu/debian: `sudo apt-get install python-dev`.


### Installation fails with 'compilation terminated'

If installing the module fails with a traceback like
```
c/_cffi_backend.c:15:17: fatal error: ffi.h: No such file or directory

#include <ffi.h>

^

compilation terminated.

error: command 'x86_64-linux-gnu-gcc' failed with exit status 1
```

You are trying to install from source (might happen if using an older pip which doesn't install manylinux1 wheels) and the compiler can't find the libraries it needs. On ubuntu/debian: `sudo apt-get install libffi-dev python-dev`. Updating your pip should also work and might not require root if you're running in a virtualenv.


Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

porridge-1.0.0.tar.gz (82.9 kB view details)

Uploaded Source

Built Distributions

porridge-1.0.0-cp36-cp36m-win_amd64.whl (40.6 kB view details)

Uploaded CPython 3.6m Windows x86-64

porridge-1.0.0-cp36-cp36m-win32.whl (37.5 kB view details)

Uploaded CPython 3.6m Windows x86

porridge-1.0.0-cp36-cp36m-manylinux1_x86_64.whl (78.6 kB view details)

Uploaded CPython 3.6m

porridge-1.0.0-cp36-cp36m-macosx_10_12_x86_64.whl (38.5 kB view details)

Uploaded CPython 3.6m macOS 10.12+ x86-64

porridge-1.0.0-cp36-cp36m-macosx_10_11_x86_64.whl (37.4 kB view details)

Uploaded CPython 3.6m macOS 10.11+ x86-64

porridge-1.0.0-cp35-cp35m-win_amd64.whl (40.6 kB view details)

Uploaded CPython 3.5m Windows x86-64

porridge-1.0.0-cp35-cp35m-win32.whl (37.5 kB view details)

Uploaded CPython 3.5m Windows x86

porridge-1.0.0-cp35-cp35m-manylinux1_x86_64.whl (78.6 kB view details)

Uploaded CPython 3.5m

porridge-1.0.0-cp35-cp35m-macosx_10_12_x86_64.whl (38.5 kB view details)

Uploaded CPython 3.5m macOS 10.12+ x86-64

porridge-1.0.0-cp35-cp35m-macosx_10_11_x86_64.whl (37.4 kB view details)

Uploaded CPython 3.5m macOS 10.11+ x86-64

porridge-1.0.0-cp34-cp34m-win_amd64.whl (36.4 kB view details)

Uploaded CPython 3.4m Windows x86-64

porridge-1.0.0-cp34-cp34m-win32.whl (35.8 kB view details)

Uploaded CPython 3.4m Windows x86

porridge-1.0.0-cp34-cp34m-manylinux1_x86_64.whl (78.6 kB view details)

Uploaded CPython 3.4m

porridge-1.0.0-cp34-cp34m-macosx_10_12_x86_64.whl (38.5 kB view details)

Uploaded CPython 3.4m macOS 10.12+ x86-64

porridge-1.0.0-cp34-cp34m-macosx_10_11_x86_64.whl (37.4 kB view details)

Uploaded CPython 3.4m macOS 10.11+ x86-64

porridge-1.0.0-cp33-cp33m-win_amd64.whl (36.4 kB view details)

Uploaded CPython 3.3m Windows x86-64

porridge-1.0.0-cp33-cp33m-win32.whl (35.8 kB view details)

Uploaded CPython 3.3m Windows x86

porridge-1.0.0-cp33-cp33m-manylinux1_x86_64.whl (78.5 kB view details)

Uploaded CPython 3.3m

porridge-1.0.0-cp27-none-manylinux1_x86_64.whl (81.8 kB view details)

Uploaded CPython 2.7

porridge-1.0.0-cp27-cp27m-win_amd64.whl (36.6 kB view details)

Uploaded CPython 2.7m Windows x86-64

porridge-1.0.0-cp27-cp27m-win32.whl (35.6 kB view details)

Uploaded CPython 2.7m Windows x86

porridge-1.0.0-cp27-cp27m-macosx_10_12_x86_64.whl (38.3 kB view details)

Uploaded CPython 2.7m macOS 10.12+ x86-64

porridge-1.0.0-cp27-cp27m-macosx_10_11_x86_64.whl (37.3 kB view details)

Uploaded CPython 2.7m macOS 10.11+ x86-64

File details

Details for the file porridge-1.0.0.tar.gz.

File metadata

  • Download URL: porridge-1.0.0.tar.gz
  • Upload date:
  • Size: 82.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No

File hashes

Hashes for porridge-1.0.0.tar.gz
Algorithm Hash digest
SHA256 2f31eea4c245627c10aef36dc6a428d71eae2ad8b13435f161f9458f8f40725a
MD5 b3281f6c3673763e291c57eae5f6145e
BLAKE2b-256 c0b9493a003cc8c4a3e8222670c6ae882169e1120bceccf0b4583916cbda778e

See more details on using hashes here.

File details

Details for the file porridge-1.0.0-pp256-pypy_41-manylinux1_x86_64.whl.

File metadata

File hashes

Hashes for porridge-1.0.0-pp256-pypy_41-manylinux1_x86_64.whl
Algorithm Hash digest
SHA256 bc3bba88b4b4fa0b906bc6b24810d0df0b9bd66731be5887208605f44d0fb8bf
MD5 4933f5ada51a0e1560b16df532a468d4
BLAKE2b-256 7e91445dc838773a0de9d55212d0725a55fc3d3e27903039a87d0236d5d1d3de

See more details on using hashes here.

File details

Details for the file porridge-1.0.0-pp254-pypy_41-manylinux1_x86_64.whl.

File metadata

File hashes

Hashes for porridge-1.0.0-pp254-pypy_41-manylinux1_x86_64.whl
Algorithm Hash digest
SHA256 d7b2de8522c2205f3492ace59efaa07ce36826845bdfe30c6fc56589eee045ef
MD5 75e4ebbb78769dff0f8d4cd0bf97b6ab
BLAKE2b-256 9451964aa2736d2133d90575900fd4ac87773c87ada0928d825a5c3fd93b2984

See more details on using hashes here.

File details

Details for the file porridge-1.0.0-pp253-pypy_41-manylinux1_x86_64.whl.

File metadata

File hashes

Hashes for porridge-1.0.0-pp253-pypy_41-manylinux1_x86_64.whl
Algorithm Hash digest
SHA256 18cc020cfd873bc702476b5892ba2a2102a7bc2a153194f11b8e428bfe5fa7cc
MD5 eb37dad7c6f3c94d8300e84c5e376f02
BLAKE2b-256 bd210dc0b1ea80d14d95275dd1f9a39d8dd5cf59e12d56d46ba537db04702c3c

See more details on using hashes here.

File details

Details for the file porridge-1.0.0-cp36-cp36m-win_amd64.whl.

File metadata

File hashes

Hashes for porridge-1.0.0-cp36-cp36m-win_amd64.whl
Algorithm Hash digest
SHA256 3128e84b44fc561fffb22f5ef1871b182992d970b3c74ce839ab813b3cceaa66
MD5 27a172536e51230cc09f77084487b483
BLAKE2b-256 24c36f235888f5460a149dd3b0b7d85fd72ddcdd8d80783b4afc9bbecb74ab31

See more details on using hashes here.

File details

Details for the file porridge-1.0.0-cp36-cp36m-win32.whl.

File metadata

File hashes

Hashes for porridge-1.0.0-cp36-cp36m-win32.whl
Algorithm Hash digest
SHA256 35a3a80c46ae26c6bbb331053f1c85560dc9cb2267610faa1d5142cf23f8d8f8
MD5 1835982bf297dd6f0c405e1ab7cb8892
BLAKE2b-256 1f5ede6f3609e9cdf28f7871de6deb46a84480609291bb847062cca3f2a53f45

See more details on using hashes here.

File details

Details for the file porridge-1.0.0-cp36-cp36m-manylinux1_x86_64.whl.

File metadata

File hashes

Hashes for porridge-1.0.0-cp36-cp36m-manylinux1_x86_64.whl
Algorithm Hash digest
SHA256 53b8255f061854f997a8f0ebc6a9d0afe71bbbd46dd395c7f145f111b1d0b08e
MD5 fd809432bfc188aabaa412042d501475
BLAKE2b-256 054e3f63d8bbbc005d2b71ec46c492e809f4ad652c243b894d74ef756123d406

See more details on using hashes here.

File details

Details for the file porridge-1.0.0-cp36-cp36m-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for porridge-1.0.0-cp36-cp36m-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 fbaade9bf6de0858844e5a79ef442516ea165fe8f942e2851d1e4d009a9acaa3
MD5 e3198b41adcc7e3ac6b72f614dff7bb2
BLAKE2b-256 0e79e6130e89e063fe0baddc686b2cefd163ae1e4190f0bd044218abc2effed4

See more details on using hashes here.

File details

Details for the file porridge-1.0.0-cp36-cp36m-macosx_10_11_x86_64.whl.

File metadata

File hashes

Hashes for porridge-1.0.0-cp36-cp36m-macosx_10_11_x86_64.whl
Algorithm Hash digest
SHA256 264cc8d3e849e36778ca7c266db820e909af3bf9fc78746a54a94cb34c8debaf
MD5 2797abb32edcc2c907626e577932b85d
BLAKE2b-256 e09e0a9ba62b671f053b433770ae4e64a8cacd997316df6713e9d710ba383345

See more details on using hashes here.

File details

Details for the file porridge-1.0.0-cp35-cp35m-win_amd64.whl.

File metadata

File hashes

Hashes for porridge-1.0.0-cp35-cp35m-win_amd64.whl
Algorithm Hash digest
SHA256 14c2feb95b190b89a4b633f6963d83960781c3e87637da5488660914895e18fa
MD5 a5bbe1d3cb3ae15fad0baf31d620213a
BLAKE2b-256 0dbba518b9fb936d1e324d8a6a79c945c41720acde683c217e07baca299c3142

See more details on using hashes here.

File details

Details for the file porridge-1.0.0-cp35-cp35m-win32.whl.

File metadata

File hashes

Hashes for porridge-1.0.0-cp35-cp35m-win32.whl
Algorithm Hash digest
SHA256 f9be336b29306fb75f9f2dbdae826998b0bf78d1b83e4b5dbe608722c90b1eca
MD5 44088848629b20576c64f26b1216c622
BLAKE2b-256 ce1cb21a5c24d883fc01c2a596c1e346f57ebcd74ef6e3e44c8a87332ceb0c55

See more details on using hashes here.

File details

Details for the file porridge-1.0.0-cp35-cp35m-manylinux1_x86_64.whl.

File metadata

File hashes

Hashes for porridge-1.0.0-cp35-cp35m-manylinux1_x86_64.whl
Algorithm Hash digest
SHA256 3865185c01b928f61c54eb46b2b648dff51b8989355b01cee74983970ec3da76
MD5 139f594f35940e994fc024d660ce1f72
BLAKE2b-256 13aecb1a475a57320c2b91ebb0750be656edcc876e5484ed1595527c40a314bc

See more details on using hashes here.

File details

Details for the file porridge-1.0.0-cp35-cp35m-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for porridge-1.0.0-cp35-cp35m-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 29e01211b0d500dbcb7d0a5bef9f0316106ec76f657f6d223cbb8c7d996cc79f
MD5 936efc2e2034c223dd5ecbf694926919
BLAKE2b-256 4c262a2f704d4a9ae1e6570fe7043fabe01b3b473c89c6ec8b83abad070a707a

See more details on using hashes here.

File details

Details for the file porridge-1.0.0-cp35-cp35m-macosx_10_11_x86_64.whl.

File metadata

File hashes

Hashes for porridge-1.0.0-cp35-cp35m-macosx_10_11_x86_64.whl
Algorithm Hash digest
SHA256 581ac95e9a6c315a5a6c7d55119d0da43637cd4a68bbf5265a74e20d15d7d322
MD5 e1cbcc9692ef3fa592671643efe2766d
BLAKE2b-256 30174a3208333b1247f08ed0cac8eb7398e1608894cf7d6e6845179bc166f635

See more details on using hashes here.

File details

Details for the file porridge-1.0.0-cp34-cp34m-win_amd64.whl.

File metadata

File hashes

Hashes for porridge-1.0.0-cp34-cp34m-win_amd64.whl
Algorithm Hash digest
SHA256 a6addaf24ba823186d0c0d2348de06e8a4fd9360db9947d21a5b0312becc228a
MD5 51611d639ddb27bbc5d395c64d8c6aca
BLAKE2b-256 8ad1f550ec7fe127fa82fa9cb7d0a6d220084c1190bcd65052ecd00d495a4d76

See more details on using hashes here.

File details

Details for the file porridge-1.0.0-cp34-cp34m-win32.whl.

File metadata

File hashes

Hashes for porridge-1.0.0-cp34-cp34m-win32.whl
Algorithm Hash digest
SHA256 57b46ba8fe929f51a8f958af358a3f7c62400d38a9dda04e618c54340b184a42
MD5 def4493d19b2957636a9b412e773616a
BLAKE2b-256 00eb0a0282648aea451c043c123bf7421b60f9292b844826d6bf704bb43bdfb5

See more details on using hashes here.

File details

Details for the file porridge-1.0.0-cp34-cp34m-manylinux1_x86_64.whl.

File metadata

File hashes

Hashes for porridge-1.0.0-cp34-cp34m-manylinux1_x86_64.whl
Algorithm Hash digest
SHA256 c792ea90906d2f4d70f05ecec8346afaa8c7ca9ae3037559aae15c37040aa277
MD5 7015e4ab0a0fc5b3bb4f715a4b166242
BLAKE2b-256 e933fc9d45da4be3a9d1fa6efaf155774540c87d1956165be1f750dc54ea3e59

See more details on using hashes here.

File details

Details for the file porridge-1.0.0-cp34-cp34m-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for porridge-1.0.0-cp34-cp34m-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 c52dee1b1a301783dedc5a7fe563d6dd1fad7ee014f6d19ef89e0f7d0d546c51
MD5 4b2327067b72b5cd227ba0a7c9528739
BLAKE2b-256 befe09b94df72adc840193d76b54fff1fbf9b0fa60a68d66ffe0a4631d55c6c3

See more details on using hashes here.

File details

Details for the file porridge-1.0.0-cp34-cp34m-macosx_10_11_x86_64.whl.

File metadata

File hashes

Hashes for porridge-1.0.0-cp34-cp34m-macosx_10_11_x86_64.whl
Algorithm Hash digest
SHA256 b0955ba0d6ef0565b2e233227dad43880db03b68f6682279f1c0b0369a7bd130
MD5 3d2259925bb258bd2d9271843802f903
BLAKE2b-256 87285d7f61b9a5ea2df1d479b76d8b0a938cdbe8dea4b361e2302f7a6121b75c

See more details on using hashes here.

File details

Details for the file porridge-1.0.0-cp33-cp33m-win_amd64.whl.

File metadata

File hashes

Hashes for porridge-1.0.0-cp33-cp33m-win_amd64.whl
Algorithm Hash digest
SHA256 0142239fcdb37682e2a6922ebef6048bd01ffd42149eb0673519488ca5904e35
MD5 f898f69c7106d73cf3a4ed87fbb0e6df
BLAKE2b-256 484f199b53f3ab298f539af3246413ac403bf6f8a4b63e3fb1aff595936ff8b9

See more details on using hashes here.

File details

Details for the file porridge-1.0.0-cp33-cp33m-win32.whl.

File metadata

File hashes

Hashes for porridge-1.0.0-cp33-cp33m-win32.whl
Algorithm Hash digest
SHA256 d61e0fb8939032cb8d6f91bac4b86f06224310f86d088673b9ec4f3fe9d683ec
MD5 90eb01262b0110c347957f951d515195
BLAKE2b-256 0f1f1acdacbaf2ba5e368cb1c2baabec34e94bbe06a3cf4f952a9d24dc80f45a

See more details on using hashes here.

File details

Details for the file porridge-1.0.0-cp33-cp33m-manylinux1_x86_64.whl.

File metadata

File hashes

Hashes for porridge-1.0.0-cp33-cp33m-manylinux1_x86_64.whl
Algorithm Hash digest
SHA256 0dedd6e0db05d6f3e8ccefca6ad3811856f176e3207079933c985442a6215523
MD5 16ececdada6499307cef144087ec8409
BLAKE2b-256 6457384fd0b7ae2df93a2333c0a1d16c9b444d1f289e7d40b0125aaa7dc91ee8

See more details on using hashes here.

File details

Details for the file porridge-1.0.0-cp27-none-manylinux1_x86_64.whl.

File metadata

File hashes

Hashes for porridge-1.0.0-cp27-none-manylinux1_x86_64.whl
Algorithm Hash digest
SHA256 00dd3251bdf0dd24ad1cc1612bc7da0e8ff844fef7c8e548a783329a06ade7bf
MD5 d94180aa8067dda7a65ea699c11e36c9
BLAKE2b-256 1e4cf33d9a6ba36f988d3f405a799f8bbe7c3d9c06644febcd4043f9e4fdda75

See more details on using hashes here.

File details

Details for the file porridge-1.0.0-cp27-cp27m-win_amd64.whl.

File metadata

File hashes

Hashes for porridge-1.0.0-cp27-cp27m-win_amd64.whl
Algorithm Hash digest
SHA256 9218daeaa0ad8a477bbbc1f154ce8a5a158d32c687eeeb80dfe5b84059a1fe81
MD5 e8b83e890877bcc499faa62483e5e323
BLAKE2b-256 29f2b8bb7078c05ea46a71d67ea6a0531b3c5f1aabcd20aa07d36027994addf8

See more details on using hashes here.

File details

Details for the file porridge-1.0.0-cp27-cp27m-win32.whl.

File metadata

File hashes

Hashes for porridge-1.0.0-cp27-cp27m-win32.whl
Algorithm Hash digest
SHA256 1a463cf15242d29b0c1b4c02a8c668bdad634ca0870a649e443682dfa18690f6
MD5 1ce8c0da159ed3838d4a30c60e0b1841
BLAKE2b-256 9e5ab4790875f3f6f39db11b90c43303b455eeb5e2644e4fb2f593e79a95eff1

See more details on using hashes here.

File details

Details for the file porridge-1.0.0-cp27-cp27m-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for porridge-1.0.0-cp27-cp27m-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 7b79f08d57b4c0d64784545a5860b23ab09dc0b816e7edd31f88164e4198a714
MD5 21398350525896d29e1eefb1008fc235
BLAKE2b-256 0f6c775aa478fa215cb484ca01133a4be9135a8f48080ea6c661d4eec8ae3a28

See more details on using hashes here.

File details

Details for the file porridge-1.0.0-cp27-cp27m-macosx_10_11_x86_64.whl.

File metadata

File hashes

Hashes for porridge-1.0.0-cp27-cp27m-macosx_10_11_x86_64.whl
Algorithm Hash digest
SHA256 dfdc066364d8e651a49c305ff522a9309734b4062f3b092e06c5987141871be3
MD5 368da57c1a1015954c56807752f1d07e
BLAKE2b-256 542699d1e6004b246c7877a36dba16e91e052867b30e29f05627f81e99cf815f

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page