Closed afill closed 7 years ago
da sind ein paar Sachen nicht richtig, die Zahl muss als Bigendian gespeichert werden, und mit 16 Byte Länge für die Verschlüsselung. So funktionierts mit einem 5-Byte Umsatzzähler:
Encrypt:
$tc_bin=str_pad(pack('N', $turnover>>8).chr($turnover),16,chr(0));
Decrypt:
$a=unpack("C*",$result);
$umsatz=$a[5]+($a[4]<<8)+($a[3]<<16)+($a[2]<<24)+($a[1]<<32);
if ($umsatz>0x7fffffffff) $umsatz-=0x10000000000;
@eauth: Dieser Code funktioniert für (betragsmäßig) größere negative Zahlen nicht. Mit z.B. $turnover = -1000000000000 kommt nach Hin- und Rückwärtskonvertierung $umsatz = +99511627776 heraus (auch auf Systemen, auf denen PHP 64-Bit-Integer unterstützt).
So klappt es aber (auch mit noch größeren Zahlen) - und ist sogar einfacher:
<?php
// integer to binary
$tc = -1000000000000000000;
$tc_bin = pack('J', $tc); // 'J' = 64-bit big-endian binary string
// binary to integer
$umsatz = unpack('J', $tc_bin);
echo 'Ergebnis: ', $umsatz[1], "\n";
?>
Ergebnis: -1000000000000000000
Eine "händische" Vorzeichenkorrektur ist nicht nötig (und würde sogar ein falsches Ergebnis erzeugen), da PHP ohnehin mit Zweierkomplement-Zahlen arbeitet.
@afill: Eine linksseitige Verlängerung auf 16 Byte ist für die Verschlüsselung nicht notwendig, da AES-CTR eine Stromchiffre darstellt, also byteweise arbeitet. Man kann auch nur einen Teil des 16-Byte-Blocks befüllen (z.B. die ersten N Byte) und erhält das Resultat dann ebenfalls in den ersten N Byte des 16-Byte-Blocks.
Je nach gewählter Umsatzzähler-Länge kann man N = 5, 6, 7 oder 8 benützen.
Achtung: Der Umsatzzähler kann nur dann als einfache Integer-Variable geführt werden, wenn PHP mit 64-bit-Integern arbeitet. Das ist insbesondere bei der Kombination PHP 5 + Windows nicht der Fall (auch bei 64-bit-Windows nicht). Bei PHP 7 klappt es aber, ebenso wie bei PHP 5 unter 64-bit-Linux.
Dieser Code funktioniert für (betragsmäßig) größere negative Zahlen nicht. Mit z.B. $turnover = -1000000000000 kommt nach Hin- und Rückwärtskonvertierung $umsatz = +99511627776 heraus (auch auf Systemen, auf denen PHP 64-Bit-Integer unterstützt).
Der Code funktioniert nur mit 5-Byte (40-Bit), mehr wird ja wohl niemand für den Umsatzzähler brauchen. Das pack('N'..) habe ich bewusst anstelle von pack('J'..) gewählt weil das 'J' (64-Bit) erst ab php 5.6.3 eingeführt wurde.
Die 64-Bit Unterstützung ist natürlich Grundvoraussetzung, das sollte man mit PHP_INT_SIZE vorher überprüfen um spätere unliebsame Überraschungen zu vermeiden.
OK, dass das nur für 5 Byte ist, hatte ich überlesen. Dann passt es natürlich.
Herzlichen Dank
Habe derzeit noch Probleme mit einem negativen Summenspeicher. Bei positiven Werten laufen meine Tests problemlos durch:
`
`
Meine Werte zum Testen: $cashbox_id = 'b19e'; $key_base64 = 'LbEk2v8pMhiNaVHsj3wogDrdaXwhgIE3pshyzRdxUE0='; $receipt_number = 20200033; $turnover = -3080
Wenn ich das decrypte kommt 3080 heraus ...
Kann mir hier wer einen Tipp geben?