5

我想更新数据库中的所有密码以获得 MD5 哈希密码。以下不能解决我的问题:

UPDATE USERS SET USERPASS = hash('SALT' || USERPASS);

问题是:它返回的散列不是使用 MD5 算法生成的。如何在 Firebird 中实现 md5 哈希算法?

4

3 回答 3

7

不幸的是,文档hash中没有提到该函数的算法......无论如何,您可以将它实现为 UDF 或使用一些第三方 UDF 库来实现它。IBPhoenix 网站上有一个Firebird 的 UDF 库列表,似乎 rFunc 和 FreeAdhocUDF 库都有一个(我只检查了这两个,可能还有其他的)。

于 2013-07-29T14:49:46.240 回答
4

Firebird 的下一个版本 Firebird 4 将添加加密哈希函数。引用Firebird 4 Beta 1 发行说明

追踪票CORE-4436

使用指定算法返回字符串的哈希值。格式为:

HASH( <string> [ USING <algorithm> ] )    
algorithm ::= { MD5 | SHA1 | SHA256 | SHA512 }

带有可选USING子句的语法在 FB 4.0 中引入,并VARCHAR以字符集返回字符串OCTETS

重要的

USING仍然支持不带子句的语法。它使用非加密 PJW 哈希函数(也称为 ELF64)的 64 位变体:
https
://en.wikipedia.org/wiki/PJW_hash_function ,速度非常快,可用于一般用途(哈希表、等),但它的碰撞质量是次优的。其他散列函数(在 USING 子句中明确指定)应该用于更可靠的散列。

例子

select hash(x using sha256) from y;
-- 
select hash(x) from y; -- not recommended 

Firebird 4 Beta 1 可以从https://www.firebirdsql.org/en/firebird-4-0-0-beta1/下载进行测试

于 2019-03-09T18:08:51.003 回答
2

这是没有UDF的另一种方式,我发现here

/******************************************************************************/
/***          Generated by IBExpert 2018.6.8.1 27.08.2018 16:31:02          ***/
/******************************************************************************/

/******************************************************************************/
/***      Following SET SQL DIALECT is just for the Database Comparer       ***/
/******************************************************************************/
SET SQL DIALECT 3;



/******************************************************************************/
/***                           Stored procedures                            ***/
/******************************************************************************/



SET TERM ^ ;

CREATE OR ALTER PROCEDURE MD5 (
    SOURCE BLOB SUB_TYPE 1 SEGMENT SIZE 80 CHARACTER SET OCTETS)
RETURNS (
    RES CHAR(32) CHARACTER SET OCTETS)
AS
BEGIN
  SUSPEND;
END^





CREATE OR ALTER PROCEDURE MD5_F (
    A BIGINT,
    B BIGINT,
    C BIGINT,
    D BIGINT,
    K INTEGER,
    S INTEGER,
    T BIGINT,
    P INTEGER,
    V CHAR(64) CHARACTER SET OCTETS)
RETURNS (
    RES BIGINT)
AS
BEGIN
  SUSPEND;
END^





CREATE OR ALTER PROCEDURE MD5_INTTOCHAR4 (
    V BIGINT)
RETURNS (
    RES CHAR(4) CHARACTER SET OCTETS)
AS
BEGIN
  SUSPEND;
END^





CREATE OR ALTER PROCEDURE MD5_INTTOHEX (
    V BIGINT)
RETURNS (
    RES CHAR(8) CHARACTER SET OCTETS)
AS
BEGIN
  SUSPEND;
END^






SET TERM ; ^



/******************************************************************************/
/***                           Stored procedures                            ***/
/******************************************************************************/



SET TERM ^ ;

CREATE OR ALTER PROCEDURE MD5 (
    SOURCE BLOB SUB_TYPE 1 SEGMENT SIZE 80 CHARACTER SET OCTETS)
RETURNS (
    RES CHAR(32) CHARACTER SET OCTETS)
