it-swarm-eu.dev

Come si cripta e decifri a PHP Stringa?

Ciò che voglio dire è:

Original String + Salt or Key --> Encrypted String
Encrypted String + Salt or Key --> Decrypted (Original String)

Forse qualcosa come:

"hello world!" + "ABCD1234" --> Encrypt --> "2a2ffa8f13220befbe30819047e23b2c" (may be, for e.g)
"2a2ffa8f13220befbe30819047e23b2c" --> Decrypt with "ABCD1234" --> "hello world!"
  • In PHP, come puoi farlo?

Tentativo di utilizzareCrypt_Blowfish, ma non ha funzionato per me.

192
夏期劇場

Cosa non fare

ATTENZIONE:
Questa risposta usa ECB . La BCE non è una modalità di crittografia, è solo un elemento fondamentale. L'uso di ECB come dimostrato in questa risposta non crittografa in realtà la stringa in modo sicuro. Non usare la BCE nel tuo codice. Vedi La risposta di Scott per una buona soluzione.

L'ho preso su me stesso. In realtà ho trovato qualche risposta su google e ho appena modificato qualcosa. Il risultato è completamente insicuro tuttavia.

<?php
define("ENCRYPTION_KEY", "[email protected]#$%^&*");
$string = "This is the original data string!";

echo $encrypted = encrypt($string, ENCRYPTION_KEY);
echo "<br />";
echo $decrypted = decrypt($encrypted, ENCRYPTION_KEY);

/**
 * Returns an encrypted & utf8-encoded
 */
function encrypt($pure_string, $encryption_key) {
    $iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);
    $iv = mcrypt_create_iv($iv_size, MCRYPT_Rand);
    $encrypted_string = mcrypt_encrypt(MCRYPT_BLOWFISH, $encryption_key, utf8_encode($pure_string), MCRYPT_MODE_ECB, $iv);
    return $encrypted_string;
}

/**
 * Returns decrypted original string
 */
function decrypt($encrypted_string, $encryption_key) {
    $iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);
    $iv = mcrypt_create_iv($iv_size, MCRYPT_Rand);
    $decrypted_string = mcrypt_decrypt(MCRYPT_BLOWFISH, $encryption_key, $encrypted_string, MCRYPT_MODE_ECB, $iv);
    return $decrypted_string;
}
?>
44
夏期劇場

Prima di fare qualsiasi cosa, cerca di capire la differenza tra crittografia e autenticazione , e perché probabilmente vuoi autenticazione autenticata piuttosto che solo crittografia.

Per implementare la crittografia autenticata, si desidera crittografare quindi MAC. L'ordine di crittografia e autenticazione è molto importante! Una delle risposte esistenti a questa domanda ha commesso questo errore, così come molte librerie di crittografia scritte in PHP.

Dovresti evitare di implementare la tua crittografia , e invece usare una libreria sicura scritta da e revisionata da esperti di crittografia.

Aggiornamento: PHP 7.2 ora fornisce libsodium! Per maggiore sicurezza, aggiorna i tuoi sistemi per usare PHP 7.2 o successivo e segui solo il consiglio di libsodium in questa risposta.

usa libsodium se hai accesso PECL (o sodium_compat se vuoi libsodium senza PECL), altrimenti ...
Usa defuse/php-encryption ; non eseguire il rollover della tua crittografia!

Entrambe le librerie collegate sopra sopra rendono semplice e indolore implementare la crittografia autenticata nelle proprie librerie.

Se vuoi ancora scrivere e distribuire la tua libreria di crittografia, contro la saggezza convenzionale di ogni esperto di crittografia su Internet, questi sono i passi che dovresti fare.

Crittografia:

  1. Cifra usando AES in modalità CTR. Puoi anche utilizzare GCM (che elimina la necessità di un MAC separato). Inoltre, ChaCha20 e Salsa20 (forniti da libsodium ) sono codici di flusso e non richiedono modalità speciali.
  2. A meno che tu non abbia scelto GCM sopra, devi autenticare il testo cifrato con HMAC-SHA-256 (o, per i codici di flusso, Poly1305 - la maggior parte delle API libsodium lo fa per te). Il MAC dovrebbe coprire la IV e il testo cifrato!

