Вывод crc32b в PHP не равен Python - PullRequest
       11

Вывод crc32b в PHP не равен Python

0 голосов
/ 15 февраля 2019

Я пытаюсь преобразовать PHP фрагмент в код Python3, но выходные данные print и echo отличаются.

Вы можете увидеть это на шаге 1.

Знаете ли вы, где проблема?Я также присоединяю входные массивы, но я думаю, что они равны.

�W2+ vs ee7523b2

РЕДАКТИРОВАТЬ

Когда я переключаю raw с TRUE на FALSE, выходы 1-го шагатот же самый.$d = strrev(hash("crc32b", $d, FALSE)) . $d

Но проблема в том, что мне нужно конвертировать PHP в Python, а не наоборот, потому что тогда я использую шаг 2, который мне нужен для получения одинакового вывода.

PHP ВЫХОД (CMD)

0 ->    1   1   100 EUR 20190101    11111111                Faktúra 1   SK6807200002891987426353        0   0
1 -> �W2+   1   1   100 EUR 20190101    11111111                Faktúra 1   SK6807200002891987426353        0   0
2 -> 00004e00007715c242b04d5014490af1445dd61c1527ddc5f4461ca5886caf63fd8fbcf7df69c2035760ecb28d8171efdb409c0206996498ea7921e715172e60c210f923f070079ffba40000

ВЫХОД ПИТОНА

-------
0 ->    1   1   100 EUR 20190101    11111111                Faktúra 1   SK6807200002891987426353        0   0
1 -> ee7523b2   1   1   100 EUR 20190101    11111111                Faktúra 1   SK6807200002891987426353        0   0
2 -> b'00006227515c7830302762275c783030325c7865305c7864386a34585c7862346d5c7838665c7865625c7863315c786266625c7839625c786339675c786332785c7831645c7862392c415c7862625c7831645c78663770365c786463735c786236572d606c225c7865355c7865635c7831345c7863655c786331205c7830635c7831315c7861375c7839345c7864665c7865635c7830365c7831652c22265c7866355c7862335c7866345c78616145585c7861625c7866395c7839615c7839645c7865645c7864625c7830305c7864355c7861643b5c7865365f5c7866645c786533405c78303027'

PHP

<?php
$suma = "100";
$datum = "20190101";
$varsym = "11111111";
$konsym = "";
$specsym = "";
$poznamka = "Faktúra";
$iban = "SK6807200002891987426353";
$swift = "";

$d = implode("\t", array(
    0 => '',
    1 => '1',
    2 => implode("\t", array(
        true,
        $suma,                      // SUMA
        'EUR',                      // JEDNOTKA
        $datum,                 // DATUM
        $varsym,                    // VARIABILNY SYMBOL
        $konsym,                        // KONSTANTNY SYMBOL
        $specsym,                       // SPECIFICKY SYMBOL
        '',
        $poznamka,                  // POZNAMKA
        '1',
        $iban,  // IBAN
        $swift,                 // SWIFT
        '0',
        '0'
    ))
));
// 0
echo "0 -> ".$d."\n";
$d = strrev(hash("crc32b", $d, TRUE)) . $d;
// 1
echo "1 -> ".$d."\n";
$x = proc_open("/usr/bin/xz '--format=raw' '--lzma1=lc=3,lp=0,pb=2,dict=128KiB' '-c' '-'", [0 => ["pipe", "r"], 1 => ["pipe", "w"]], $p);
fwrite($p[0], $d);
fclose($p[0]);
$o = stream_get_contents($p[1]);
fclose($p[1]);
proc_close($x);

$d = bin2hex("\x00\x00" . pack("v", strlen($d)) . $o);
// 2
echo "2 -> ".$d."\n";
?>

