【问题标题】:Making a sha1-hash of a row in Oracle在 Oracle 中对一行进行 sha1-hash
【发布时间】:2009-11-17 15:43:02
【问题描述】:

我在 Oracle 数据库的选择中对一行进行 sha1-hash 时遇到问题。我在 MSSQL 中做了如下:

SELECT *,HASHBYTES('SHA1',CAST(ID as varchar(10)+
  TextEntry1+TextEntry2+CAST(Timestamp as varchar(10)) as Hash
FROM dbo.ExampleTable
WHERE ID = [foo]

但是,在使用 Oracle 时,我似乎找不到可以使用的类似功能。 就我的谷歌搜索而言,我猜测 dbms_crypto.hash_sh1 与它有关,但我还没有能够将我的大脑包裹在它周围......

任何指针将不胜感激。

【问题讨论】:

    标签: oracle hash sha1


    【解决方案1】:

    DBMS_CRYPTO 是生成哈希的正确包。默认情况下不授予 PUBLIC,您必须专门授予它 (GRANT EXECUTE ON SYS.DBMS_CRYPTO TO user1)。

    这个函数的结果是数据类型RAW。您可以将其存储在RAW 列中或使用RAWTOHEXUTL_ENCODE.BASE64_ENCODE 函数将其转换为VARCHAR2

    HASH 函数被重载以接受三种数据类型作为输入:RAWCLOBBLOB。由于rules of implicit conversion,如果您使用VARCHAR2 作为输入,Oracle 将尝试将其转换为RAW,并且很可能会失败,因为此转换仅适用于十六进制字符串。

    如果您使用VARCHAR2,则需要将输入转换为二进制数据类型或CLOB,例如:

    DECLARE
       x RAW(20);
    BEGIN
       SELECT sys.dbms_crypto.hash(utl_raw.cast_to_raw(col1||col2||to_char(col3)), 
                                   sys.dbms_crypto.hash_sh1) 
         INTO x 
         FROM t;
    END;
    

    您将在DBMS_CRYPTO.hash 的文档中找到更多信息

    【讨论】:

    • 感谢您的帮助。我必须使用值 dbms_crypto.hash_sh1 代表(整数 3)而不是常量,以使其在执行常规 SQL 时工作。从 t 中选择 sys.dbms_crypto.hash(utl_raw.cast_to_raw(col1),3);
    • 我认为这对于 11g R2 来说并不完全正确。 dbms_crypto.hash 似乎有 rawblobclob 的 3 个重载版本。 varchar2 值必须通过utl_i18n.string_to_rawutl_raw.cast_to_raw 显式转换为raw。或者使用clobs 获取字符数据。
    • 如果有些列没有字符串数据类型怎么办?
    • @PrometheusDrake 上面的评论谈到了dbms_crypto.hash_sh1。需要明确的是,这是包中定义的常量,并作为 typ 参数传递给dbms_crypto.hash。表示应该使用SHA-1哈希算法。
    • @ca9163d9 如果您的列是另一种类型,请查找相应的 UTL_RAW 包函数。例如,如果您有一个 NUMBER 类型的列,请使用 CAST_FROM_NUMBER 将其转换为 RAW,然后加密。要反转,解密,然后 CAST_TO_NUMBER。
    【解决方案2】:

    DBMS_crypto 包不支持 varchar2。它适用于原始类型,因此如果您需要 varchar2,则必须对其进行转换。这是一个示例函数,展示了如何执行此操作:

    declare
      p_string varchar2(2000) := 'Hello world !';
      lv_hash_value_md5    raw (100);
      lv_hash_value_sh1    raw (100);
      lv_varchar_key_md5   varchar2 (32);
      lv_varchar_key_sh1   varchar2 (40);
    begin
      lv_hash_value_md5 :=
         dbms_crypto.hash (src   => utl_raw.cast_to_raw (p_string),
                           typ   => dbms_crypto.hash_md5);
    
      -- convert into varchar2
      select   lower (to_char (rawtohex (lv_hash_value_md5)))
        into   lv_varchar_key_md5
        from   dual;
    
      lv_hash_value_sh1 :=
         dbms_crypto.hash (src   => utl_raw.cast_to_raw (p_string),
                           typ   => dbms_crypto.hash_sh1);
    
      -- convert into varchar2
      select   lower (to_char (rawtohex (lv_hash_value_sh1)))
        into   lv_varchar_key_sh1
        from   dual;
    
      --
      dbms_output.put_line('String to encrypt : '||p_string);
      dbms_output.put_line('MD5 encryption : '||lv_varchar_key_md5);
      dbms_output.put_line('SHA1 encryption : '||lv_varchar_key_sh1);
    end;
    

    【讨论】:

    • 上面的例子使用cast_to_raw,但是调用者应该使用UTL_I18N.STRING_TO_RAWcast_to_raw 不考虑二进制独立语言转换。如果在加密和解密之间更改数据库的默认语言,cast_to_raw 和后续的cast_to_varchar2 可能会失败。例如,varchar2 可以转换为:UTL_I18N.STRING_TO_RAW (string, 'AL32UTF8')
    【解决方案3】:

    你可以在你喜欢的包中定义这个函数,我在 utils_pkg 中定义的。

    FUNCTION SHA1(STRING_TO_ENCRIPT VARCHAR2) RETURN VARCHAR2 AS 
    BEGIN 
    RETURN LOWER(TO_CHAR(RAWTOHEX(SYS.DBMS_CRYPTO.HASH(UTL_RAW.CAST_TO_RAW(STRING_TO_ENCRIPT), SYS.DBMS_CRYPTO.HASH_SH1))));
    END SHA1;
    

    现在叫它

    SELECT UTILS_PKG.SHA1('My Text') AS SHA1 FROM DUAL;
    

    回应是

    SHA1
    --------------------------------------------
    5411d08baddc1ad09fa3329f9920814c33ea10c0
    

    您可以从某个表中选择一列:

    SELECT UTILS_PKG.SHA1(myTextColumn) FROM myTable;
    

    享受吧!

    【讨论】:

      【解决方案4】:

      只是放在这里,如果有人会搜索。

      在 Oracle 12 中,您可以使用 standard_hash(<your_value>, <algorythm>) 函数。 未定义参数<algorythm>,它将生成SHA-1哈希(输出数据类型raw(20)

      【讨论】:

        猜你喜欢
        • 2021-12-11
        • 2019-11-23
        • 2011-08-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-11-03
        • 2011-08-24
        相关资源
        最近更新 更多