AS
declare variable A bigint = 0X0067452301;
declare variable B bigint = 0X00EFCDAB89;
declare variable C bigint = 0X0098BADCFE;
declare variable D bigint = 0X0010325476;
declare variable AA bigint;
declare variable BB bigint;
declare variable CC bigint;
declare variable DD bigint;
declare variable BUF char(64) character set OCTETS;
declare variable LEN bigint;
declare variable M integer;
declare variable N integer;
begin
  len = octet_length(source);
  m = 56 - mod(len + 1, 64);
  if (m < 0) then m = m + 64;
  source = source || rpad(x'80', m+1, x'00') ||
    (select res from md5_IntToChar4(bin_and(0x00FFFFFFFF, bin_shl(:len, 3)))) ||
    (select res from md5_IntToChar4(bin_shr(:len, 32-3)));

  n = 0;
  while (n < (len+m+9) / 64) do
  begin
    AA = A;
    BB = B;
    CC = C;
    DD = D;

    buf = substring(source from n * 64 + 1 for 64);

    /* Round 1 */
    A = (select res from md5_F(:A, :B, :C, :D,  0,  7, 0x00d76aa478, 1, :buf)); /* 1 */
    D = (select res from md5_F(:D, :A, :B, :C,  1, 12, 0x00e8c7b756, 1, :buf)); /* 2 */
    C = (select res from md5_F(:C, :D, :A, :B,  2, 17, 0x00242070db, 1, :buf)); /* 3 */
    B = (select res from md5_F(:B, :C, :D, :A,  3, 22, 0x00c1bdceee, 1, :buf)); /* 4 */
    A = (select res from md5_F(:A, :B, :C, :D,  4,  7, 0x00f57c0faf, 1, :buf)); /* 5 */
    D = (select res from md5_F(:D, :A, :B, :C,  5, 12, 0x004787c62a, 1, :buf)); /* 6 */
    C = (select res from md5_F(:C, :D, :A, :B,  6, 17, 0x00a8304613, 1, :buf)); /* 7 */
    B = (select res from md5_F(:B, :C, :D, :A,  7, 22, 0x00fd469501, 1, :buf)); /* 8 */
    A = (select res from md5_F(:A, :B, :C, :D,  8,  7, 0x00698098d8, 1, :buf)); /* 9 */
    D = (select res from md5_F(:D, :A, :B, :C,  9, 12, 0x008b44f7af, 1, :buf)); /* 10 */
    C = (select res from md5_F(:C, :D, :A, :B, 10, 17, 0x00ffff5bb1, 1, :buf)); /* 11 */
    B = (select res from md5_F(:B, :C, :D, :A, 11, 22, 0x00895cd7be, 1, :buf)); /* 12 */
    A = (select res from md5_F(:A, :B, :C, :D, 12,  7, 0x006b901122, 1, :buf)); /* 13 */
    D = (select res from md5_F(:D, :A, :B, :C, 13, 12, 0x00fd987193, 1, :buf)); /* 14 */
    C = (select res from md5_F(:C, :D, :A, :B, 14, 17, 0x00a679438e, 1, :buf)); /* 15 */
    B = (select res from md5_F(:B, :C, :D, :A, 15, 22, 0x0049b40821, 1, :buf)); /* 16 */

    /* Round 2 */
    A = (select res from md5_F(:A, :B, :C, :D,  1,  5, 0x00f61e2562, 2, :buf)); /* 17 */
    D = (select res from md5_F(:D, :A, :B, :C,  6,  9, 0x00c040b340, 2, :buf)); /* 18 */
    C = (select res from md5_F(:C, :D, :A, :B, 11, 14, 0x00265e5a51, 2, :buf)); /* 19 */
    B = (select res from md5_F(:B, :C, :D, :A,  0, 20, 0x00e9b6c7aa, 2, :buf)); /* 20 */
    A = (select res from md5_F(:A, :B, :C, :D,  5,  5, 0x00d62f105d, 2, :buf)); /* 21 */
    D = (select res from md5_F(:D, :A, :B, :C, 10,  9, 0x0002441453, 2, :buf)); /* 22 */
    C = (select res from md5_F(:C, :D, :A, :B, 15, 14, 0x00d8a1e681, 2, :buf)); /* 23 */
    B = (select res from md5_F(:B, :C, :D, :A,  4, 20, 0x00e7d3fbc8, 2, :buf)); /* 24 */
    A = (select res from md5_F(:A, :B, :C, :D,  9,  5, 0x0021e1cde6, 2, :buf)); /* 25 */
    D = (select res from md5_F(:D, :A, :B, :C, 14,  9, 0x00c33707d6, 2, :buf)); /* 26 */
    C = (select res from md5_F(:C, :D, :A, :B,  3, 14, 0x00f4d50d87, 2, :buf)); /* 27 */
    B = (select res from md5_F(:B, :C, :D, :A,  8, 20, 0x00455a14ed, 2, :buf)); /* 28 */
    A = (select res from md5_F(:A, :B, :C, :D, 13,  5, 0x00a9e3e905, 2, :buf)); /* 29 */
    D = (select res from md5_F(:D, :A, :B, :C,  2,  9, 0x00fcefa3f8, 2, :buf)); /* 30 */
    C = (select res from md5_F(:C, :D, :A, :B,  7, 14, 0x00676f02d9, 2, :buf)); /* 31 */
    B = (select res from md5_F(:B, :C, :D, :A, 12, 20, 0x008d2a4c8a, 2, :buf)); /* 32 */

    /* Round 3 */
    A = (select res from md5_F(:A, :B, :C, :D,  5,  4, 0x00fffa3942, 3, :buf)); /* 33 */
    D = (select res from md5_F(:D, :A, :B, :C,  8, 11, 0x008771f681, 3, :buf)); /* 34 */
    C = (select res from md5_F(:C, :D, :A, :B, 11, 16, 0x006d9d6122, 3, :buf)); /* 35 */
    B = (select res from md5_F(:B, :C, :D, :A, 14, 23, 0x00fde5380c, 3, :buf)); /* 36 */
    A = (select res from md5_F(:A, :B, :C, :D,  1,  4, 0x00a4beea44, 3, :buf)); /* 37 */
    D = (select res from md5_F(:D, :A, :B, :C,  4, 11, 0x004bdecfa9, 3, :buf)); /* 38 */
    C = (select res from md5_F(:C, :D, :A, :B,  7, 16, 0x00f6bb4b60, 3, :buf)); /* 39 */
    B = (select res from md5_F(:B, :C, :D, :A, 10, 23, 0x00bebfbc70, 3, :buf)); /* 40 */
    A = (select res from md5_F(:A, :B, :C, :D, 13,  4, 0x00289b7ec6, 3, :buf)); /* 41 */
    D = (select res from md5_F(:D, :A, :B, :C,  0, 11, 0x00eaa127fa, 3, :buf)); /* 42 */
    C = (select res from md5_F(:C, :D, :A, :B,  3, 16, 0x00d4ef3085, 3, :buf)); /* 43 */
    B = (select res from md5_F(:B, :C, :D, :A,  6, 23, 0x0004881d05, 3, :buf)); /* 44 */
    A = (select res from md5_F(:A, :B, :C, :D,  9,  4, 0x00d9d4d039, 3, :buf)); /* 45 */
    D = (select res from md5_F(:D, :A, :B, :C, 12, 11, 0x00e6db99e5, 3, :buf)); /* 46 */
    C = (select res from md5_F(:C, :D, :A, :B, 15, 16, 0x001fa27cf8, 3, :buf)); /* 47 */
    B = (select res from md5_F(:B, :C, :D, :A,  2, 23, 0x00c4ac5665, 3, :buf)); /* 48 */

    /* Round 4 */
    A = (select res from md5_F(:A, :B, :C, :D,  0,  6, 0x00f4292244, 4, :buf)); /* 49 */
    D = (select res from md5_F(:D, :A, :B, :C,  7, 10, 0x00432aff97, 4, :buf)); /* 50 */
    C = (select res from md5_F(:C, :D, :A, :B, 14, 15, 0x00ab9423a7, 4, :buf)); /* 51 */
    B = (select res from md5_F(:B, :C, :D, :A,  5, 21, 0x00fc93a039, 4, :buf)); /* 52 */
    A = (select res from md5_F(:A, :B, :C, :D, 12,  6, 0x00655b59c3, 4, :buf)); /* 53 */
    D = (select res from md5_F(:D, :A, :B, :C,  3, 10, 0x008f0ccc92, 4, :buf)); /* 54 */
    C = (select res from md5_F(:C, :D, :A, :B, 10, 15, 0x00ffeff47d, 4, :buf)); /* 55 */
    B = (select res from md5_F(:B, :C, :D, :A,  1, 21, 0x0085845dd1, 4, :buf)); /* 56 */
    A = (select res from md5_F(:A, :B, :C, :D,  8,  6, 0x006fa87e4f, 4, :buf)); /* 57 */
    D = (select res from md5_F(:D, :A, :B, :C, 15, 10, 0x00fe2ce6e0, 4, :buf)); /* 58 */
    C = (select res from md5_F(:C, :D, :A, :B,  6, 15, 0x00a3014314, 4, :buf)); /* 59 */
    B = (select res from md5_F(:B, :C, :D, :A, 13, 21, 0x004e0811a1, 4, :buf)); /* 60 */
    A = (select res from md5_F(:A, :B, :C, :D,  4,  6, 0x00f7537e82, 4, :buf)); /* 61 */
    D = (select res from md5_F(:D, :A, :B, :C, 11, 10, 0x00bd3af235, 4, :buf)); /* 62 */
    C = (select res from md5_F(:C, :D, :A, :B,  2, 15, 0x002ad7d2bb, 4, :buf)); /* 63 */
    B = (select res from md5_F(:B, :C, :D, :A,  9, 21, 0x00eb86d391, 4, :buf)); /* 64 */

    A = bin_and(0x00FFFFFFFF, AA + A);
    B = bin_and(0x00FFFFFFFF, BB + B);
    C = bin_and(0x00FFFFFFFF, CC + C);
    D = bin_and(0x00FFFFFFFF, DD + D);
    n = n + 1;
  end

  res =
    (select res from md5_IntToHex(:a))||
    (select res from md5_IntToHex(:b))||
    (select res from md5_IntToHex(:c))||
    (select res from md5_IntToHex(:d));
    suspend;