Decrittazione:

  1. A meno che non si utilizzi Poly1305 o GCM, ricalcolare il MAC del testo cifrato e confrontarlo con il MAC inviato usando hash_equals() . Se fallisce, abortire.
  2. Decrittografare il messaggio.

Altre considerazioni sulla progettazione:

  1. Non comprimere nulla mai. Il testo cifrato non è comprimibile; comprimere il testo in chiaro prima della crittografia può portare a perdite di informazioni (ad esempio CRIME e BREACH su TLS).
  2. Assicurati di utilizzare mb_strlen() e mb_substr(), utilizzando la modalità di set di caratteri '8bit' per evitare problemi mbstring.func_overload.
  3. Gli IV dovrebbero essere generati usando un CSPRNG ; Se stai usando mcrypt_create_iv(), NON USARE MCRYPT_Rand!
  4. A meno che tu non stia utilizzando un costrutto di AEAD, SEMPRE crittografare quindi MAC!
  5. bin2hex(), base64_encode(), ecc. possono far trapelare informazioni sulle tue chiavi di crittografia tramite il timing della cache. Evitali se possibile.

Anche se segui il consiglio dato qui, molto può andare storto con la crittografia. Chiedi sempre a un esperto di crittografia di rivedere la tua implementazione. Se non sei abbastanza fortunato da essere amico personale di uno studente di crittografia presso la tua università locale, puoi sempre provare Cryptography Stack Exchange forum per un consiglio.

Se hai bisogno di un'analisi professionale della tua implementazione, puoi sempre assumere un gruppo di consulenti di sicurezza stimabile per rivedere il tuo PHP cryptography code (divulgazione: il mio datore di lavoro).

Importante: quando non usare la crittografia

Non encrypt passwords. Vuoi invece hash loro, usando uno di questi algoritmi di hashing delle password:

Non utilizzare mai una funzione hash di uso generico (MD5, SHA256) per l'archiviazione delle password.

Non crittografare i parametri URL . È lo strumento sbagliato per il lavoro.

Esempio di crittografia di stringa PHP con Libsodium

Se stai su PHP <7.2 o altrimenti non hai installato libsodium, puoi usare sodium_compat per ottenere lo stesso risultato (anche se più lento).

<?php
declare(strict_types=1);

/**
 * Encrypt a message
 * 
 * @param string $message - message to encrypt
 * @param string $key - encryption key
 * @return string
 * @throws RangeException
 */
function safeEncrypt(string $message, string $key): string
{
    if (mb_strlen($key, '8bit') !== SODIUM_CRYPTO_SECRETBOX_KEYBYTES) {
        throw new RangeException('Key is not the correct size (must be 32 bytes).');
    }
    $nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);

    $cipher = base64_encode(
        $nonce.
        sodium_crypto_secretbox(
            $message,
            $nonce,
            $key
        )
    );
    sodium_memzero($message);
    sodium_memzero($key);
    return $cipher;
}

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

    $plain = sodium_crypto_secretbox_open(
        $ciphertext,
        $nonce,
        $key
    );
    if (!is_string($plain)) {
        throw new Exception('Invalid MAC');
    }
    sodium_memzero($ciphertext);
    sodium_memzero($key);
    return $plain;
}

Quindi per testarlo:

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

// Do this once then store it somehow:
$key = random_bytes(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);

Halite - Libsodium reso più facile

Uno dei progetti su cui ho lavorato è una libreria di crittografia chiamata Halite , che mira a rendere la libsodium più facile e più intuitiva.

<?php
use \ParagonIE\Halite\KeyFactory;
use \ParagonIE\Halite\Symmetric\Crypto as SymmetricCrypto;

// Generate a new random symmetric-key encryption key. You're going to want to store this:
$key = new KeyFactory::generateEncryptionKey();
// To save your encryption key:
KeyFactory::save($key, '/path/to/secret.key');
// To load it again:
$loadedkey = KeyFactory::loadEncryptionKey('/path/to/secret.key');

$message = 'We are all living in a yellow submarine';
$ciphertext = SymmetricCrypto::encrypt($message, $key);
$plaintext = SymmetricCrypto::decrypt($ciphertext, $key);

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

Tutta la crittografia sottostante è gestita da libsodium.

Esempio con defuse/php-encryption

<?php
/**
 * This requires https://github.com/defuse/php-encryption
 * php composer.phar require defuse/php-encryption
 */

use Defuse\Crypto\Crypto;
use Defuse\Crypto\Key;