ПИТОН

    def crc32b(x):
        h = zlib.crc32(x)
        x='%08X' % (h & 0xffffffff,)
        return x.lower()

    t = "\t"
    gen = t.join(["1",
                  "100", # SAME VARIABLES 
                  "EUR",
                  "20190101",
                  "11111111",
                  "",
                  "",
                  "",
                  "Faktúra",
                  "1",
                  "SK6807200002891987426353",
                  "",
                  "0",
                  "0"]
                 )

    d = t.join([
        "", "1", gen])
    # 0
    print(f"0 -> {d}")
    hashD = crc32b(d.encode()) # OK

    hashD = hashD[::-1]
    # hashD = str(binascii.unhexlify(hashD))
    d = hashD + d
    # 1
    print(f"1 -> {d}")
    args = shlex.split("xz '--format=raw' '--lzma1=lc=3,lp=0,pb=2,dict=128KiB' -c -")
    process = subprocess.Popen(args, shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
                               stderr=subprocess.PIPE)
    output = process.communicate(d.encode())

    pack = "\x00\x00" + str(struct.pack("H", len(d))) + str(output[0])

    d = binascii.hexlify(pack.encode())
    # 2
    print(f"2 -> {d}")

Ответы [ 2 ]

0 голосов
/ 15 февраля 2019

Не работает с PHP .
Согласно [Python 3]: zlib. crc32 ( data [, value] ) ( выделение - мое):

Вычисляет контрольную сумму CRC (проверка циклическим избыточным кодом) data .В результате получается 32-разрядное целое число без знака .

Вы путаете:

  • Его значение, которое также можно рассматривать как ASCII строка длиной 4
  • Текстовое представление его значения (в base 16 ) - строка длиной 8
>>> crc = 0x2B3257EE  # The value returned by zlib.crc32 for your text
>>> type(crc), crc
(<class 'int'>, 724719598)
>>>
>>> [chr((crc >> shift_bits) & 0xFF) for shift_bits in [0, 8, 16, 24]]
['î', 'W', '2', '+']

Примечания :

  • Один из способов сделать это - преобразовать каждый из 4 байтов числа в char
  • Чтобы получить байт из значения uint32 , uint32 необходимо сместить вправо ( [Python.Wiki]: BitwiseOperators ) по порядку этого байта в значении ( [3, 2, 1, 0] ), умноженном на 8 (количество бит в байте)
    • Кроме того, чтобы избавиться от нежелательных байтов (любого из них, кроме самого правого), результирующее значение также равно и ed с 0xFF ( 255 )
  • Из-за little endian ness байты преобразуются в char s в обратном порядке (справа налево)
  • The 1 st char ('î') выглядит иначе, но это просто вопрос представления (в моей консоли vs yours)

Интеграцияв ваш код, вам нужно изменить функцию crc32b (а также удалить любую дальнейшую обработку на hashD ), чтобы:

def crc32b(x):
    crc = zlib.crc32(x)
    return "".join([chr((crc >> shift_bits) & 0xFF) for shift_bits in [0, 8, 16, 24]])

Для получения более подробной информации об этом общемтема, проверьте [SO]: поведение Python struct.pack () (@ ответ CristiFati) .

@ EDIT0 :

Добавление версии, которая начинается с представления hex :

>>> crc = 0x2B3257EE
>>> crc_hex = "{:08X}".format(crc)
>>> crc_hex
'2B3257EE'
>>>
>>> list(reversed([chr(int(crc_hex[2 * i] + crc_hex[2 * i + 1], 16)) for i in range(len(crc_hex) // 2)]))
['î', 'W', '2', '+']
  • Из моего PoV , это более уродливоКроме того, это неэффективно (многие преобразования туда и обратно), но, тем не менее, публикация сообщений, поскольку у некоторых людей возникают проблемы при работе с битовыми операциями
  • Ключевым моментом является обработка 2 hex char с за раз, и только обратный после преобразования
0 голосов
/ 15 февраля 2019

вам просто нужно удалить 3-й аргумент функции hash()

, если вы установите для этого аргумента значение true, хеш вернет необработанные двоичные данные, а php попытается проанализировать их как текстовую строку, тогда как выожидаем шестнадцатеричный результат

...