Ankündigung

Einklappen
Keine Ankündigung bisher.

Logarithmus (float) sehr ungenau

Einklappen

Neue Werbung 2019

Einklappen
X
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • Logarithmus (float) sehr ungenau

    Ich bin zurzeit dabei, meinen kleinen Verslüsselungsalgorithmus zu programmieren. ER basiert auf dem Logarithmus. Um aus einem Versclüsselten Text wieder die alte Eingabe zu machen, werden zwei Keys genutzt. Diese werden heälftig aus dem Passwort generiert (crc32). Jetzt habe ich das Problem, dass ich bei meinen Tests bemerkt habe, dass als Endergebnis zwar der vorherige zu Verschlüsselne Wert herauskommt, aber dieser nicht aufs Bit genau stimmt.

    Code:
    Password: Test
    Key: 1563025544
    Key 2: 312708591
    Text: 1
    Txetlen: 1
    
    Encrypted: LTE2OTE2MDI5ODAuNDg2
    Decrypted: 0.9999999999998
    Ausgabe = Anfangswert: false
    Differenz: 1.9806378759313E-13
    Zurzeit werden lediglich Zahlen verschlüsselt (hier am Beispiel von 1).
    Der Code, den ich aktuell verwende ist folgender:
    PHP-Code:
    <?php
    $password 
    "Test";
    $keyarr generateKey($password);
    $key $keyarr['key'];
    $key2 $keyarr['key2'];
    $text $argv[1];
    $encrypted encrypt($keyarr$text);
    $decrypted decrypt($keyarr$encrypted);
    echo 
    "Password: ".$password.PHP_EOL."Key: ".$key.PHP_EOL."Key 2: ".$key2.PHP_EOL."Text: ".number_format($text).PHP_EOL."Txetlen: ".strlen($text).PHP_EOL;
    echo 
    PHP_EOL;
    echo 
    "Encrypted: ".$encrypted.PHP_EOL."Decrypted: ".$decrypted.PHP_EOL;
    if(
    $decrypted == $text) {
        echo 
    'true';
    } else {
        if(
    $decrypted <= $text) {
            
    $difference = ($text $decrypted);
        } else {
            
    $difference = ($decrypted $text);
        }
        echo 
    'false.'.$difference;
    }

    function 
    generateKey($password) {
        if((
    strlen($password) % 2) == 1) {
            
    $password str_pad($password, (strlen($password) + 1), '='STR_PAD_RIGHT);
        }
        
    $pwd1 substr($password0, (strlen($password) / 2));
        
    $pwd2 substr($password, (strlen($password) / 2), strlen($password));
        
    $crc1 crc32($pwd1);
        
    $crc2 crc32($pwd2);
        if(
    $crc1 0) {
            
    $crc1 = ($crc1 * -1);
        }
        if(
    $crc2 0) {
            
    $crc2 = ($crc2 * -1);
        }
        return array(
    'key' => $crc1'key2' => $crc2);
    }

    function 
    encrypt($keyarr$text) {
        
    $key $keyarr['key'];
        
    $key2 $keyarr['key2'];
        
    $encrypted base64_encode((float)((log(($text $key)) / log($key2)) * $key));
        return 
    $encrypted;
    }
    function 
    decrypt($keyarr$text) {
        
    $key $keyarr['key'];
        
    $key2 $keyarr['key2'];
        
    $decrypted = (pow($key2, ((float)base64_decode($text)) / $key) * $key);
        return 
    $decrypted;
    }
    ?>
    Für Hilfe wäre ich sehr dankbar!

  • #2
    Was für Hilfe möchtest du denn? Ich habe den Code jetzt nicht wirklich genau analysiert, aber dass floats nicht genau sind ist doch nichts neues.

    Kommentar


    • #3
      So ist das nunmal. double kann eben nunmal Kommazahlen nicht genau darstellen. Was du dagegen tun kannst? Nicht wirklich viel, das ist nämlich ein weites Recherchefeld und moderene numerische Analyse gibt nur Möglichkeiten, Rundungsfehler zu minimieren.
      Crashkurs zum Thema Rechtschreibung: [COLOR="Green"]normalerweise[/COLOR] ([COLOR="Red"]normaler weise[/COLOR] oder [COLOR="Red"]normaler weiße[/COLOR]), [COLOR="DarkGreen"]Standard[/COLOR] ([COLOR="Red"]Standart[/COLOR]), [COLOR="DarkGreen"]eben[/COLOR] ([COLOR="Red"]ebend[/COLOR])

      Kommentar


      • #4
        Zitat von Asterixus Beitrag anzeigen
        So ist das nunmal. double kann eben nunmal Kommazahlen nicht genau darstellen. Was du dagegen tun kannst? Nicht wirklich viel, das ist nämlich ein weites Recherchefeld und moderene numerische Analyse gibt nur Möglichkeiten, Rundungsfehler zu minimieren.
        Das größte Problem ist eben, dass es wie mir scheint nicht nur schnöde rundungsfehler sind... wenn ich mehr als 8 Stellen als Ausgangstext habe, bekomme ich nach number_format($decrypted) rieseige differenzen...

        Würdet ihr Aufrunden empfehlen?

        Dann würde wenigstens das richtige rauskommen. Von der Logik her ist es aber trotzdem noch falsch.

        Kommentar


        • #5
          Ich habe mir den Code nicht genau angeschaut, ich schließe daher aus, dass du unsinnigen Code geschrieben hast.

          Habe aber gesehen, dass du in deiner log Funktion eine Teilung durchführst. Ich habe noch nie mit log numerisch gearbeitet, aber ich gehe mal davon aus, dass das numerisch instabiler ist als die Definition:

          log(a/b) = log(a) - log(b)

          Genauso hat PHP in seiner log-Funktion einen zweiten Parameter für die Basis.

          Da könntest du auch für eventuell genauere Resultate dieses Resultat benutzen:

          log(a)/log(b) = log_{b}(a)
          Crashkurs zum Thema Rechtschreibung: [COLOR="Green"]normalerweise[/COLOR] ([COLOR="Red"]normaler weise[/COLOR] oder [COLOR="Red"]normaler weiße[/COLOR]), [COLOR="DarkGreen"]Standard[/COLOR] ([COLOR="Red"]Standart[/COLOR]), [COLOR="DarkGreen"]eben[/COLOR] ([COLOR="Red"]ebend[/COLOR])

          Kommentar


          • #6
            PHP-Code:
            $decrypted = (pow($key2, ((float)base64_decode($text)) / $key) * $key); 
            Ich habe die starke Vermutung, dass hier das Problem anfängt.
            PHP arbeitet mit 64Bit (http://php.net/manual/de/language.types.float.php), damit können auch nicht mehr als diese 64 Bit an Information vorhanden bleiben, wenn man mit den in PHP eingebauten Zahlen rechnet. Jetzt sind 8 Zeichen zwar 48Bit (bei euch durch das base_64 nur 6Bit * 8 statt 8*, dadurch, dass aber eine 64Bit Gleitkommazahl in nur in 52 Bits ihre Information speichert (der Rest ist Vorzeichen (hier ungenutzt und Exponent) http://de.wikipedia.org/wiki/Gleitko...itkommazahl.29), wird das schon sehr eng mit der Genauigkeit, wenn man davon ausgeht, dass man durch Rundungsfehler bei jeder Rechenoperation 1 Bit verliert. (da immer abgerundet wird)



            Ist die Division im Exponenten unbedingt notwendig? Ohne diese Division könnte man die ganze Rechnung mit ganzen Zahlen durchführen.

            Auf jeden Fall müsst ihr sobald ihr mit größeren Texten arbeitet selbst Algorithmen implementieren, die auch für größere Zahlen noch richtige Ergebnisse liefern. (Oder mal nach fertigen PHP-Bibliotheken für große (ganze) Zahlen suchen)

            PS: Absolute Gleichheit gibt es bei Gleitkommazahlen nicht:
            PHP-Code:
            if($decrypted == $text) { 
            Wird immer false liefern

            PS2: Dies gilt übrigens nicht nur für PHP sondern auch für andere Programmiersprachen
            [URL="http://php.net/manual/en/migration55.deprecated.php"]mysql ist veraltet[/URL] [URL="http://php-de.github.io/jumpto/mail-class/"]Mails senden: Ohne Probleme und ohne mail()[/URL]
            [PHP]echo 'PS: <b>Meine Antwort ist keine Lösung, sondern nur eine Hilfe zur Lösung.</b>';[/PHP]

            Kommentar


            • #7
              Zitat von ChrisvA Beitrag anzeigen
              Ist die Division im Exponenten unbedingt notwendig? Ohne diese Division könnte man die ganze Rechnung mit ganzen Zahlen durchführen.
              Ja ist sie. In der Theorie ist genau das ja die Verschlüsselung. Weil man aus dem Ergebnis heraus nie ohne den dividenden ($key) wieder den Klartext generiern können darf.

              Zitat von ChrisvA Beitrag anzeigen
              PS2: Dies gilt übrigens nicht nur für PHP sondern auch für andere Programmiersprachen
              Habe ich bemerkt... ähnliches Problem mit Python. Auch mit import decimal (BigNumber).

              Gäbe es iwie eine Möglichkeit eines bigfloat oder soetwas?

              Kommentar


              • #8
                Zitat von jankal Beitrag anzeigen
                Habe ich bemerkt... ähnliches Problem mit Python. Auch mit import decimal (BigNumber).
                Bist du sicher, dass du den Decimal-Typ richtig gehandhabt hast?
                http://docs.python.org/2/library/dec...cimal-tutorial

                Ansonsten lohnt sich eventuell ein Blick auf:
                http://pypi.python.org/pypi/bigfloat/
                http://pypi.python.org/pypi/mpmath


                Gäbe es iwie eine Möglichkeit eines bigfloat oder soetwas?
                http://docs.php.net/manual/en/book.gmp.php
                http://docs.php.net/manual/en/book.bc.php
                Wenn man die Wurst schräg anschneidet, hält sie länger, weil die Scheiben größer sind.

                Kommentar


                • #9
                  Nach Google scheint es Klassen für BigFloat zu geben, trotzdem bleibt dein Algorithmus Numerisch sehr instabil.
                  Rechne dir doch mal aus, was du an Genauigkeit (im Verschlüsselten "Text") benötigst, damit eine 64-Bit Zahl am Ende wieder identisch rauskommt.

                  PS: Mathematisch gillt
                  Code:
                  ((log(($text / $key)) / log($key2)) * $key) == ((log(($text)) / log($key2)) * $key) - ((log(($key)) / log($key2)) * $key)
                  Damit wird aus der Division eine Subtraktion. War dir das beim Entwurf bewusst, dass du hier eine nur vom Key abhängige Zahl abziehst?

                  PS2: Ich habe bei meinem ersten Post die Verschlüsselung mit der Entschlüsselung verwechselt. Mein Vorschlag mit den ganzen Zahlen macht aus diesem Grund keinen Sinn
                  [URL="http://php.net/manual/en/migration55.deprecated.php"]mysql ist veraltet[/URL] [URL="http://php-de.github.io/jumpto/mail-class/"]Mails senden: Ohne Probleme und ohne mail()[/URL]
                  [PHP]echo 'PS: <b>Meine Antwort ist keine Lösung, sondern nur eine Hilfe zur Lösung.</b>';[/PHP]

                  Kommentar


                  • #10
                    Mal ne kurze Gegenfrage: Warum muss es eine eigene Verschlüsselung sein?

                    In der Regel sind selbst ausgedachte Verschlüsselungsverfahren für die Tonne.
                    Seine sensitiven Daten sollte man lieber etwas anvertrauen, was getestet wurde und was sich bewährt hat.
                    Über 90% aller Gewaltverbrechen passieren innerhalb von 24 Stunden nach dem Konsum von Brot.

                    Kommentar

                    Lädt...
                    X