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?

    pip install itsdangerous
    

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?

        pip install bcrypt
    

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