BMF-RKSV-Technik / at-registrierkassen-mustercode

111 stars 39 forks source link

Umsatzzähler/Kassastand #542

Open stebrl opened 7 years ago

stebrl commented 7 years ago

Hallo, ich ersuche um Unterstützung, weil mir in diesem Punkt das Verständnis fehlt:

Nachdem man einen Startbeleg erstellt hat, beginnt der Umsatzzähler mit 0. Sobald man nun Bar-, Maestro- und Kreditkartenzahlungen signiert, beeinflussen all diese Zahlungen den Umsatzzähler. In vielen Berichten wird der Umsatzzähler mit dem Kassastand gleichgestellt. Ich habe gelesen, dass nach dem Erstellen des Startbeleges eine Bareinlage gemacht wird, um den Umsatzzähler an den Kassastand anzupassen.

Sobald aber die erste Kartenzahlung erfolgt, unterscheidet sich der Umsatzzähler aber vom Kassastand weil die Kartenzahlung keinem Bargeld entspricht. Kann mir bitte jemand erklären was es mit dem Umsatzzähler auf sich hat? Was bringt der Zählerstand, wenn er weder mit dem Kassastand, Kontostand, Gesamtumsatz usw. konform ist?

Danke!

lebail commented 7 years ago

Es ist richtig, dass der Umsatzzähler aus verschiedensten Gründen nicht mit dem Kassastand oder dem Gesamtumsatz übereinstimmt.

Der Umsatzzähler ist lediglich technischer Bestandteil der Sicherheitseinrichtung - und wird nicht als alleiniges Instrument zur Ermittlung des Umsatzes oder anderer Unternehmenskennzahlen benutzt. Man sollte ihn vielleicht eher als "Summenspeicher" bezeichnen.

Dieses Thema wurde übrigens hier im Forum während der letzten 1½ Jahre immer wieder diskutiert.

stebrl commented 7 years ago

Vielen Dank für die Info!

BRRIT2017 commented 7 years ago

Hi, Ich habe ein kleines Problem bei dem Ihr mir ganz bestimmt helfen könnt :-)

Habe folgende Werte: KassenID: rgiKa2 BelegNr: 8564 Umsatz: 24 KassenID: DMryBaXqtOMiAAOTzdJUiwboSBVAGV2OCkkBx+pvu5w=

Frage1: Ist der Umsatz mit Nachkommern (24,00) oder nicht (24) ich meine laut Doku nicht... Frage2: Könnte mir das mal jemand verschlüsseln und das Ergebnis geben?

Hintergrund ist der, dass ich anscheinden bei der Verschlüsselung ein Fehler habe? Zumindestens sagt das das Prüftool?

ErichFreitag commented 7 years ago

Die Beträge sind in den Steuersätzen gemäß Dokumentation mit zwei Nachkommastellen anzugeben.

Verschlüsseln müssen sie selbst, das ist nicht errechenbar.

lebail commented 7 years ago

Ich nehme an, Sie meinen den Umsatzzähler, und die letzte Zeile ist der AES-Schlüssel. Dann wäre das unter Annahme eines 8-Byte-Umsatzzählers folgendermaßen (der Umsatzzähler ist in Cent anzugeben, in Ihrem Beispiel also 2400):

SELECT TO_BASE64(AES256_CTR(
    TO_BINARY(2400, 8),
    SHA256('rgiKa2' || '8564', 16),
    FROM_BASE64('DMryBaXqtOMiAAOTzdJUiwboSBVAGV2OCkkBx+pvu5w=')
))

Ergebnis: /GSqUOQFtNE=

BRRIT2017 commented 7 years ago

Irgendwie komme ich auf das Ergebnis: /GSqUOQFvbHN50ZGNozIkA==

Hier das berechnen:

using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.IO; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Security; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography; using System.Text;

namespace DepErzeugen { public class RGIVSModule { public static byte[] GenerateKey() { AesManaged aesKey = new AesManaged(); aesKey.KeySize = 256; aesKey.GenerateKey();

        return aesKey.Key;
    }

    public static byte[] Encrypt(long umsatz, string kassenID, string belegnummer, byte[] aesKey)
    {
        byte[] data = EncodeUmsatz(umsatz);
        byte[] iv = GenerateIV(kassenID, belegnummer);

        return Encrypt(data, iv, aesKey);
    }

    public static long Decrypt(byte[] data, string kassenID, string belegnummer, byte[] aesKey)
    {
        long umsatz = -1;
        byte[] iv = GenerateIV(kassenID, belegnummer);
        byte[] decrypted = Decrypt(data, iv, aesKey);
        if (decrypted != null)
        {
            umsatz = DecodeUmsatz(decrypted);
        }

        return umsatz;
    }

