Ankündigung

Einklappen
Keine Ankündigung bisher.

Verschlüsselung - Ergänzung Beispielklasse

Einklappen

Neue Werbung 2019

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

  • Verschlüsselung - Ergänzung Beispielklasse

    Würde für diesen Beitrag zum Thema Verschlüsselung folgende lauffähige (Basic-)Beispielklasse ergänzen. Habe mich zwecks "Herzeigbarkeit" absichltich für die (im Grunde nicht nötige) Anwendung von base64_...() entschieden.

    Falls es dazu etwaiges zu sagen gibt, bitte - danke!

    PHP-Code:
    <?php

    // needs activated php_mcrypt.dll extension

    class Cipher
    {

        private 
    $securekey$iv;

        private
            
    $crypt_cipher MCRYPT_RIJNDAEL_256,
            
    $crypt_mode   MCRYPT_MODE_CBC,
            
    $iv_source    MCRYPT_RAND;

        public function 
    __construct($passphrase)
        {
            
    $this->securekey hash('sha256'$passphrasetrue);
            
    $this->iv mcrypt_create_ivmcrypt_get_iv_size($this->crypt_cipher$this->crypt_mode), $this->iv_source );
        }

        public function 
    encrypt($data)
        {
            return 
    base64_encodemcrypt_encrypt($this->crypt_cipher$this->securekey$data$this->crypt_mode$this->iv) );
        }

        public function 
    decrypt($data)
        {
            return 
    rtrimmcrypt_decrypt$this->crypt_cipher$this->securekeybase64_decode($data), $this->crypt_mode$this->iv ), "\0\4" );
        }

    }

    Test:
    PHP-Code:
    $data 'Der geheime Text';
    $passphrase '52s.5f4,4er';

    $cipher = new Cipher($passphrase);
    $crypted $cipher->encrypt($data);
    $decrypted $cipher->decrypt($crypted);

    var_dump($crypted);   // qR21CymfIUv573gnlGONaZ4s/6za9D40mm4lSGTKy5c=
    var_dump($decrypted); // Der geheime Text 
    LG
    Debugging: Finde DEINE Fehler selbst! | Gegen Probleme beim E-Mail-Versand | Sicheres Passwort-Hashing | Includes niemals ohne __DIR__
    PHP.de Wissenssammlung | Kein Support per PN


  • #2
    PHPDocs und ein eindeutiger Coding Standard wäre nicht schlecht..

    PHP-Code:
    <?php

    /**
     * Mcrypt Adapter
     *
     * @license https://creativecommons.org/publicdomain/zero/1.0/
     * @see http://php.net/manual/en/mcrypt.installation.php
     * @see http://php.net/manual/en/mcrypt.requirements.php
     * @see https://en.wikipedia.org/wiki/Adapter_pattern
     */
    class Cipher
    {
        
    /**
         * @var hash of passphrase
         */
        
    private $secureKey;
        
        
    /**
         * @var initialization vector
         */
        
    private $initializationVector;

        
    /**
         * @var en-/decryption method
         */
        
    private $cryptCipher MCRYPT_RIJNDAEL_256;
        
        
    /**
         * @var en-/decryption mode
         */
        
    private $cryptMode MCRYPT_MODE_CBC;
        
        
    /**
         * @var initialization vector source
         */
        
    private $initializationVectorSource MCRYPT_RAND;

        
    /**
         * Constructor
         *
         * @api
         * @param string $passpharse
         */
        
    public function __construct($passphrase)
        {
            
    $this->secureKey hash('sha256'$passphrasetrue);
            
    $this->initializationVector mcrypt_create_iv(
                
    mcrypt_get_iv_size($this->cryptCipher$this->cryptMode),
                
    $this->initializationVectorSource
            
    );
        }

        
    /**
         * query command - encrypts the given data string
         *
         * @api
         * @param string $unencryptedData
         * @return string
         */
        
    public function encrypt($unencryptedData)
        {
            return 
    base64_encode(
                
    mcrypt_encrypt(
                    
    $this->cryptCipher,
                    
    $this->secureKey,
                    
    $unencryptedData,
                    
    $this->cryptMode,
                    
    $this->initializationVector
                
    )
            );
        }

        
    /**
         * query command - decrypts the given encrypted string
         *
         * @api
         * @param string $encryptedData
         * @return string
         */
        
    public function decrypt($encryptedData)
        {
            return 
    rtrim(
                
    mcrypt_decrypt(
                    
    $this->cryptCipher,
                    
    $this->secureKey,
                    
    base64_decode($encryptedData),
                    
    $this->cryptMode,
                    
    $this->initializationVector
                
    ),
                
    "\0\4"
            
    );
        }
    }
    [URL="https://gitter.im/php-de/chat?utm_source=share-link&utm_medium=link&utm_campaign=share-link"]PHP.de Gitter.im Chat[/URL] - [URL="https://raindrop.io/user/32178"]Meine öffentlichen Bookmarks[/URL] ← Ich habe dir geholfen ? [B][URL="https://www.amazon.de/gp/wishlist/348FHGUZWTNL0"]Beschenk mich[/URL][/B].

    Kommentar


    • #3
      Eine Methode zum Ändern der Passphrase wäre ganz praktisch.
      Und ein paar Parameterchecks wären auch sinnvoll.

      PHP-Code:
      <?php

      /**
       * Mcrypt Adapter
       *
       * @license https://creativecommons.org/publicdomain/zero/1.0/
       * @see http://php.net/manual/en/mcrypt.installation.php
       * @see http://php.net/manual/en/mcrypt.requirements.php
       * @see https://en.wikipedia.org/wiki/Adapter_pattern
       */
      class Cipher
      {
          
      /**
           * @var string hash of passphrase
           */
          
      private $secureKey;

          
      /**
           * @var string initialization vector
           */
          
      private $initializationVector;

          
      /**
           * @var string en-/decryption method
           */
          
      private $cryptCipher MCRYPT_RIJNDAEL_256;

          
      /**
           * @var string en-/decryption mode
           */
          
      private $cryptMode MCRYPT_MODE_CBC;

          
      /**
           * @var int initialization vector source
           */
          
      private $initializationVectorSource MCRYPT_RAND;

          
      /**
           * Constructor
           *
           * @api
           * @param $passphrase
           */
          
      public function __construct($passphrase)
          {
              
      $this->setPassphrase($passphrase);
          }

          
      /**
           * Sets the passphrase for encryption or decryption
           *
           * @api
           * @param string $passphrase
           *
           * @throws InvalidArgumentException if the provided argument is not a string
           */
          
      public function setPassphrase($passphrase) {
              if(
      false === is_string($passphrase)) {
                  throw new 
      InvalidArgumentException('Passphrase must be a string');
              }

              
      $this->secureKey hash('sha256'$passphrasetrue);
              
      $this->initializationVector mcrypt_create_iv(
                  
      mcrypt_get_iv_size($this->cryptCipher$this->cryptMode),
                  
      $this->initializationVectorSource
              
      );
          }

          
      /**
           * query command - encrypts the given data string
           *
           * @api
           * @param string $unencryptedData
           *
           * @throws InvalidArgumentException if the provided argument is not a string
           * @return string
           */
          
      public function encrypt($unencryptedData)
          {
              if(
      false === is_string($unencryptedData)) {
                  throw new 
      InvalidArgumentException('Unencrypted data must be a string');
              }

              return 
      base64_encode(
                  
      mcrypt_encrypt(
                      
      $this->cryptCipher,
                      
      $this->secureKey,
                      
      $unencryptedData,
                      
      $this->cryptMode,
                      
      $this->initializationVector
                  
      )
              );
          }

          
      /**
           * query command - decrypts the given encrypted string
           *
           * @api
           * @param string $encryptedData
           *
           * @throws InvalidArgumentException if the provided argument is not a string
           * @return string
           */

          /**
           * @param $encryptedData
           *
           * @return string
           */
          
      public function decrypt($encryptedData)
          {
              if(
      false === is_string($encryptedData)) {
                  throw new 
      InvalidArgumentException('Crypted data must be a string');
              }

              return 
      rtrim(
                  
      mcrypt_decrypt(
                      
      $this->cryptCipher,
                      
      $this->secureKey,
                      
      base64_decode($encryptedData),
                      
      $this->cryptMode,
                      
      $this->initializationVector
                  
      ),
                  
      "\0\4"
              
      );
          }
      }
      -

      Kommentar


      • #4
        Zitat von jack88
        Eine Methode zum Ändern der Passphrase wäre ganz praktisch.
        Generell sind immutable Klassen zu bevorzugen, da sie eine ganze Klasse von möglichen Fehlern ausräumen. So musst du keine Angst haben, dass irgendwo (unkontrolliert) die Phrase geändert wird, wofür es wahrscheinlich auch keinen Grund gibt. Wenn du eine neue Phrase brauchst, dann erzeuge das Objekt einfach neu.

        Ansonsten kann man das Design der Objekte auch etwas anders planen. Das Kernobjekt wäre dann dafür Zuständig, den Verschlüsselungsalgoritmus zu verwalten und die Encode/Decode-Methoden bekämen als zweiten Parameter noch die Passphrase mit. Ein weiteres Objekt wird darum gewrappt und gibt die Passphrase vor - wenn gewünscht.
        Standards - Best Practices - AwesomePHP - Guideline für WebApps

        Kommentar


        • #5
          Generell sind immutable Klassen zu bevorzugen, da sie eine ganze Klasse von möglichen Fehlern ausräumen.
          Immutable Objekte sollen Klasse von möglichen Fehlern ausräumen

          Wenn Du mit "Fehlern" das Setzen einer falschen Passphrase meinst, wo liegt dann der Unterschied ob ich beim Instanziieren eines Objektes eine falsche Passphrase übergebe oder mittels einer setPassphrase() Methode?

          So musst du keine Angst haben, dass irgendwo (unkontrolliert) die Phrase geändert wird,
          Wenn "irgendwo unkontrolliert" die Paphrase geändert werden kann, dann läuft da grundsätzlich was schief... Außerdem wird damit auch nicht verhindert, daß ein neues Objekt mit einer geänderten Passphrase erstellt wird? Die Problematik scheint mir hier ein wenig konstruiert und in diesem Zusammenhang wenig realistisch. Und wenn Du ein Objekt vor Änderungen schützen willst dann... (s.u.)

          Das Kernobjekt wäre dann dafür Zuständig, den Verschlüsselungsalgorithmus zu verwalten und die Encode/Decode-Methoden bekämen als zweiten Parameter noch die Passphrase mit. Ein weiteres Objekt wird darum gewrappt und gibt die Passphrase vor - wenn gewünscht.
          Dann könntest Du genauso gut ein Wrapper-Objekt für die Cipher-Klasse mit der setPassphrase()-Methode nehmen? Das kannst Du dann so immutable gestalten wie Du willst und die Cipher-Klasse selbst wird nicht unnötig eingeschränkt. Jedes Mal die Passphrase der en-/decode Methoden zu übergeben ist wirklich keine gute Idee und nicht im Sinne von OOP, wo man mit Objekten arbeitet die diese Information speichern können und sollten.

          VG
          Jack
          -

          Kommentar


          • #6
            Zitat von jack88
            Wenn Du mit "Fehlern" das Setzen einer falschen Passphrase meinst, wo liegt dann der Unterschied ob ich beim Instanziieren eines Objektes eine falsche Passphrase übergebe oder mittels einer setPassphrase() Methode?
            Ich meine, dass du die Phrase später einfach nicht mehr verändern kannst und damit das Objekt so bleibt wie es ist, egal wo es zwischenzeitlich war.

            Keinen Fehler machen zu können ist sicherer als darauf zu achten, keinen zu machen.

            Zitat von moma
            übergebe ich die klasse dann dem constructor der verschlüsselungsklasse?
            Du übergibst die Verschlüsselungklasse dem Wrapper via Constructor-Injection.

            Zitat von moma
            macht es sinn dafür eine klasse zu nehmen, und nicht wenigstens block und stream cyphers zu trennen.
            Wenn du eine Generalimplementation schaffen willst, eher ja. Ansonsten ist das so ziemlich dir und deinem Vorhaben überlassen...
            Standards - Best Practices - AwesomePHP - Guideline für WebApps

            Kommentar


            • #7
              Ich meine, dass du die Phrase später einfach nicht mehr verändern kannst und damit das Objekt so bleibt wie es ist, egal wo es zwischenzeitlich war.
              Ja ist schon klar, aber wieso sollte sich ausgerechnet die Cipher-Klasse mit solchen Fragen beschäftigen und quasi vom Haus aus dem Client "Sicherheitsmechanismen" aufdrängen bzw. Funktionalität vorenthalten, die dieser möglicherweise entweder nicht benötigt oder gut gebrauchen könnte? Liegt der richtige Umgang mit dem Cipher-Objekt nicht in der Verantwortung des Clients? Oder soll das Cipher-Objekt den Client vor sich selbst beschützen auch wenn es nicht die geringste Ahnung haben kann in welchem Kontext es benutzt wird?

              VG
              Jack
              -

              Kommentar


              • #8
                Ich weiß gerade nicht, wo ich dich da abholen kann. Es geht nur darum, dass du (bzw dein Team) dir/sich nicht selbst ein Bein stellen kann(st).
                Standards - Best Practices - AwesomePHP - Guideline für WebApps

                Kommentar


                • #9
                  Es geht nur darum, dass du (bzw dein Team) dir/sich nicht selbst ein Bein stellen kann(st).
                  Danke dafür, aber Bevormundung im Kontext > 18 ist i.d.R. keine so gute Idee

                  VG
                  Jack
                  -

                  Kommentar


                  • #10
                    Dann solltest du einen weiten Bogen um Scala machen.
                    Standards - Best Practices - AwesomePHP - Guideline für WebApps

                    Kommentar


                    • #11
                      PHP-Code:
                      <?php

                      // needs activated php_mcrypt.dll extension

                      class Cipher
                      {

                          private 
                      $securekey$iv;

                          private
                              
                      $crypt_cipher MCRYPT_RIJNDAEL_256,
                              
                      $crypt_mode   MCRYPT_MODE_CBC,
                              
                      $iv_source    MCRYPT_RAND;

                          public function 
                      __construct($passphrase$iv null)
                          {
                              
                      $this->securekey hash('sha256'$passphrasetrue);
                              
                      $this->iv $iv?:mcrypt_create_ivmcrypt_get_iv_size($this->crypt_cipher$this->crypt_mode), $this->iv_source );
                          }

                          public function 
                      encrypt($data)
                          {
                              return 
                      base64_encodemcrypt_encrypt($this->crypt_cipher$this->securekey$data$this->crypt_mode$this->iv) );
                          }

                          public function 
                      decrypt($data)
                          {
                              return 
                      rtrimmcrypt_decrypt$this->crypt_cipher$this->securekeybase64_decode($data), $this->crypt_mode$this->iv ), "\0\4" );
                          }

                          public function 
                      getIV() {
                              return 
                      $this->iv;
                          }

                      }

                      $data 'Der geheime Text';
                      $passphrase '52s.5f4,4er';

                      $cipher = new Cipher($passphrase);
                      $crypted $cipher->encrypt($data);
                      $decrypted $cipher->decrypt($crypted);

                      var_dump($crypted);
                      var_dump($decrypted);

                      $c2 = new Cipher($passphrase$cipher->getIV());
                      var_dump($c2->decrypt($crypted));
                      Der IV muss wohl mitgespeichert werden, oder es muss mithilfe des Passwort(-hashes) ein deterministischer berechnet werden, was aber Möglicherwise nicht ganz so sicher ist.
                      Zitat von nikosch
                      Macht doch alle was Ihr wollt mit Eurem Billigscheiß. Von mir aus sollen alle Eure Server abrauchen.

                      Kommentar


                      • #12
                        Zitat von hausl Beitrag anzeigen
                        Falls es dazu etwaiges zu sagen gibt, bitte - danke!
                        Warum trimst du beim Zero Padding mit auf \4? Wenn das eine Allgemein brauchbare Klasse werden soll würde ich auch eher aufs PKCS7 Padding setzen. Beim Zero Padding besteht die Gefahr das du Nutzdaten abschneidest.
                        Den IV solltest du mit in die Rückgabe von encrypt packen und dort auch wieder her nehmen. Die kombination aus Passwort und IV sollten niemals mehrfach verwendet werden. Damit kommt dann auch niemand auf Ideen wie "Der IV muss wohl mitgespeichert werden, oder es muss mithilfe des Passwort(-hashes) ein deterministischer berechnet werden, was aber Möglicherwise nicht ganz so sicher ist." Das mag in einem Szenario keine negativen einfluss haben, in einem anderen aber umsomehr.

                        Kommentar


                        • #13
                          Aktuelle Version u.A. auf Basis Anmerkungen tr0y und erc , sofern ich das richitg verstanden habe... Quellenangabe zu dem PKCS7 Padding siehe die Links zu Beginn der Klasse und die dort jeweils verlinken Seiten.
                          Das base64 hab ich auch rausgenommen, kann man ja "extern" noch anwenden wenn benötigt.

                          PHP-Code:
                          /**
                           * Mcrypt Adapter
                           *
                           * @license https://creativecommons.org/publicdomain/zero/1.0/
                           * @see http://php.net/manual/en/book.mcrypt.php
                           * @see https://en.wikipedia.org/wiki/Adapter_pattern
                           * @see https://gist.github.com/Halama/5956871
                           * @see http://www.cryptofails.com/post/70059609995/crypto-noobs-1-initialization-vectors
                           */
                          class Cipher
                          {
                              
                          /**
                               * @var hash of passphrase
                               */
                              
                          private $secureKey;

                              
                          /**
                               * @var initialization vector size
                               */
                              
                          private $initializationVectorSize;

                              
                          /**
                               * @var en-/decryption method
                               */
                              
                          private $cryptCipher MCRYPT_RIJNDAEL_256;

                              
                          /**
                               * @var en-/decryption mode
                               */
                              
                          private $cryptMode MCRYPT_MODE_CBC;

                              
                          /**
                               * Constructor
                               *
                               * @api
                               * @param string $passpharse
                               */
                              
                          public function __construct($passphrase)
                              {
                                  
                          $this->secureKey hash('sha256'$passphrasetrue);
                                  
                          $this->initializationVectorSize mcrypt_get_iv_size($this->cryptCipher$this->cryptMode);
                              }

                              
                          /**
                               * query command - encrypts the given data string
                               *
                               * @api
                               * @param string $unencryptedData
                               * @return string
                               */
                              
                          public function encrypt($unencryptedData)
                              {
                                  
                          $blockSize mcrypt_get_block_size($this->cryptCipher$this->cryptMode);
                                  
                          $pad $blockSize - (strlen($unencryptedData) % $blockSize);
                                  
                          $iv mcrypt_create_iv($this->initializationVectorSizeMCRYPT_DEV_URANDOM);

                                  return 
                          $iv.mcrypt_encrypt(
                                              
                          $this->cryptCipher,
                                              
                          $this->secureKey,
                                              
                          $unencryptedData str_repeat(chr($pad), $pad),
                                              
                          $this->cryptMode,
                                              
                          $iv
                                  
                          );
                              }

                              
                          /**
                               * query command - decrypts the given encrypted string
                               *
                               * @api
                               * @param string $encryptedData
                               * @return string
                               */
                              
                          public function decrypt($encryptedData)
                              {
                                  
                          $decryptedData mcrypt_decrypt(
                                          
                          $this->cryptCipher,
                                          
                          $this->secureKey,
                                          
                          substr($encryptedData$this->initializationVectorSize),
                                          
                          $this->cryptMode,
                                          
                          substr($encryptedData0$this->initializationVectorSize)
                                  );
                                  
                          $pad ord($decryptedData[strlen($decryptedData) - 1]);
                                  return 
                          substr($decryptedData0, -$pad);
                              }


                          Test:
                          PHP-Code:
                          // Test
                          $passphrase 'f00bar';
                          $data 'Fußball á la Bärbel';

                          // Person A:
                          $cipherA = new Cipher($passphrase);
                          $crypted $cipherA->encrypt($data);
                          var_dumpbase64_encode($crypted) ); // Test: div. base64-Strings [F5]

                          // Person B:
                          $cipherB = new Cipher($passphrase);
                          $decrypted $cipherB->decrypt($crypted);
                          var_dump($decrypted); // Fußball á la Bärbel 
                          Debugging: Finde DEINE Fehler selbst! | Gegen Probleme beim E-Mail-Versand | Sicheres Passwort-Hashing | Includes niemals ohne __DIR__
                          PHP.de Wissenssammlung | Kein Support per PN

                          Kommentar


                          • #14
                            Das sieht gut aus. Das Padding ist aber falsch implementiert. Wenn die Daten ein vielfaches der Blockgröße sind wird ein Block angehangen.

                            PHP-Code:
                            $pad $blockSize - (strlen($unencryptedData) % $blockSize)?:$blockSize
                            Ich würde noch rijndeal 128 als Standard setzen. Damit wird dass Ergebnis bei kurzen Eingaben kleiner und es wäre mit AES 256 kompatibel. (Bei rijndeal steht die Zahl für die Blockgröße, bei AES für die Schlüssellänge. Die Blückgröße bei AES ist immer 128.)

                            Kommentar


                            • #15
                              ok.. danke für Infos! Somit sieht aktuell finaler Entwurf aus ...

                              EDIT: Ist nun in der Wissenssammlung: http://php-de.github.io/jumpto/hash-etc/#beispiel
                              Debugging: Finde DEINE Fehler selbst! | Gegen Probleme beim E-Mail-Versand | Sicheres Passwort-Hashing | Includes niemals ohne __DIR__
                              PHP.de Wissenssammlung | Kein Support per PN

                              Kommentar

                              Lädt...
                              X