it-swarm-eu.dev

PHP Criptare/decifrare AES

Ho trovato un esempio per le stringhe en/decoding in PHP. All'inizio sembra molto buono ma non funzionerà :-(

Qualcuno sa quale sia il problema?

$Pass = "Passwort";
$Clear = "Klartext";

$crypted = fnEncrypt($Clear, $Pass);
echo "Encrypted: ".$crypted."</br>";

$newClear = fnDecrypt($crypted, $Pass);
echo "Decrypted: ".$newClear."</br>";

function fnEncrypt($sValue, $sSecretKey) {
    return trim(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $sSecretKey, $sDecrypted, MCRYPT_MODE_ECB, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_Rand))));
}

function fnDecrypt($sValue, $sSecretKey) {
    return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $sSecretKey, base64_decode($sEncrypted), MCRYPT_MODE_ECB, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_Rand)));
}

Il risultato è:

Crittografato: boKRNTYYNp7AiOvY1CidqsAn9wX4ufz/D9XrpjAOPk8=

Decrittografato: —‚(ÑÁ ^ yË~F'¸®Ó–í œð2Á_B‰Â—

40
Andreas Prang

$sDecrypted e $sEncrypted non sono stati definiti nel tuo codice. Guarda una soluzione che funziona (ma non è sicuro!):


FERMARE!

Questo esempio è insicuro! Non usarlo!


$Pass = "Passwort";
$Clear = "Klartext";        

$crypted = fnEncrypt($Clear, $Pass);
echo "Encrypred: ".$crypted."</br>";

$newClear = fnDecrypt($crypted, $Pass);
echo "Decrypred: ".$newClear."</br>";        

function fnEncrypt($sValue, $sSecretKey)
{
    return rtrim(
        base64_encode(
            mcrypt_encrypt(
                MCRYPT_RIJNDAEL_256,
                $sSecretKey, $sValue, 
                MCRYPT_MODE_ECB, 
                mcrypt_create_iv(
                    mcrypt_get_iv_size(
                        MCRYPT_RIJNDAEL_256, 
                        MCRYPT_MODE_ECB
                    ), 
                    MCRYPT_Rand)
                )
            ), "\0"
        );
}

function fnDecrypt($sValue, $sSecretKey)
{
    return rtrim(
        mcrypt_decrypt(
            MCRYPT_RIJNDAEL_256, 
            $sSecretKey, 
            base64_decode($sValue), 
            MCRYPT_MODE_ECB,
            mcrypt_create_iv(
                mcrypt_get_iv_size(
                    MCRYPT_RIJNDAEL_256,
                    MCRYPT_MODE_ECB
                ), 
                MCRYPT_Rand
            )
        ), "\0"
    );
}

Ma ci sono altri problemi in questo codice che lo rendono insicuro, in particolare l'uso di ECB (che non è una modalità encryption, solo un elemento fondamentale in cima al quale possono essere definite le modalità di crittografia). Vedi La risposta di Fab Sa per una rapida soluzione dei problemi peggiori e la risposta di Scott per come farlo correttamente.

52
zz1433

Utilizzare una libreria di crittografia esistente sicura PHP

In genere è una cattiva idea scrivere la tua crittografia a meno che tu non abbia esperienza di violazione delle implementazioni di crittografia di altre persone.

Nessuno degli esempi qui autentica il ciphertext , che li rende vulnerabili agli attacchi di riscrittura dei bit.

Se è possibile installare estensioni PECL, libsodium è ancora meglio

<?php
// PECL libsodium 0.2.1 and newer

/**
 * Encrypt a message
 * 
 * @param string $message - message to encrypt
 * @param string $key - encryption key
 * @return string
 */
function safeEncrypt($message, $key)
{
    $nonce = \Sodium\randombytes_buf(
        \Sodium\CRYPTO_SECRETBOX_NONCEBYTES
    );

    return base64_encode(
        $nonce.
        \Sodium\crypto_secretbox(
            $message,
            $nonce,
            $key
        )
    );
}

/**
 * Decrypt a message
 * 
 * @param string $encrypted - message encrypted with safeEncrypt()
 * @param string $key - encryption key
 * @return string
 */
function safeDecrypt($encrypted, $key)
{   
    $decoded = base64_decode($encrypted);
    $nonce = mb_substr($decoded, 0, \Sodium\CRYPTO_SECRETBOX_NONCEBYTES, '8bit');
    $ciphertext = mb_substr($decoded, \Sodium\CRYPTO_SECRETBOX_NONCEBYTES, null, '8bit');

    return \Sodium\crypto_secretbox_open(
        $ciphertext,
        $nonce,
        $key
    );
}    

Quindi per testarlo:

<?php
// This refers to the previous code block.
require "safeCrypto.php"; 

// Do this once then store it somehow:
$key = \Sodium\randombytes_buf(\Sodium\CRYPTO_SECRETBOX_KEYBYTES);
$message = 'We are all living in a yellow submarine';

$ciphertext = safeEncrypt($message, $key);
$plaintext = safeDecrypt($ciphertext, $key);

var_dump($ciphertext);
var_dump($plaintext);

Può essere utilizzato in qualsiasi situazione in cui si trasmettano dati al client (ad esempio, cookie crittografati per sessioni senza memoria lato server, parametri URL crittografati, ecc.) Con un grado ragionevolmente alto di certezza che l'utente finale non può decifrare o manomettere in modo affidabile con esso.

Poiché libsodium è multipiattaforma , questo rende anche più facile comunicare con PHP da, ad es. Applet Java o app mobili native.


Nota: se hai specificamente bisogno di aggiungere cookie crittografati basati su libsodium alla tua app, il mio datore di lavoro Paragon Initiative Enterprises sta sviluppando una libreria chiamata Halite che fa tutto questo per te.

68

Per informazioni MCRYPT_MODE_ECB non usa la IV (vettore di inizializzazione). La modalità ECB divide il tuo messaggio in blocchi e ogni blocco viene crittografato separatamente. Davvero non lo consiglio.

La modalità CBC usa la IV per rendere unico ogni messaggio. CBC è raccomandato e dovrebbe essere usato al posto della BCE.

Esempio :

<?php
$password = "myPassword_!";
$messageClear = "Secret message";

// 32 byte binary blob
$aes256Key = hash("SHA256", $password, true);

// for good entropy (for MCRYPT_Rand)
srand((double) microtime() * 1000000);
// generate random iv
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC), MCRYPT_Rand);


