0

I'm using passlib==1.7.1 with the following import:

from passlib.apps import custom_app_context as pwd_context

Then hashing the password with the following:

pwd_context.encrypt(password)

I then verify with:

pwd_context.verify(password, self.password_hash)

This is fine, but verification fails with certain characters. e.g. "£" or "$".

Does anyone know why this would be the case please?

Thank you!


Update:

Thank you all very much. Armed with this info I investigated a bit more and it seems that the problem is not passlib but sits somewhere between angular4 where I send a base64 authorisation header to the flask app.

I'm currently using the following to do this:

let headers: Headers = new Headers({
        'Content-Type': 'application/json',
        'Authorization': 'Basic ' + btoa(userLoginRequest.username + ':' + userLoginRequest.password)
    });

I have read a lot today about unescape (and it's depreciation in favour of decodeURI()). I have also read a lot about support for unicode in base64 encoding. I tried a number of combinations of these things and it made no difference. I am now really rather confused!

To test what's going on I do the following. In angular4 I execute the following:

let encodedString = btoa('doug:Tree£9')
console.log(encodedString)
console.log(atob(encodedString))

As expected, this prints the following to the console.

ZG91ZzpUcmVlozk=
doug:Tree£9

So it's clearly ok encoding and decoding.

Doing the same process in Python...

import base64
encoded = base64.b64encode('doug:Tree£9')
print encoded
print base64.b64decode(encoded)

I get the the following in terminal.

ZG91ZzpUcmVlwqM5
doug:Tree£9

I note that "ZG91ZzpUcmVlozk=" and "ZG91ZzpUcmVlwqM5" are not the same. However, both methods are working within their own languages.

If I put the "ZG91ZzpUcmVlozk=" encoded string from javascript into python and decode it as follows...

import base64
print base64.b64decode("ZG91ZzpUcmVlozk=")

I get:

doug:Tree�9

Note that the £ character has now been mashed.

Other Unicode characters fail too.

So I think the question is how to I encode the Authorisation header so that python correctly recognises the £ character, and any other character users choose for their passwords?

Thanks so much!


Edit: Resolved!

I found this Using Javascript's atob to decode base64 doesn't properly decode utf-8 strings which goes into some detail. I resolved it by using the following approach recommended by @brandonscript.

b64EncodeUnicode(str) : string{
    return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function(match, p1) {
        return String.fromCharCode(parseInt(p1, 16))
    }))
}

Works perfectly! Phew!

Doug
  • 665
  • 2
  • 8
  • 22
  • By the way, I couldn't reproduce the same issue, your code works fine as it is. So please provide the whole code input and output. – BcK Jun 01 '18 at 06:00

2 Answers2

0

I guess you are running into an encoding issue, from the documentation,

http://passlib.readthedocs.io/en/stable/narr/hash-tutorial.html#hashing

Use PasswordHash.hash() to hash a password. This call takes care of unicode encoding....

from passlib.hash import pbkdf2_sha256

hash = pbkdf2_sha256.hash("$password")
pbkdf2_sha256.verify("$password", hash)
# True
BcK
  • 2,548
  • 1
  • 13
  • 27
0
# -*- coding: utf-8 -*-
from passlib.apps import custom_app_context as pwd_contex

password='£$'

encrypted=pwd_contex.encrypt(password)

print(pwd_contex.verify('£$', encrypted))
print(pwd_contex.verify('john', encrypted))

True
False

works perfectly well on my system. Perhaps you need to set your default encoding # -*- coding: utf-8 -*- at the top of your script