我正在做一个登录系统。我希望客户端(使用他的私钥)加密来自服务器的随机消息并将结果发送到服务器。然后,服务器将使用公钥破译消息并进行比较。
我试过jsencrypt。我有一个密码结果,但我无法使用openssl_public_decrypt解密,但它不起作用
请提供建议或帮助!!
这是完成javascript加密的文件
<?php
//Génération d'un message aleatoires
$i = 4;
global $bytes;
$bytes = openssl_random_pseudo_bytes($i, $cstrong);
$hex = pack('H*', bin2hex($bytes));;
$username = $_POST["username"];
$password = $_POST["password"];
echo '<!DOCTYPE html>
<html>
<head>
<title>Accueil</title>
<script language="javascript">
function controle(form1, n) {
if(n == 0){
var pub = document.form1.clepub.value;
var fso = new ActiveXObject("Scripting.FileSystemObject");
// 2=overwrite, true=create if not exist, 0 = ASCII
var varFileObject = fso.OpenTextFile(pub, 1, false, 0);
//varFileObject.write("File handling in Javascript");
var s = varFileObject.ReadAll();
varFileObject.close();
return s;
}
else{
var priv = document.form1.clepriv.value;
var fso = new ActiveXObject("Scripting.FileSystemObject");
// 2=overwrite, true=create if not exist, 0 = ASCII
var varFileObject = fso.OpenTextFile(priv, 1, false, 0);
//varFileObject.write("File handling in Javascript");
var s = varFileObject.ReadAll();
varFileObject.close();
return s;
}
//alert("La clé privée est : " + s);
}
</script>
<script src="jquery-1.12.1.min.js"></script>
<script src="jsencrypt-master/bin/jsencrypt.js"></script>
<script language="javascript">
function chiffrer() {
document.getElementById("testme").style.visibility="hidden";
// Encrypt with the public key...
var encrypt = new JSEncrypt();
encrypt.setPublicKey(controle(form1, 1));
//alert(controle(form1, 1));
var encrypted = encrypt.encrypt("'.$hex.'");
document.getElementById("submit").style.visibility="visible";
document.getElementById("input").value = encrypted;
//alert(encrypted);
//document.getElementById("input").value = encryptedb64tohex(encrypted);
}
</script>';
echo '</head>
<body>
<h1>Bienvenue sur TelGov</h1>
<h2>Engager votre clef privee</h2>
<form action="compare.php" method="POST" name = "form1">
<!--<label for="clepub">Engager votre clef publique</label>
<input name="clepub" id="clepub" type="file"></input>
<label for="clepriv">Engager votre clef privee</label>-->
<input name="clepriv" id="clepriv" type="file"></input>
<br/><br/>
<input name="hash" id="hash" type="hidden" value="'.$hex.'"></input>
<br/><br/>
<input id="input" name="input" type="hidden" ></input><br/>
<input id="testme" type="button" value="Engager" onclick="chiffrer()" /><br/>
<input type="hidden" name="username" value="'.$username.'">
<input type="hidden" name="password" value="'.$password.'">
<!--<br/><br/>
<input type="button" name="bouton" value="Controler" onClick="controle(form1)">
<br/><br/>-->
<input type="submit" id = "submit" value="Se connecter" style="visibility: hidden;"</input>
</form>
</body>
</html>';
?>
这是用于比较的代码
<?php
try{
$bdd = new PDO('mysql:host=localhost;dbname=authentification', 'root', '');
}
catch (Exception $e){
die('Erreur : ' . $e->getMessage());
}
$username = $_POST['username'];
$password = $_POST['password'];
$config = array(
"config" => "C:/wamp/bin/apache/apache2.4.9/conf/openssl.cnf",
"digest_alg" => "sha512",
"private_key_bits" => 1024,
"private_key_type" => OPENSSL_KEYTYPE_RSA,
);
if(isset($_POST['input'])&&isset($_POST['hash'])){
$crypt = $_POST['input'];
$bon = $_POST['hash'];
$cle = $bdd->prepare("SELECT publicKey FROM utilisateurs WHERE username =? AND password=?");
$cle->execute(array($username, $password));
$tmp = $cle->fetch();
var_dump($tmp['publicKey']);
var_dump($bon);
//var_dump(openssl_private_decrypt(base64_decode($crypt), $decrypted, $tmp['privateKey']/*openssl_pkey_get_private($tmp['privateKey'], null)*/));
var_dump(openssl_public_decrypt (base64_decode($crypt)/*$crypt*/, $decryted, $tmp['publicKey']));
var_dump($decryted);
var_dump(base64_decode($crypt));
if($decryted == $bon){
//header("Location:Accueil.php");
echo "Bon";
}
else{
//header("Location:index.php");
echo "Mauvais";
}
}
else{
header("Location:index.php");
}
?>
这是比较结果
来自 IE 的图像结果
我正在使用Jsencrypt library。我发现不可能用Jscrypt用私钥加密,用php openssl用公钥解密。所以我改变了我的方法,我用Jsencrypt 使用公钥加密,用php openssl解密。这工作得很好
我找到了这个jsencrypt 库(http://travistidwell.com/jsencrypt),经过 2 天的尝试,我得到了我的解决方案。
我遇到的唯一问题是当我发送长文本时。这是因为根据定义,RSA 支持有限长度的字符串。
https://security.stackexchange.com/questions/33434/rsa-maximum-bytes-to-encrypt-comparison-to-aes-in-terms-of-security/33445#33445
根据 PKCS#1 的定义,RSA 加密大小有限的"消息"。跟 常用的"v1.5 填充"和一个 2048 位 RSA 密钥,最大值 可以使用 RSA 加密的数据大小为 245 字节。没有了。
即如果我使用 1024 的private_key_bits,我可以发送
"José compró en Perú una vieja zampoña. Excusándose, Sofía tiró su whisky al desagüe de la banqueta."
没有了。如果我使用 512 中的private_key_bits,我可以发送
"José compró en Perú una vieja zampoña. Excusánd"
没有了。
在长字符串上,JavaScript 控制台报告:"消息对于 RSA 来说太长了"
然后,如果你想加密长字符串,你必须在javascript加密之前和解密之后压缩和拆分它们 加入和解压缩 php,我认为zlib是一个很好的拆分/连接解决方案,因为它在javascript和php上受支持。
我的工作代码如下:
<?php
//------------------------------------------------------------
// Global Settings.
//------------------------------------------------------------
ini_set('display_errors', 1);
error_reporting(E_ALL);
$directorio = "/path/to/key/directory/apache/writable/";
$nombre_base = "llaves_php";
//------------------------------------------------------------
// Initialization.
//------------------------------------------------------------
$encabezado_html = "";
$cuerpo_html = "";
//------------------------------------------------------------
// Loading keys
//------------------------------------------------------------
list($privateKey, $pubKey) =
cargar_llaves_RSA($directorio, $nombre_base);
//------------------------------------------------------------
// Form that uses javascript to encrypt data.
// (it uses only the public key)
//------------------------------------------------------------
$librerias_html = "
<script type='text/javascript'
src='https://ajax.googleapis.com/ajax/libs/".
"jquery/3.2.1/jquery.min.js'></script>
<script type='text/javascript'
src='lib/jsencrypt.js'></script>
";
$pubKey_html = htmlentities($pubKey);
$datos_html = "
<h2>Cifrando con Javascript</h2>
<input type='text' id='mensaje' />
<br />
<button id='ENVIAR'>Enviar</button>
<br />
<textarea id='pubkey' style='display: none;'>".
$pubKey_html.
"</textarea>
<script type='text/javascript'>
$('#ENVIAR').click(function () {
var codificador = new JSEncrypt();
codificador.setKey($('#pubkey').val());
var cifrado = codificador.encrypt($('#mensaje').val());
window.open('?mensaje=' + encodeURIComponent(cifrado)
, '_top');
});
</script>
";
//------------------------------------------------------------
// Decrypting using php (it uses only the privateKey)
//------------------------------------------------------------
if (isset($_REQUEST['mensaje'])) {
openssl_private_decrypt( base64_decode($_REQUEST['mensaje'])
, $descifrado
, $privateKey);
$datos_html.= "
<h2>Descifrando con PHP</h2>
".$descifrado."
";
}
//------------------------------------------------------------
// HTML DISPLAY
//------------------------------------------------------------
$encabezado_html.= "<title>Receptor de mensaje cifrado</title>"
. $librerias_html;
$cuerpo_html.= $datos_html;
$contenido = "<head>$encabezado_html</head><body>$cuerpo_html</body>";
$contenido = "<html>$contenido</html>";
print $contenido;
//============================================================
//============================================================
// Functions
//============================================================
//============================================================
//------------------------------------------------------------
function cargar_llaves_RSA($directorio, $nombre_base) {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// PROPÓSITO: Genera o carga desde archivos las llaves RSA
// ENTRADAS:
// $directorio: Directorio donde se encuentran los archivos.
// $nombre_base: Nombre, sin extensión, de los archivos con
// las llaves.
// SALIDAS:
//------------------------------------------------------------
if ( !file_exists($directorio.$nombre_base.".crt")
|| !file_exists($directorio.$nombre_base.".pub")) {
list($privateKey, $pubKey) = crear_llaves_RSA($directorio.$nombre_base);
} else {
//------------------------------------------------------------
// CARGA DE LLAVES RSA ARCHIVADAS
//------------------------------------------------------------
$privateKey = file_get_contents($directorio.$nombre_base.".crt");
if (!$privKey = openssl_pkey_get_private($privateKey))
die('Loading Private Key failed');
$pubKey = file_get_contents($directorio.$nombre_base.".pub");
}
return array($privateKey, $pubKey);
}
//------------------------------------------------------------
function crear_llaves_RSA($ruta_base) {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// PROPÓSITO:
// generacion de llaves RSA en php
// ENTRADAS:
// $ruta_base: Ruta de los archivos a generar sin extensión.
// SALIDAS:
// Se generarán dos archivos, uno con la llave privada con
// extensión .crt, el otro con llave pública con extensión
// .pub; la función retorna tanto la llave pública como la
// privada en un arreglo.
//------------------------------------------------------------
$config = array(
"private_key_bits" => 1024,
"private_key_type" => OPENSSL_KEYTYPE_RSA,
);
$llavePrivadaCruda = openssl_pkey_new($config);
openssl_pkey_export_to_file($llavePrivadaCruda, $ruta_base.".crt");
$privateKey = file_get_contents($ruta_base.".crt");
openssl_pkey_export($llavePrivadaCruda, $privKey);
$pubKeyData = openssl_pkey_get_details($llavePrivadaCruda);
$pubKey = $pubKeyData["key"];
file_put_contents($ruta_base.".pub", $pubKey);
openssl_free_key($llavePrivadaCruda);
return array($privateKey, $pubKey);
}
//------------------------------------------------------------
function Mostrar($valor) {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// PROPÓSITO: Genera el código HTML para presentar una
// variable embebida en la página.
// ENTRADAS:
// $valor: el valor a presentar.
// SALIDAS: código html que permite visualizar la variable.
//------------------------------------------------------------
$retorno = htmlentities(stripslashes(var_export($valor, true)));
$retorno = "<pre>$retorno</pre>";
return $retorno;
}
?>
目录树必须如下所示:
├── script.php
└── lib
└── jsencrypt.js
以及一个可由 PHP 在公共区域之外写入的目录,名为
/path/to/key/directory/apache/writable/