end^


CREATE OR ALTER PROCEDURE MD5_F (
    A BIGINT,
    B BIGINT,
    C BIGINT,
    D BIGINT,
    K INTEGER,
    S INTEGER,
    T BIGINT,
    P INTEGER,
    V CHAR(64) CHARACTER SET OCTETS)
RETURNS (
    RES BIGINT)
AS
declare variable FF bigint;
declare variable R bigint;
declare variable X bigint;
begin
  X = bin_or(ascii_val(substring(V from k*4 + 1 for 1)),
             bin_shl(ascii_val(substring(V from k*4 + 2 for 1)), 8),
             bin_shl(ascii_val(substring(V from k*4 + 3 for 1)),16),
             bin_shl(ascii_val(substring(V from k*4 + 4 for 1)),24));

  if (p = 1) then /* f */
    ff = bin_or(bin_and(b, c), bin_and(bin_not(b), d));
  if (p = 2) then /* g */
    ff = bin_or(bin_and(b, d), bin_and(bin_not(d), c));
  if (p = 3) then /* h */
    ff = bin_xor(b, c, d);
  if (p = 4) then /* i */
    ff = bin_xor(c, bin_or(bin_not(d), b));

  r = bin_and(0x00FFFFFFFF, a + ff + x + t);
  r = bin_and(0x00FFFFFFFF, b + bin_or(bin_shl(r, s), bin_shr(r, 32 - s)));
  res = r;
  suspend;