    private static byte[] Encrypt(byte[] data, byte[] IV, byte[] aesKey)
    {
        byte[] encrypted = null;
        IBufferedCipher cipher = CipherUtilities.GetCipher("AES/CTR/NoPadding");

        try
        {
            KeyParameter skey = new KeyParameter(aesKey);
            ParametersWithIV aesIVKeyParam = new ParametersWithIV(skey, IV);
            cipher.Init(true, aesIVKeyParam);
        }
        catch (Exception e)
        {
            Console.WriteLine("Encrypt exception (init): " + e.Message);
            return null;
        }

        try
        {
            MemoryStream bOut = new MemoryStream();
            CipherStream cOut = new CipherStream(bOut, null, cipher);

            cOut.Write(data, 0, data.Length);
            cOut.Close();
            encrypted = bOut.ToArray();
        }
        catch (Exception e)
        {
            Console.WriteLine("Encrypt exception: " + e.Message);
            encrypted = null;
        }

        return encrypted;

    }

    private static byte[] Decrypt(byte[] data, byte[] iv, byte[] aesKey)
    {
        byte[] output = null;

      IBufferedCipher cipher = CipherUtilities.GetCipher("AES/CTR/NoPadding");

        try
        {
            KeyParameter skey = new KeyParameter(aesKey);
            ParametersWithIV aesIVKeyParam = new ParametersWithIV(skey, iv);
            cipher.Init(false, aesIVKeyParam);
        }
        catch (Exception e)
        {
            Console.WriteLine("Decrypt exception (init): " + e.Message);
            return output;
        }

        try
        {
            MemoryStream bIn = new MemoryStream(data, false);
            CipherStream cIn = new CipherStream(bIn, cipher, null);
            BinaryReader dIn = new BinaryReader(cIn);

            output = new byte[data.Length];
            Array.Clear(output, 0, output.Length);
            output = dIn.ReadBytes(output.Length);
        }
        catch (Exception e)
        {
            Console.WriteLine("Decrypt exception : " + e.Message);
            return output;
        }

        return output;
    }

    private static byte[] GenerateIV(string kassenId, string belegNummer)
    {
        byte[] inBytes = System.Text.Encoding.UTF8.GetBytes(kassenId + belegNummer);
        SHA256 hasher = SHA256Managed.Create();
        byte[] hashBytes = hasher.ComputeHash(inBytes);

        byte[] iv = new List<byte>(hashBytes).GetRange(0, 16).ToArray();

        return iv;
    }

    private static long DecodeUmsatz(byte[] umsatzBytes)
    {
        // reverse to get little-endian array
        Array.Reverse(umsatzBytes, 0, umsatzBytes.Length);
        return BitConverter.ToInt64(umsatzBytes, 0);
    }

    private static byte[] EncodeUmsatz(long umsatz)
    {
        // This gives an 8-byte array
        byte[] umsatzBytes = BitConverter.GetBytes(umsatz);
        // Pad with zeroes to get 16 bytes
        int length = 16 * ((umsatzBytes.Length + 15) / 16);
        Array.Resize(ref umsatzBytes, length);
        // reverse to get big-endian array
        Array.Reverse(umsatzBytes, 0, umsatzBytes.Length);
        return umsatzBytes;
    }

}

}

lebail commented 7 years ago

Ja, ich habe einen 8-Byte-Umsatzzähler benutzt. Bei einem 16-Byte-Umsatzzähler kommt auch mir /GSqUOQFvbHN50ZGNozIkA== heraus. Ihr Ergebnis stimmt also.

BRRIT2017 commented 7 years ago

Haben Sie ein Idee wie ich auf 8 Bit kommen könnte? Die 16 Bit scheinen für das Prüftool des BMF zu lang zu sein :-(

lebail commented 7 years ago

Angeblich kommt das Prüftool mit 16 Byte zurecht (ich selbst habe aber nur 5, 6, 7 und 8 Byte probiert).

Zum Verkürzen z.B. auf 8 Byte benutzen Sie nur die ersten 8 Byte des 16-Byte-AES-Blockes und schreiben vor dem Verschlüsseln dort die niederwertigsten 8 Byte des Umsatzzählers hinein. Nach dem Verschlüsseln lesen Sie auch nur diese ersten 8 Byte wieder heraus.

BRRIT2017 commented 7 years ago

Super :-) Den ersten Teil hab ich jetzt! Jetzt kommt der zweite Teil... :-( Da ich jetzt eine Umsatzzähler habe brauche ich nur noch den DEP-Satz hinbekommen...

Startbeleg: _R1-AT1_rgiKa2_8580_2017-04-06T19:11:00_0,00_0,00_0,00_0,00_0,00_VnAoTCb97f4=_44FCC78C_VnAoTCb97f4= /K:DMryBaXqtOMiAAOTzdJUiwboSBVAGV2OCkkBx+pvu5w=

Erste Beleg: _R1-AT1_rgiKa2_8582_2017-04-06T19:38:32_0,00_3,49_0,00_0,00_0,00_OVtQpEYN15k=_44FCC78C_VnAoTCb97f4=

Der nötige AES-Key: DMryBaXqtOMiAAOTzdJUiwboSBVAGV2OCkkBx+pvu5w=

Könnte mir jemand den Signaturwert für die beiden DEP-Sätze geben? Dann wäre ich fast durch mit der Kasse :-))

BRRIT2017 commented 7 years ago

Natürlich gehört der Parameter "/K:DMryBaXqtOMiAAOTzdJUiwboSBVAGV2OCkkBx+pvu5w=" da nicht hin, sorry, war ein Kopierfehler... (Startbeleg Zeile)