require "vendor/autoload.php";

// Do this once then store it somehow:
$key = Key::createNewRandomKey();

$message = 'We are all living in a yellow submarine';

$ciphertext = Crypto::encrypt($message, $key);
$plaintext = Crypto::decrypt($ciphertext, $key);

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

Nota: Crypto::encrypt() restituisce l'output con codifica esadecimale.

Gestione delle chiavi di crittografia

Se sei tentato di usare una "password", fermati subito. Hai bisogno di una chiave di crittografia casuale a 128 bit, non di una password umana memorabile.

È possibile memorizzare una chiave di crittografia per l'uso a lungo termine in questo modo:

$storeMe = bin2hex($key);

E, su richiesta, puoi recuperarlo in questo modo:

$key = hex2bin($storeMe);

Io fortemente raccomando di archiviare una chiave generata a caso per un uso a lungo termine invece di qualsiasi tipo di password come chiave (o per derivare la chiave).

Se stai usando la libreria di Defuse:

"Ma io veramente voglio usare una password."

Questa è una cattiva idea, ma va bene, ecco come farlo in modo sicuro.

Innanzitutto, genera una chiave casuale e la memorizza in una costante.

/**
 * Replace this with your own salt! 
 * Use bin2hex() then add \x before every 2 hex characters, like so:
 */
define('MY_PBKDF2_SALT', "\x2d\xb7\x68\x1a\x28\x15\xbe\x06\x33\xa0\x7e\x0e\x8f\x79\xd5\xdf");

Nota che stai aggiungendo lavoro extra e potresti usare questa costante come chiave e risparmiarti un sacco di dolore!

Quindi utilizzare PBKDF2 (come tale) per ricavare una chiave di crittografia appropriata dalla propria password anziché crittografare direttamente con la password.

/**
 * Get an AES key from a static password and a secret salt
 * 
 * @param string $password Your weak password here
 * @param int $keysize Number of bytes in encryption key
 */
function getKeyFromPassword($password, $keysize = 16)
{
    return hash_pbkdf2(
        'sha256',
        $password,
        MY_PBKDF2_SALT,
        100000, // Number of iterations
        $keysize,
        true
    );
}

Non usare solo una password di 16 caratteri. La tua chiave di crittografia sarà comicamente rotta.

362

Sono in ritardo per la festa, ma cercando il modo corretto per farlo mi sono imbattuto in questa pagina è stata una delle migliori ricerche di Google, quindi mi piacerebbe condividere la mia opinione sul problema, che considero essere aggiornato al momento della stesura di questo post (inizio del 2017). Da PHP 7.1.0 il mcrypt_decrypt e mcrypt_encrypt saranno deprecati, quindi la creazione di codice a prova di futuro dovrebbe usare openssl_encrypt e openssl_decrypt

Puoi fare qualcosa come:

$string_to_encrypt="Test";
$password="password";
$encrypted_string=openssl_encrypt($string_to_encrypt,"AES-128-ECB",$password);
$decrypted_string=openssl_decrypt($encrypted_string,"AES-128-ECB",$password);

Importante : utilizza modalità ECB , che non è sicuro. Se vuoi una soluzione semplice senza seguire un corso accelerato in ingegneria crittografica, non scrivere da solo, solo usa una libreria .

È possibile utilizzare anche altri metodi di cippatore, a seconda delle esigenze di sicurezza. Per scoprire i metodi di cippatura disponibili, vedi la funzione openssl_get_cipher_methods .

46
Emil Borconi

Per Laravel framework

Se si utilizza Laravel framework, è più semplice crittografarlo e decrittografarlo con le funzioni interne.

$string = 'Some text to be encrypted';
$encrypted = \Illuminate\Support\Facades\Crypt::encrypt($string);
$decrypted_string = \Illuminate\Support\Facades\Crypt::decrypt($encrypted);

var_dump($string);
var_dump($encrypted);
var_dump($decrypted_string);

Nota: assicurati di impostare una stringa casuale di 16, 24 o 32 caratteri nell'opzione chiave del file config/app.php. In caso contrario, i valori crittografati non saranno sicuri.

12
Somnath Muluk

Nota storica: Questo è stato scritto al momento di PHP4. Questo è ciò che chiamiamo "codice legacy" ora.