end^


CREATE OR ALTER PROCEDURE MD5_INTTOCHAR4 (
    V BIGINT)
RETURNS (
    RES CHAR(4) CHARACTER SET OCTETS)
AS
begin
  res =  ascii_char(bin_and(0xFF, V))||
         ascii_char(bin_and(0xFF, bin_shr(V, 8)))||
         ascii_char(bin_and(0xFF, bin_shr(V, 16)))||
         ascii_char(bin_and(0xFF, bin_shr(V, 24)));
  suspend;
end^


CREATE OR ALTER PROCEDURE MD5_INTTOHEX (
    V BIGINT)
RETURNS (
    RES CHAR(8) CHARACTER SET OCTETS)
AS
declare variable H char(16) = '0123456789ABCDEF';
begin
  res = substring(h from bin_and(0x0F, bin_shr(V, 4))+1 for 1) ||
        substring(h from bin_and(0x0F, V)+1  for 1)||
        substring(h from bin_and(0x0F, bin_shr(V, 12))+1 for 1)||
        substring(h from bin_and(0x0F, bin_shr(V, 8))+1 for 1)||
        substring(h from bin_and(0x0F, bin_shr(V, 20))+1 for 1)||
        substring(h from bin_and(0x0F, bin_shr(V, 16))+1 for 1)||
        substring(h from bin_and(0x0F, bin_shr(V, 28))+1 for 1)||
        substring(h from bin_and(0x0F, bin_shr(V, 24))+1 for 1);
  suspend;
end^



SET TERM ; ^
于 2020-06-03T10:02:28.607 回答