Je voudrais chiffrer en JavaScript, déchiffrer en PHP, en utilisant la cryptographie à clé publique. J'ai essayé de trouver des bibliothèques qui peuvent accomplir cela, mais j'ai des problèmes.
Je regarde actuellement openpgpjs , mais j'ai besoin de support dans tous les navigateurs, et même la page de test a des erreurs sur le seul navigateur répertorié comme supporté (Google Chrome).
Notes sur l'objectif final:
La connexion TCP est déjà protégée par SSL. Le but principal de cette couche de protection est de se défendre contre la journalisation intentionnelle ou non du serveur Web, les vidages sur incident, etc.
Du côté PHP côté, une clé privée temporaire sera générée (elle expirera peu de temps après). L'appelant (en Javascript) est responsable de demander une nouvelle clé publique à son expiration. La raison de l'expiration de la clé privée est d'empêcher le déchiffrement des données chiffrées enregistrées, au cas où le serveur qui stocke la clé privée serait ultérieurement compromis.
Scénario compromis des serveurs: quelqu'un met la main sur des sauvegardes pour toutes les machines sauf le serveur de base de données (et ne peut pas accéder à la base de données en raison du pare-feu, même s'il découvre l'utilisateur et le mot de passe). Étant donné que la clé privée qui a chiffré les données enregistrées n'existe plus, l'attaquant ne peut rien faire.
J'ai utilisé quelque chose de similaire pour ma page de connexion; il crypte les identifiants de connexion en utilisant les informations de clé publique données (N, e) qui peuvent être décryptées en PHP.
Il utilise les fichiers suivants qui font partie de JSBN
:
jsbn.js
- pour travailler avec de grands entiersrsa.js
- pour le chiffrement RSA uniquement (utilise jsbn.js)rng.js
- collecteur d'entropie de baseprng4.js
- Backend ARC4 RNGPour crypter les données:
$pk = '-----BEGIN RSA PRIVATE KEY-----
...
-----END RSA PRIVATE KEY-----';
$kh = openssl_pkey_get_private($pk);
$details = openssl_pkey_get_details($kh);
function to_hex($data)
{
return strtoupper(bin2hex($data));
}
?>
<script>
var rsa = new RSAKey();
rsa.setPublic('<?php echo to_hex($details['rsa']['n']) ?>', '<?php echo to_hex($details['rsa']['e']) ?>');
// encrypt using RSA
var data = rsa.encrypt('hello world');
</script>
Voici comment décoder les données envoyées:
$kh = openssl_pkey_get_private($pk);
$details = openssl_pkey_get_details($kh);
// convert data from hexadecimal notation
$data = pack('H*', $data);
if (openssl_private_decrypt($data, $r, $kh)) {
echo $r;
}
Découvrez node-rsa .
C'est un module node.js
Ce module permet d'accéder aux routines à clé publique RSA à partir d'OpenSSL. La prise en charge est limitée à RSAES-OAEP et au chiffrement avec une clé publique, au déchiffrement avec une clé privée.
Vous pouvez peut-être le porter pour l'exécuter dans le navigateur.
[~ # ~] mise à jour [~ # ~]
Bibliothèque côté client RSA pour javascript: (pidcrypt a été officiellement interrompu et le domaine du site Web a expiré - voir la réponse de @ jack qui contient les mêmes bibliothèques que pidcrypt contenue) . https://www.pidder.com/pidcrypt/?page=rsa
Composant côté serveur PHP: http://phpseclib.sourceforge.net/
Bonne chance!
Soyez prudent avec l'implémentation de RSA. En fait, vous ne devriez probablement pas utiliser du tout RSA. ( tilisez plutôt libsodium! )
Même si vous utilisez une bibliothèque (par exemple, l'extension OpenSSL de PHP directement ou, jusqu'à récemment, Zend\Crypt
), il y a encore beaucoup de choses qui peuvent mal tourner. En particulier:
Vous voudrez peut-être lire La cryptographie JavaScript considérée comme nuisible quelques fois avant de suivre cette voie. Mais cela dit ...
crypto_box_seal()
avec une clé publique pour crypter vos messages, côté client.\Sodium\crypto_box_seal_open()
avec la clé secrète correspondante pour la clé publique pour déchiffrer le message.Veuillez ne pas le faire . La cryptographie à courbe elliptique est plus rapide, plus simple et beaucoup plus facile à mettre en œuvre sans canaux latéraux. La plupart des bibliothèques le font déjà pour vous. (Libsodium!)
Très bien, suivez ces recommandations à la lettre et ne venez pas pleurer sur StackOverflow lorsque vous faites une erreur (comme SaltStack l'a fait ) qui rend votre cryptographie inutile.
Une option (qui n'est pas livrée avec une implémentation JavaScript complémentaire, et n'en demandez pas) qui vise à fournir un chiffrement RSA simple et facile est paragonie/easyrsa .
Mais, vraiment, si vous trouvez un cas d'utilisation valide pour la cryptographie à clé publique, vous voulez plutôt libsodium.
Exemple d'utilisation de RSA pour pidCrypt (js) et phpseclib (php).
Ne réutilisez pas la clé privée dans cet exemple de travail.
Cryptage pidCrypt
//From the pidCrypt example sandbox
function certParser(cert) {
var lines = cert.split('\n');
var read = false;
var b64 = false;
var end = false;
var flag = '';
var retObj = {
};
retObj.info = '';
retObj.salt = '';
retObj.iv;
retObj.b64 = '';
retObj.aes = false;
retObj.mode = '';
retObj.bits = 0;
for (var i = 0; i < lines.length; i++) {
flag = lines[i].substr(0, 9);
if (i == 1 && flag != 'Proc-Type' && flag.indexOf('M') == 0)//unencrypted cert?
b64 = true;
switch (flag) {
case '-----BEGI':
read = true;
break;
case 'Proc-Type':
if (read)retObj.info = lines[i];
break;
case 'DEK-Info:':
if (read) {
var tmp = lines[i].split(',');
var dek = tmp[0].split(': ');
var aes = dek[1].split('-');
retObj.aes = (aes[0] == 'AES') ? true : false;
retObj.mode = aes[2];
retObj.bits = parseInt(aes[1]);
retObj.salt = tmp[1].substr(0, 16);
retObj.iv = tmp[1];
}
break;
case '':
if (read)b64 = true;
break;
case '-----END ':
if (read) {
b64 = false;
read = false;
}
break;
default : if (read && b64)retObj.b64 += pidCryptUtil.stripLineFeeds(lines[i]);
}
}
return retObj;
}
var strCreditCardPublicKey="-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC\/tI7cw+gnUPK2LqWp50XboJ1i\njrLDn+4\/gPOe+pB5kz4VJX2KWwg9iYMG9UJ1M+AeN33qT7xt9ob2dxgtTh7Mug2S\nn1TLz4donuIzxCmW+SZdU1Y+WNDINds194hWsAVhMC1ClMQTfldUGzQnI5sXvZTF\nJWp\/9jheCNLDRIkAnQIDAQAB\n-----END PUBLIC KEY-----\n";
var objParams=certParser(strCreditCardPublicKey);
var binaryPrivateKey=pidCryptUtil.decodeBase64(objParams.b64);
var rsa=new pidCrypt.RSA();
var asn=pidCrypt.ASN1.decode(pidCryptUtil.toByteArray(key));
var tree=asn.toHexTree();
rsa.setPublicKeyFromASN(tree);
var strHexSensitiveDataEncrypted=rsa.encrypt("4111111111111111");
var strBase64SensitiveDataEncrypted=pidCryptUtil.fragment(pidCryptUtil.encodeBase64(pidCryptUtil.convertFromHex(strHexSensitiveDataEncrypted)), 64))
console.log(strBase64SensitiveDataEncrypted);
.
décryptage phpseclib
require_once("Crypt/RSA.php");
function decrypt($strBase64CipherText)
{
//CRYPT_RSA_MODE_INTERNAL is slow
//CRYPT_RSA_MODE_OPENSSL is fast, but requires openssl to be installed, configured and accessible.
define("CRYPT_RSA_MODE", CRYPT_RSA_MODE_INTERNAL);
$rsa=new Crypt_RSA();
//$strPrivateKey=file_get_contents("private.pem");
//This private key is for example purposes
//DO NOT REUSE
$strPrivateKey="-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQDBNHK7R2CCYGqljipbPoj3Pwyz4cF4bL5rsm1t8S30gbEbMnKn
1gpzteoPlKp7qp0TnsgKab13Fo1d+Yy8u3m7JUd/sBrUa9knY6dpreZ9VTNul8Bs
p2LNnAXOIA5xwT10PU4uoWOo1v/wn8eMeBS7QsDFOzIm+dptHYorB3DOUQIDAQAB
AoGBAKgwGyxy702v10b1omO55YuupEU3Yq+NopqoQeCyUnoGKIHvgaYfiwu9sdsM
ZPiwxnqc/7Eo6Zlw1XGYWu61GTrOC8MqJKswJvzZ0LrO3oEb8IYRaPxvuRn3rrUz
K7WnPJyQ2FPL+/D81NK6SH1eHZjemb1jV9d8uGb7ifvha5j9AkEA+4/dZV+dZebL
dRKtyHLfbXaUhJcNmM+04hqN1DUhdLAfnFthoiSDw3i1EFixvPSiBfwuWC6h9mtL
CeKgySaOkwJBAMSdBhn3C8NHhsJA8ihQbsPa6DyeZN+oitiU33HfuggO3SVIBN/7
HmnuLibqdxpnDOtJT+9A+1D29TkNENlTWgsCQGjVIC8xtFcV4e2s1gz1ihSE2QmU
JU9sJ3YeGMK5TXLiPpobHsnCK8LW16WzQIZ879RMrkeDT21wcvnwno6U6c8CQQCl
dsiVvXUmyOE+Rc4F43r0VRwxN9QI7hy7nL5XZUN4WJoAMBX6Maos2Af7NEM78xHK
SY59+aAHSW6irr5JR351AkBA+o7OZzHIhvJfaZLUSwTPsRhkdE9mx44rEjXoJsaT
e8DYZKr84Cbm+OSmlApt/4d6M4YA581Os1eC8kopewpy
-----END RSA PRIVATE KEY-----
";
$strPrivateKey=preg_replace("/[ \t]/", "", $strPrivateKey);//this won't be necessary when loading from PEM
$rsa->loadKey($strPrivateKey);
$binaryCiphertext=base64_decode($strBase64CipherText);
$rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);
$strBase64DecryptedData=$rsa->decrypt($binaryCiphertext);
return base64_decode($strBase64DecryptedData);
}
//The pidCrypt example implementation will output a base64 string of an encrypted base64 string which contains the original data, like this one:
$strBase64CipherText="JDlK7L/nGodDJodhCj4uMw0/LW329HhO2EvxNXNUuhe+C/PFcJBE7Gp5GWZ835fNekJDbotsUFpLvP187AFAcNEfP7VAH1xLhhlB2a9Uj/z4Hulr4E2EPs6XgvmLBS3MwiHALX2fES5hSKY/sfSUssRH10nBHHO9wBLHw5mRaeg=";
$binaryDecrypted=decrypt($strBase64CipherText);
//should output '4111111111111111'
var_export($binaryDecrypted);
Ceci est basé sur Tiny Encryption Algorithm , qui est un système de cryptage symétrique (clé privée). Il peut néanmoins vous être utile en raison de sa légèreté.
C'est maintenant à: http://babelfish.nl/Projecten/JavascriptPhpEncryption