问题
I have a postgres 9.1 database that is used by both a django website and a application server.
Currently, I use the old SHA1 authentication in both system, but will upgrade to bcrypt. I have this:
CREATE OR REPLACE FUNCTION random_string(length INTEGER, OUT RETURNS TEXT)
AS $$
BEGIN
IF length < 0 THEN
raise exception 'Given length cannot be less than 0';
END IF;
RETURNS = libs.gen_salt('bf', length);
END;
$$
LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION encryp_TEXT(_TEXT TEXT, OUT RETURNS TEXT)
AS $$
DECLARE
hash TEXT := '';
salt TEXT := '';
BEGIN
salt := random_string(12);
hash := libs.crypt(_TEXT,salt);
RETURNS = 'bcrypt$' || salt || '$' || hash;
END;
$$
LANGUAGE 'plpgsql';
select encryp_TEXT('123');
However, is generating invalid passwords (ie, django can't login with that):
In [9]: from django.contrib.auth.hashers import BCryptPasswordHasher
In [10]: a=BCryptPasswordHasher()
In [19]: p='bcrypt$$2a$12$dCw4N7U1aQbuTVhE8ybV0O$2a$12$dCw4N7U1aQbuTVhE8ybV0OVVeFYgl1EMtBhG.4/PobMWDlih1IGLK'
In [20]: a.verify('123',p)
Out[20]: False
Before, using the SHA1 auth both system work fine, so I wonder what I'm missing...
Before I have this:
-- Genera una cadena aleatoria del tamaño especificado
CREATE OR REPLACE FUNCTION random_string(length INTEGER, OUT RETURNS TEXT)
AS $$
DECLARE
chars TEXT[] := '{0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z}';
result TEXT := '';
i INTEGER := 0;
BEGIN
IF length < 0 THEN
raise exception 'Given length cannot be less than 0';
END IF;
FOR i IN 1..length LOOP
result := result || chars[1+random()*(array_length(chars, 1)-1)];
END LOOP;
RETURNS = result;
END;
$$
LANGUAGE plpgsql;
-- Encripta con SHA1 una cadena y retorna el tipo de algoritmo + salt + hash
CREATE OR REPLACE FUNCTION encryp_TEXT(_TEXT TEXT, OUT RETURNS TEXT)
AS $$
DECLARE
hash TEXT := '';
salt TEXT := '';
BEGIN
salt := random_string(12);
hash := encode( libs.digest(salt || _TEXT, 'sha1'), 'hex');
RETURNS = 'sha1$' || salt || '$' || hash;
END;
$$
LANGUAGE 'plpgsql';
Looking at the source of django and checking this, I modify the salt generation. However, even if I use the same code the check will fail anyway (with a ValueError: Invalid salt
), so I don't know if the problem is in the salt or the encrypt
P.D: I will be equally happy with reimplement PBKDF2 or using a custom hasher, if necesary
回答1:
Well, finally I do it. I check the generated string by postgres and django and found that the ones with postgres duplicate the salt. So was a simple change to:
-- Encripta con bcrypto una cadena y retorna el tipo de algoritmo + salt + hash, django compatible
CREATE OR REPLACE FUNCTION encryp_text(_TEXT TEXT, OUT RETURNS TEXT)
AS $$
DECLARE
hash TEXT := '';
salt TEXT := '';
BEGIN
salt := random_string(12);
hash := libs.crypt(_TEXT,salt);
RETURNS = 'bcrypt$' || hash;
END;
$$
LANGUAGE 'plpgsql';
来源:https://stackoverflow.com/questions/12736576/how-reimplement-bcryptpasswordhasher-of-django-with-postgres-9-1