Crittografia a chiave pubblica con PHP

La crittografia a chiave pubblica prevede l'utilizzo di due chiavi una pubblica e l'altra privata.

Pubblicato da ,
Ultima modifica

Il tipico esempio di crittografia a chiave pubblica e lo scambio di messaggi tra due soggetti Alice e Bob, Alice per inviare un messaggio a Bob utilizza la chiave pubblica di Bob per cifrare il messaggio, mentre Bob per decifrare il messaggio di Alice utilizza la sua chiave privata, e viceversa Bob per inviare un messaggio ad Alice utilizza la chiave pubblica di Alice per cifrare il messaggio, mentre Alice per decifrare il messaggio di Bob utilizza la sua chiave privata.

Per generare una coppia di chiavi si utilizza l'estensione OpenSSL di PHP

Codice PHP

<?php
$config = array(
    "private_key_bits" => 4096,
    "private_key_type" => OPENSSL_KEYTYPE_RSA
);

$keys = openssl_pkey_new($config);

$passphrase = 'xyz';
openssl_pkey_export_to_file($keys, 'private.pem', $passphrase);

$details = openssl_pkey_get_details($keys);
$publickey = $details['key'];
file_put_contents('public.key', $publickey);

entrambe le chiavi hanno una lunghezza di 4096 bit ed è utilizzato l'algoritmo di cifratura RSA ($config), entrambe le chiavi sono memorizzate nella variabile $keys, in particolare è usata una 'passphrase' per cifrare la chiave privata, la quale viene memorizzata in un file private.pem, la chiave pubblica è memorizzata in un file public.key.

Adesso che abbiamo generato la coppia di chiavi pubblica e privata possiamo procedere a criptare e decriptare un messaggio, in particolare usiamo le due funzioni encrypt e decrypt disponibili nella documentazione di PHP al seguente link

php.net/manual/en/function.openssl-encrypt.php#126296

Codice PHP

<?php

function encrypt(string $plaintext, string $key, string $iv = '', string $aad = ''):
    string
    {
        ...... .
    }

    function decrypt(string $ciphertext, string $key, string $iv = '', string $aad = ''):
        string
        {
            ...... .
        }

        $msg = "Testo del messaggio...";
        $key = random_bytes(32);
        $iv = random_bytes(16);
        
        /** public key */
        $publickey = file_get_contents('public.key');

        /** private key */
        $passphrase = "xyz";
        $privatekey = openssl_pkey_get_private('file://private.pem', $passphrase);

        openssl_public_encrypt($key, $encryptedKey, $publickey, OPENSSL_PKCS1_OAEP_PADDING);

        $ciphertext = encrypt($msg, $key, $iv);
        printf($ciphertext."\n");

        $result = openssl_private_decrypt($encryptedKey, $decryptedKey, $privatekey, OPENSSL_PKCS1_OAEP_PADDING);

        if (false !== $result)
        {
            $result = decrypt($ciphertext, $key, $iv);
            printf($result."\n");
        }
        else
        {

            while ($msg = openssl_error_string())
            {
                printf("%s\n", $msg);
            }
        }
        

$key e $iv sono rispettivamente la chiave segreta (stringa di 32 bit) e il vettore di inizializzazione (stringa di 16 bit), $publickey è la chiave pubblica che abbiamo generato in precedenza, $passphrase è la passphrase che abbiamo usato per cifrare la chiave privata, $privatekey è la chiave privata che otteniamo tramite la funzione openssl_pkey_get_private, eseguendo il codice otterremo un risultato simile a questo

rtEjTs+bCo2FMQJyWuxCzWujyCPvhJm0lHwxzACyG6P0a+WVXGg=
Testo del messaggio...

la prima stringa è il messaggio criptato, mentra la seconda stringa è il messaggio decriptato e quindi l'originale.