I am learning to use crypt() function from pgcrypto to crypt my passwords and store them into user tables.
However I don't understand how it is possible for the crypt function to generate the same password if we pass as a second parameter the existing password.
I want to understand how it does it please.
do $$
declare
generated_salt text;
hashResult text;
authenticationPassword text;
begin
-- select the number of actors from the actor table
select public.gen_salt('bf')
into generated_salt;
select public.crypt('password', generated_salt)
into hashResult;
select public.crypt('password', hashResult)
into authenticationPassword;
-- show the number of actors
raise notice 'Generated salt : %', generated_salt;
raise notice 'Hash result : %', hashResult;
raise notice 'authenticationPassword : %', authenticationPassword;
end; $$
In the exemple above if I take an execution and the stored variables's values.
I get : "$2a$06$.lub5s4Eqz4.epcg5zW4Ke" for generated_salt "$2a$06$.lub5s4Eqz4.epcg5zW4KervErzw//uARn8F2gchj2wM11ok.MJLK" for hashResult "$2a$06$.lub5s4Eqz4.epcg5zW4KervErzw//uARn8F2gchj2wM11ok.MJLK" for authenticationPassword
Why is the authenticationPassword the same as hashResult, I was expecting it to hash it again with hashResult as a salt.
How can it tell if it must recognize and calculate the same password or generate a new hash based on a salt?
P.S : I understand how to use the function for storing/retrieving passwords but I don't understand how it does it.
Thank you for your help,
CodePudding user response:
As long as you use the same salt, the resulting hash will always be the same one for each password. This is what happens when the password is being verified.
The trick is that when a new password is being hashed (not when verifying it) the engine chooses a brand new random salt for it, so it makes it nearly impossible to guess it from the hashed result.
CodePudding user response:
I finally understand what is happening, the crypt function uses only the first 29 chars (passed as salt) to generate the hashOutput so even if you put anything behind those 29 characters the result will be the same. Example :
public.crypt('password', '$2a$06$.lub5s4Eqz4.epcg5zW4Ke')
public.crypt('password', '$2a$06$.lub5s4Eqz4.epcg5zW4KervErzw//uARn8F2gchj2wM11ok.MJLK')
public.crypt('password', '$2a$06$.lub5s4Eqz4.epcg5zW4Keyadayadayadayada')
The result of the 3 lines above is always $2a$06$.lub5s4Eqz4.epcg5zW4KervErzw//uARn8F2gchj2wM11ok.MJLK what really matters is the first 29 characters $2a$06$.lub5s4Eqz4.epcg5zW4Ke and the password value which decides of what is generated after the 29 characters : rvErzw//uARn8F2gchj2wM11ok.MJLK
The source code of pgcrypto helped me understand what was happening under the hood : https://github.com/postgres/postgres/tree/master/contrib/pgcrypto