在Python中复制此Java哈希



我试图在Python中复制这个哈希代码,但两种语言处理字节的方式不同,生成的输出也非常不同。

有人能带我到这儿来吗?

Java代码(原始代码(

public static String hash(String filePath, String salt) {
        String finalHash = null;
        Path path = Paths.get(filePath);
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-1");
            byte[] data = Files.readAllBytes(path);
            byte[] dataDigest = md.digest(data);
            byte[] hashDigest = md.digest(salt.getBytes("ISO-8859-1"));
            byte[] xorBytes = new byte[dataDigest.length];
            for (int i = 0; i < dataDigest.length && i < hashDigest.length; i++) {
                xorBytes[i] = (byte) (dataDigest[i] << 1 ^ hashDigest[i] >> 1);
            }
            finalHash = (new HexBinaryAdapter()).marshal(xorBytes);
        } catch (IOException | NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return finalHash;
    }

Python代码(我翻译(

def generate_hash(file_path: str, salt: bytes) -> str:
    with open(file_path, 'rb') as f:
        data = f.read()
    hashed_file = sha1(data).digest()
    hashed_salt = sha1(salt).digest()
    xor_bytes = []
    for i in range(len(hashed_file)):
        xor_bytes.append((hashed_file[i] << 1 ^ hashed_salt[i] >> 1))
    return ''.join(map(chr, xor_bytes))  # This is probably not equivalent of HexBinaryAdapter

存在以下问题:

  • 在Python代码中错误地实现了移位操作:

    在Python代码中,生成的哈希存储在类似字节的对象中,作为0255[1]之间的无符号整数值的列表,例如0xc8 = 11001000 = 200。在Java中,整数存储为有符号值,其中二者的补码用于表示负数[2][3]。如果值0x8c存储在byte变量中,则该值将被解释为-56

    对于有符号值和无符号值,>>-运算符在二进制级别上产生不同的结果,因为它是一个保留符号[4][5][6]的算术移位运算符。示例:

    signed       -56 >> 1 = 1110 0100 = -28
    unsigned     200 >> 1 = 0110 0100 = 100
    

    另一方面,<<-运算符不会导致上述问题,但可能导致无法用字节表示的值。示例:

    signed       -56 << 1 = 1 1001 0000 = -112
    unsigned     200 << 1 = 1 1001 0000 = 400
    

    出于这些原因,在Python代码中

    xor_bytes.append((hashed_file[i] << 1 ^ hashed_salt[i] >> 1))
    

    必须由取代

    xor_bytes.append((hashed_file[i] << 1 ^ tc(hashed_salt[i]) >> 1) & 0xFF)
    

    其中

    def tc(val):
        if val > 127:
            val = val - 256
        return val
    

    确定两个补码表示的负值(或更复杂的逐位运算符,请参见[7](。

    0xFF一起使用位和(&(可确保在Python代码中只考虑相关字节,类似于Java代码[5]。


  • 有几种方法可以将类似列表/字节的对象转换为十六进制字符串(如在Java代码中(,例如使用[8][9]

    bytes(xor_bytes).hex() 
    

    或使用[8][10](作为二进制字符串(

    binascii.b2a_hex(bytes(xor_bytes))
    


  • 在Python代码中,必须考虑salt的编码。由于salt已经作为二进制字符串传递(在Java代码中,它是作为字符串传递的(,因此必须在调用函数之前执行编码:

    saltStr = 'MySalt'
    salt = saltStr.encode('ISO-8859-1')
    

    为了实现与Java代码的功能一致性,salt必须作为字符串传递,并且必须在函数中执行编码。


最新更新