【问题标题】:Postgres: How to convert 16 bytes into 4 bytes by XOR-ing every 4 bytesPostgres:如何通过 XOR-ing 每 4 个字节将 16 个字节转换为 4 个字节
【发布时间】:2016-03-17 21:06:15
【问题描述】:

我有一个 16 字节 md5 哈希,我需要使用 XOR 将其“折叠”成 4 字节数据:{1st 4 bytes} XOR {2nd 4 bytes} XOR {3rd 4 bytes} XOR {4th 4 字节}。然后我需要将结果转换为十六进制形式(8 个字符的字符串)。

我正在像这样生成我的哈希(解码为十六进制,因为它似乎更容易处理):

SELECT decode(md5('test'), 'hex');

但这就是我所得到的。我不知道将 16 字节哈希拆分为 4 个 4 字节值的最佳方法,然后对这些 4 字节值进行异或。

【问题讨论】:

  • @MarcB:我认为这个想法是使用按位异或运算符。但我正在努力解决如何制定这个问题。我目前正在查看this stackoverflow 答案以供参考。但我无法将其转换为我的示例。
  • 事实证明,实际问题与 MD5 无关,只是在 Postgres 中异或字节。
  • @zaph 是的,这是正确的。我认为我的问题很清楚。但是,标题有点误导,所以我已经更新了。
  • 好吧,# 是 postgress 中的异或运算符,所以从技术上讲,您只需要一些字符串和/或位运算来提取单个字节,然后将它们全部异或。

标签: postgresql cryptography md5 xor


【解决方案1】:

不幸的是,docs 对您可以使用位字符串值做什么有点模糊,但提到了substring 函数(语法在string functions page 上),可用于从中提取部分:

select i1 # i2 # i3 # i4
from   cast('x' || md5('test') as bit(128)) bits,
       cast(substring(bits from 97 for 32) as int4) i1,
       cast(substring(bits from 65 for 32) as int4) i2,
       cast(substring(bits from 33 for 32) as int4) i3,
       cast(substring(bits from  1 for 32) as int4) i4

注意:较低的位在其位串表示中具有较高的索引,f.ex.

select 3::bit(32)
-- will yield '00000000000000000000000000000011'

【讨论】:

  • 有趣的是,我想出了一种完全不同的方法来做同样的事情(我会把它作为替代答案发布)。顺便说一句,我在最初的问题中错过了一部分。我需要最终结果的十六进制形式(8 个字符字符串)。我认为要做到这一点,您只需调用“to_hex(i1 # i2 # i3 # i4)”。
  • 另外,根据the postgres message board,您的技术“依赖于位类型输入转换器的一些未记录行为”。
  • @Jason 这现在是bit strings 上一个有据可查的功能:此外,可以将整数值与类型位进行转换。 是的,如果你需要十六进制表示,你可以使用to_hex(i1 # i2 # i3 # i4)(或lpad(to_hex(i1 # i2 # i3 # i4), 8, '0') 用于固定宽度)
  • 哦,好的。我猜那个帖子是 2011 年的。谢谢。如果您能帮我一个忙并将“to_hex”部分添加到您的回复中,我会将您的答案标记为已接受。
【解决方案2】:

花了一些时间了解this的答案后,我想出了这个:

CREATE OR REPLACE FUNCTION compressed_md5(var_txt TEXT) RETURNS TEXT
AS $$
DECLARE
  var_hash BYTEA;
  var_compressedHash BYTEA;
  var_offset INTEGER;
BEGIN
  var_hash := decode(md5(var_txt), 'hex');
  var_compressedHash := decode('00000000', 'hex'); -- prepopulate with some 4-byte data
  FOR var_offset IN 0..3 LOOP
    var_compressedHash := set_byte(var_compressedHash, var_offset,
                                   get_byte(var_hash, var_offset) #
                                   get_byte(var_hash, var_offset + 4) #
                                   get_byte(var_hash, var_offset + 8) #
                                   get_byte(var_hash, var_offset + 12));
  END LOOP;
  RETURN encode(var_compressedHash, 'hex');
END;
$$ LANGUAGE plpgsql;

SELECT compressed_md5('test');

结果:

"a35742cb"

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-02-19
    • 2012-12-15
    • 2022-05-04
    • 1970-01-01
    • 2019-09-19
    • 2023-01-13
    • 2012-06-06
    • 2019-10-18
    相关资源
    最近更新 更多