It's Dangerous
...and a little bit of bcrypt
Ned Jackson Lovely
njl@njl.us
@nedjl
Crypto is Hard
- Primitives
- Protocols
- Systems
Everything I say will make somebody mad.
Know your threat.
If you are protecting lives or millions, pay for professionals.
How can I keep a user from messing with it?
What's It Good For?
- Email Validation
- Password Reset
- Expiring Access Token (OAuth)
- Tamper-proof Cookies
Making Keys
>>> os.urandom(40).encode('hex')
'130d6cb77e887b4fac9[...]8b2bcc79dffd95ec0741e0d51c'
>>> from itsdangerous import Signer
>>> s = Signer(os.environ['ITSD_SECRET'])
>>> signed = s.sign('bob@example.com')
>>> print signed
bob@example.com.XqNmXBq1uGLgEKRqboqoifbbgeE
>>> s.unsign(signed)
'bob@example.com'
>>> fake = 'malory@example.com.lsdflashdfalsdkhfsadf'
>>> try:
... s.unsign(fake)
... except itsdangerous.BadSignature as e:
... print e
...
Signature 'lsdflashdfalsdkhfsadf' does not match
>>> from itsdangerous import TimestampSigner
>>> s = TimestampSigner(SECRET_KEY)
>>> signed = s.sign("This Thing")
>>> print(signed)
This Thing.CNNEZA.RhnQmEVTMSFzo9aaZrM07kFHRus
>>> s.unsign(signed, max_age=60*60)
'This Thing'
>>> try:
... s.unsign(signed, max_age=60*60)
... except itsdangerous.SignatureExpired as e:
... print e
...
Signature age 4051 > 3600 seconds
>>>
>>> from itsdangerous import Serializer
>>> s = Serializer(SECRET_KEY)
>>> signed = s.dumps({'email':'example@example.com', 'points':273})
>>> print signed
{"points": 273, "email": "example@example.com"}.gd-WocjMM0A5zi6UJxbevhiOc5A
>>> s.loads(signed)
{u'points': 273, u'email': u'example@example.com'}
Signer
TimestampSigner
Serializer
TimedSerializer
URLSafeSerializer
URLSafeTimedSerializer
>>> from itsdangerous import URLSafeTimedSerializer
>>> s = URLSafeTimedSerializer(SECRET_KEY, salt='password-reset')
>>> signed = s.dumps({'id':123, 'email':'bob@example.com'})
>>> signed
'eyJpZCI6MTIzLCJlbWFpbCI6ImJvYkBleGFtcGxlLmNvbSJ9.CN[...]8uViLlNMMBw'
>>> s.loads(signed, max_age=24*60*60)
{u'id': 123, u'email': u'bob@example.com'}
"salt" is a namespace
Be Very Careful
- Things are "signed", not "encrypted"
- Tamper Proof and Transparent
- The key is crucial to the whole thing
bcrypt
The Only Other Crypto Library I Trust Myself With
How do I make my password database less valuable?
Hash Your Passwords
One way function to hide the password! That was easy!
Rainbow Tables
Salt
Brute Force
Slow Hash Function
>>> import bcrypt
>>> salt = bcrypt.gensalt()
>>> salt
'$2b$12$DvRUJkFiFLL3eKTmED/eou'
>>> hashed = bcrypt.hashpw(u'Secret'.encode('utf8'), salt)
>>> hashed
'$2b$12$DvRUJkFiFLL3eKTmED/eouQxibvOd/RZcLMYRljVBRqYgd1VUGoM.'
>>>
>>> u = u"Not The Secret".encode('utf8')
>>> bcrypt.hashpw(u, hashed) == hashed
False
>>> bcrypt.hashpw(u'Secret'.encode('utf8'), hashed) == hashed
True
Questions?
Ned Jackson Lovely
njl@njl.us
@nedjl