$crypted = fnEncrypt($messageClear, $aes256Key);

$newClear = fnDecrypt($crypted, $aes256Key);

echo
"IV:        <code>".$iv."</code><br/>".
"Encrypred: <code>".$crypted."</code><br/>".
"Decrypred: <code>".$newClear."</code><br/>";

function fnEncrypt($sValue, $sSecretKey) {
    global $iv;
    return rtrim(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $sSecretKey, $sValue, MCRYPT_MODE_CBC, $iv)), "\0\3");
}

function fnDecrypt($sValue, $sSecretKey) {
    global $iv;
    return rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $sSecretKey, base64_decode($sValue), MCRYPT_MODE_CBC, $iv), "\0\3");
}

Devi immagazzinare la IV per decodificare ogni messaggio (IV sono not secret). Ogni messaggio è unico perché ogni messaggio ha un IV unico.

25
Fabien Sa

Se tu non vuoi usare una dipendenza pesante per qualcosa di risolvibile in 15 linee di codice, usa le funzioni built-in OpenSSL . La maggior parte delle installazioni PHP vengono fornite con OpenSSL, che fornisce una crittografia AES veloce, compatibile e sicura in PHP. Bene, è sicuro finché segui le migliori pratiche.

Il seguente codice:

  • utilizza AES256 in modalità CBC
  • è compatibile con altre implementazioni AES, ma non con mcrypt , poiché mcrypt utilizza PKCS # 5 invece di PKCS # 7.
  • genera una chiave dalla password fornita utilizzando SHA256
  • genera un hash hmac dei dati crittografati per il controllo dell'integrità
  • genera un IV casuale per ogni messaggio
  • antepone IV (16 byte) e l'hash (32 byte) al testo cifrato
  • dovrebbe essere abbastanza sicuro

IV è un'informazione pubblica e deve essere casuale per ogni messaggio. L'hash garantisce che i dati non siano stati manomessi.

function encrypt($plaintext, $password) {
    $method = "AES-256-CBC";
    $key = hash('sha256', $password, true);
    $iv = openssl_random_pseudo_bytes(16);

    $ciphertext = openssl_encrypt($plaintext, $method, $key, OPENSSL_RAW_DATA, $iv);
    $hash = hash_hmac('sha256', $ciphertext, $key, true);

    return $iv . $hash . $ciphertext;
}

function decrypt($ivHashCiphertext, $password) {
    $method = "AES-256-CBC";
    $iv = substr($ivHashCiphertext, 0, 16);
    $hash = substr($ivHashCiphertext, 16, 32);
    $ciphertext = substr($ivHashCiphertext, 48);
    $key = hash('sha256', $password, true);

    if (hash_hmac('sha256', $ciphertext, $key, true) !== $hash) return null;

    return openssl_decrypt($ciphertext, $method, $key, OPENSSL_RAW_DATA, $iv);
}

Uso:

$encrypted = encrypt('Plaintext string.', 'password'); // this yields a binary string

echo decrypt($encrypted, 'password');
// decrypt($encrypted, 'wrong password') === null
20
blade

Poche cose importanti da notare con la crittografia AES: 

  1. Non utilizzare mai il testo normale come chiave di crittografia. Cancella sempre la chiave di testo in chiaro e utilizzala per la crittografia. 
  2. Usa sempre Random IV (vettore di inizializzazione) per la crittografia e la decrittografia. True randomization è importante. 
  3. Come detto sopra, non usare ecb mode, usa invece CBC.
2
Navneet Kumar

Se stai utilizzando MCRYPT_RIJNDAEL_128, prova rtrim($output, "\0\3"). Se la lunghezza della stringa è inferiore a 16, la funzione decrypt restituirà una stringa con lunghezza di 16 caratteri, aggiungendo 03 alla fine.

Puoi facilmente controllare questo, ad es. provando:

$string = "TheString";
$decrypted_string = decrypt_function($stirng, $key);

echo bin2hex($decrypted_string)."=".bin2hex("TheString");
1
Kamen

Se si utilizza PHP> = 7.2, considerare l'utilizzo dell'estensione del core di sodio incorporata per la crittografia. 

Trova maggiori informazioni qui - http://php.net/manual/en/intro.sodium.php.

0
M_R_K