Ho lasciato questa risposta per scopi storici, ma alcuni metodi sono ora deprecati, DES il metodo di crittografia non è una pratica consigliata, ecc.

Non ho aggiornato questo codice per due motivi: 1) Non lavoro più con i metodi di crittografia a mano in PHP, e 2) questo codice serve ancora allo scopo per cui è stato concepito: dimostrare il concetto minimo e semplicistico di come la crittografia può funzionare in PHP.

Se trovi una sorta di fonte similistica di "crittografia PHP for dummies" che può far iniziare le persone in 10-20 righe di codice o meno, fammi sapere nei commenti.

Oltre a questo, ti invitiamo a goderti questo episodio classico della risposta di crittografia minimalista PHP4 dei primi tempi.


Idealmente hai - o puoi ottenere - l'accesso alla libreria mcrypt PHP, poiché è sicuramente una delle attività più popolari e molto utili. Ecco una serie di diversi tipi di crittografia e alcuni esempi di codice: Tecniche di crittografia in PHP

//Listing 3: Encrypting Data Using the mcrypt_ecb Function 

<?php 
echo("<h3> Symmetric Encryption </h3>"); 
$key_value = "KEYVALUE"; 
$plain_text = "PLAINTEXT"; 
$encrypted_text = mcrypt_ecb(MCRYPT_DES, $key_value, $plain_text, MCRYPT_ENCRYPT); 
echo ("<p><b> Text after encryption : </b>"); 
echo ( $encrypted_text ); 
$decrypted_text = mcrypt_ecb(MCRYPT_DES, $key_value, $encrypted_text, MCRYPT_DECRYPT); 
echo ("<p><b> Text after decryption : </b>"); 
echo ( $decrypted_text ); 
?> 

Alcuni avvertimenti:

1) Non utilizzare mai la crittografia reversibile o "simmetrica" ​​quando si eseguirà un hash unidirezionale.

2) Se i dati sono veramente sensibili, come i numeri di carta di credito o di sicurezza sociale, fermati; avete bisogno di più di una semplice porzione di codice, ma avete bisogno di una libreria crittografica progettata per questo scopo e una quantità significativa di tempo per ricercare i metodi necessari. Inoltre, la crittografia software è probabilmente <10% della sicurezza dei dati sensibili. È come ricablare una centrale nucleare: accetta che il compito sia pericoloso, difficile e al di là delle tue conoscenze, se è così. Le sanzioni finanziarie possono essere immense, quindi è meglio usare un servizio e fornire loro la responsabilità.

3) Qualsiasi tipo di crittografia facilmente implementabile, come elencato qui, può ragionevolmente proteggere informazioni leggermente importanti che si desidera mantenere da occhi indiscreti o limitare l'esposizione in caso di perdita accidentale/intenzionale. Ma visto che la chiave è memorizzata in chiaro sul server web, se possono ottenere i dati possono ottenere la chiave di decodifica.

Sia come sia, divertiti :)

6
BrianH

Se non vuoi usare la libreria (che dovresti), usa qualcosa di simile a questo (PHP 7):

function sign($message, $key) {
    return hash_hmac('sha256', $message, $key) . $message;
}

function verify($bundle, $key) {
    return hash_equals(
      hash_hmac('sha256', mb_substr($bundle, 64, null, '8bit'), $key),
      mb_substr($bundle, 0, 64, '8bit')
    );
}

function getKey($password, $keysize = 16) {
    return hash_pbkdf2('sha256',$password,'some_token',100000,$keysize,true);
}

function encrypt($message, $password) {
    $iv = random_bytes(16);
    $key = getKey($password);
    $result = sign(openssl_encrypt($message,'aes-256-ctr',$key,OPENSSL_RAW_DATA,$iv), $key);
    return bin2hex($iv).bin2hex($result);
}

function decrypt($hash, $password) {
    $iv = hex2bin(substr($hash, 0, 32));
    $data = hex2bin(substr($hash, 32));
    $key = getKey($password);
    if (!verify($data, $key)) {
      return null;
    }
    return openssl_decrypt(mb_substr($data, 64, null, '8bit'),'aes-256-ctr',$key,OPENSSL_RAW_DATA,$iv);
}

$string_to_encrypt='John Smith';
$password='password';
$encrypted_string=encrypt($string_to_encrypt, $password);
$decrypted_string=decrypt($encrypted_string, $password);
3
Ascon