PHP OpenSSL – Signer des données

Ici je vais essayer de vous expliquer assez facilement comment signer des données en php via openssl pour être sûr qu’elle n’ont pas été altérées durant la transmission.

Tout d’abord on va commencer par se créer une clé publique et une clé privée via la ligne de commande (c’est la méthode la plus simple, pas la seule possible!)

Source des commandes : devco.net

Génération d’une clé privée :

openssl genrsa -out private.pem 1024

  • openssl : no comment ;-)
  • genrsa : génération de clé RSA
  • -out private.pem : écriture dans le fichier private.pem
  • 1024 : la taille de la clé privée (plus longue = meilleure encryptage et donc sécurité)

On extrait la clé publique de la clé privée private.pem générée au préalable

openssl rsa -in private.pem -out public.pem -outform PEM -pubout

  • openssl : idem ci dessus
  • rsa : manipulation de clé RSA
  • -in private.pem : lecture des infos dans la clé privée
  • -out public.pem : écriture dans public.pem
  • -outform PEM : les données seront formatées selon PEM (comme demandé par la fonction openssl_pkey_get_public)
  • -pubout : on sort la clé publique plutôt que la privée

Ah oui j’oubliais pour ceux qui ne connaissent/comprennent pas le concept de clé publique/privée l’article sur la cryptographie asymétrique de wikipédia devrait vous aider.
Si vous comprenez pas tout du premier coup, ne vous inquiétez pas il m’a fallut quelques mois pour vraiment bien comprendre comment cela pouvait fonctionner.

Je fini sur le code source de mon script php abondamment commenté.

 

	//Les deux fichiers de signatures
	define ('KEY_PREFIX', 'file://');
	define ('KEY_PRIVATE', KEY_PREFIX.'private.pem');
	define ('KEY_PUBLIC', KEY_PREFIX.'public.pem');

	$data = "bouh j'vais vous mangeeeeer sales bêtes"; //Les données à signer
	$signature;	//L'endroit où stocker la signature générée

	//On récupère la clé privée et la publique de leur fichiers respectifs
	$privatekey = openssl_get_privatekey(KEY_PRIVATE);
	$publickey = openssl_get_publickey(KEY_PUBLIC);

	//On signe les données en utilisant la clé privée
	$bool = openssl_sign($data, $signature, $privatekey);

	//On permet d'afficher la signature en base64
	//echo "--------------------------\n";
	//echo base64_encode($signature)."---";
	//echo urlencode(base64_encode($signature));

	/*La signature est quand même un peu longue à placer dans une URL
	 * - soit trouver un moyen de la raccourcir
	 * - soit faire en sorte que le base64 passe dans l'url sans problème
	 * (=, + etc potentiellement problèmatiques)*/
	echo "\nLongueur de la signature generée au format base64\n";
	echo strlen(base64_encode($signature))."---";
	echo strlen(urlencode(base64_encode($signature)));
	echo "\n--------------------------\n";

	/*//Tentative de compression 1 : échoué, la string compressée prend plus de place
	$gzSignature = gzcompress($signature, 9);
	echo "\nVersion compressée\n";
	echo strlen(base64_encode($gzSignature))."---";
	echo strlen(urlencode(base64_encode($gzSignature)));
	echo "\n--------------------------\n";
	*/

	/* On vérifie la correspondance entre la signature et les données "reçues"
	 * en utilisant la clé publique
	 * Retourne 1 si la signature est correcte,
	 * 0 si elle est incorrecte
	 * et -1 si une erreur survient.*/
	$intRet = openssl_verify($data,$signature,$publickey);
	if ($intRet == 1)
		echo "Données et signature OK\n";
	if ($intRet == 0)
		echo "Données et signature KO\n";
	if ($intRet == -1)
		echo "Erreur survenue lors de la vérification\n";

	//On vire les clés de la mémoire
	openssl_free_key($privatekey);
	openssl_free_key($publickey);

Comme vous pouvez le voir j’ai tenté de réduire la string de signature produite, mais ceci s’est soldé pas un échec, la string compressée étant plus longue que la non compressée.
Néanmoins la signature devrait pouvoir passer dans une URL (Get) (n’oubliez pas d’urlencode la string base64 avant) sachant que la longueur de la signature ne dépassait en général pas les 200 caractères et que cet article datant de 2006 parlait à l’époque d’un minimum de +- 2000 caractères.  Ça ne peut que s’être amélioré depuis ;-)

Posted in Web by El Gnap at April 19th, 2011.
Tags: , , , , , , ,

2 Responses to “PHP OpenSSL – Signer des données”

  1. shinryo says:

    Salut

    J’ai à peu près compris votre script mais néanmoins une chose m’échappe, donnez-vous une valeur aux clés privé et publique si oui à quel endroit du script si non peut-on donner une valeur à ces clés et comment ?

    Merci d’avance

  2. El Gnap says:

    Salut,
    D’abord désolé pour avoir pris tant de temps à valider ton message. Je suis en plein déménagement de serveurs.
    Qu’entends tu par donner une valeur ? Si tu parles du code de cryptage utilisé il est généré au moment où tu crées la clé privée (la publique étant “déduite” (ou plutôt calculée) depuis cette dernière).
    Non tu ne peux pas spécifier manuellement le “mot de passe” utilisé, au mieux le nombre de bits dont il sera constitué.