Re: [HACKERS] SCRAM authentication, take three
От | Heikki Linnakangas |
---|---|
Тема | Re: [HACKERS] SCRAM authentication, take three |
Дата | |
Msg-id | 76ac7e67-4e3a-f4df-e087-fbac90151907@iki.fi обсуждение исходный текст |
Ответ на | Re: [HACKERS] SCRAM authentication, take three (Aleksander Alekseev <a.alekseev@postgrespro.ru>) |
Список | pgsql-hackers |
On 02/20/2017 01:51 PM, Aleksander Alekseev wrote: > Currently I don't see any significant flaws in these patches. However I > would like to verify that implemented algorithms are compatible with > algorithms implemented by third party. Yes, that's very important. > For instance, for user 'eax' and password 'pass' I got the following > record in pg_authid: > > ``` > scram-sha-256: > xtznkRN/nc/1DQ==: > 4096: > 2387c124a3139a276b848c910f43ece05dd670d0977ace4f20d724af522312e4: > 5e3bdd6584880198b0375acabd8754c460af2389499f71a756660a10a8aaa843 > ``` > > Let's say I would like to implement SCRAM in pure Python, for instance > add it to pg8000 driver. Firstly I need to know how to generate server > key and client key having only user name and password. Somehow like > this: > > ``` > >>> import base64 > >>> import hashlib > >>> base64.b16encode(hashlib.pbkdf2_hmac('sha256', b'pass', > ... base64.b64decode(b'xtznkRN/nc/1DQ=='), 4096)) > b'14B90CFCF690120399A0E6D30C60DD9D9D221CD9C2E31EA0A00514C41823E6C3' > ``` > > Naturally it doesn't work because both SCRAM_SERVER_KEY_NAME and > SCRAM_CLIENT_KEY_NAME should also be involved. I see PostgreSQL > implementation just in front of me but unfortunately I'm still having > problems calculating exactly the same server key and client key. It makes > me worry whether PostgreSQL implementation is OK. > > Could you please give an example of how to do it? RFC5802 describes the protocol in detail: > SaltedPassword := Hi(Normalize(password), salt, i) > ClientKey := HMAC(SaltedPassword, "Client Key") > StoredKey := H(ClientKey) > AuthMessage := client-first-message-bare + "," + > server-first-message + "," + > client-final-message-without-proof > ClientSignature := HMAC(StoredKey, AuthMessage) > ClientProof := ClientKey XOR ClientSignature > ServerKey := HMAC(SaltedPassword, "Server Key") > ServerSignature := HMAC(ServerKey, AuthMessage) You've calculated SaltedPassword correctly with your Python snippet. To derive ClientKey from it, you need to pass it to the HMAC() function. In python, that'd be hmac.new(SaltedPassword, "Client Key", hashlib.sha256). For example: ``` import base64 import hashlib import hmac salt = base64.b64decode(b'xtznkRN/nc/1DQ=='); SaltedPassword = hashlib.pbkdf2_hmac('sha256', b'pass', salt, 4096); ClientKey = hmac.new(SaltedPassword, "Client Key", hashlib.sha256).hexdigest() print 'SaltedPassword: ' + base64.b16encode(SaltedPassword) print 'ClientKey; ' + ClientKey ``` This prints: SaltedPassword: 14B90CFCF690120399A0E6D30C60DD9D9D221CD9C2E31EA0A00514C41823E6C3 ClientKey; 5b681195146a2027cb028a921bd0a89ff858b74bd2b38ed8b42561c28b1e369f Which matches what the libpq implementation calculated. For constructing the whole client-final-message, you'll also need to calculate ClientSignature and ClientProof, which depend on the nonces, and is therefore different on every authentication exchange. - Heikki
В списке pgsql-hackers по дате отправления:
Следующее
От: Simon RiggsДата:
Сообщение: Re: [HACKERS] Patch to improve performance of replay of AccessExclusiveLock