Javascript + PHP шифрование с помощью pidCrypt
Я работал над попыткой реализовать механизм шифрования для передачи защищенной информации на мой сайт. Мой хост взимает дополнительную плату за SSL, и я не готов к дополнительным денежным обязательствам.
Я пытался использовать pidCrypt для шифрования значений на стороне клиента с помощью JavaScript. Затем я попробовал несколько методов для дешифрования на стороне PHP. По какой-то причине данные просто искажаются.
Может кто-то указать, что я делаю не так? Или я должен использовать другую библиотеку JavaScript для шифрования? Любой совет?
Вот код javascript, который извлекает текст для шифрования из ввода на странице, а открытый ключ - из скрытой текстовой области на странице.
$(document).ready(function() {
$('button').click(function() {
var dataToSend = new Object();
var input = $('input[name=textToEncrypt]').val();
var public_key = $('textarea[name=publicKey]').val();
var params = certParser(public_key);
var key = pidCryptUtil.decodeBase64(params.b64);
//new RSA instance
var rsa = new pidCrypt.RSA();
//RSA encryption
//ASN1 parsing
var asn = pidCrypt.ASN1.decode(pidCryptUtil.toByteArray(key));
var tree = asn.toHexTree();
//setting the public key for encryption
rsa.setPublicKeyFromASN(tree);
var t = new Date(); // timer
crypted = rsa.encrypt(input);
dataToSend.unencrypted = input;
dataToSend.textToDecrypt = pidCryptUtil.fragment(pidCryptUtil.encodeBase64(pidCryptUtil.convertFromHex(crypted)),64);
$('body').append(dataToSend.textToDecrypt);
$.getJSON('engine.php', dataToSend, function(data) {
var items = [];
$.each(data, function(key, val) {
items.push('<li id="' + key + '">' + key + ': ' + val + '</li>');
});
$('<ul/>', {
'class': 'my-new-list',
html: items.join('')
}).appendTo('body');
});
});
});
Это мой код engine.php, который должен расшифровывать значение. Обратите внимание, что я пробовал несколько разных способов на разных примерах.
<?php
require_once 'private/keys.php';
function EncryptData($source)
{
/*
* NOTE: Here you use the $pub_key value (converted, I guess)
*/
$key = $DEkeys->pubKey;
openssl_public_encrypt($source,$crypttext,$key);
return(base64_encode($crypttext));
}
function DecryptData($source)
{
/*
* NOTE: Here you use the returned resource value
*/
$decoded_source = base64_decode($source);
openssl_private_decrypt($decoded_source,$newsource,$DEkeys->privKey);
return($newsource);
}
function EncryptData2($source)
{
$fp=fopen("/pathtokey/public.pem","r");
$pub_key=fread($fp,8192);
fclose($fp);
openssl_get_publickey($pub_key);
/*
* NOTE: Here you use the $pub_key value (converted, I guess)
*/
openssl_public_encrypt($source,$crypttext,$pub_key);
return(base64_encode($crypttext));
}
function DecryptData2($source)
{
#print("number : $number");
$fp=fopen("/pathtokey/private.pem","r");
$priv_key=fread($fp,8192);
fclose($fp);
// $passphrase is required if your key is encoded (suggested)
$res = openssl_get_privatekey($priv_key);
/*
* NOTE: Here you use the returned resource value
*/
$decoded_source = base64_decode($source);
openssl_private_decrypt($decoded_source,$newsource,$res);
return($newsource);
}
$out = new stdClass;
$out->hello = 'hello, world!';
if(!empty($_GET["textToDecrypt"])) {
$out->raw = $_GET['textToDecrypt'];
$out->unencrypted = $_GET['unencrypted'];
if($DEkeys->privKey == false) {
$out->error = 'Could not read private key';
}
$out->success = openssl_private_decrypt(base64_decode($out->raw), $decrypted, $DEkeys->privKey);
$out->decrypted = $decrypted;
$out->dec2 = DecryptData2($out->raw);
$out->test1 = EncryptData2('testing');
$out->test2 = DecryptData2($out->test1);
} else {
$out->nondata = $_GET['textToDecrypt'];
}
echo json_encode($out);
Когда я ввожу "test" для значения для расшифровки, PHP показывает: - расшифрован: dGVzdA== - dec2: dGVzdA==
Таким образом, ни функции openssl_private_decrypt(), ни функции DecryptData2() не смогут правильно расшифровать значения. EncryptData2() и DecryptData2() будут работать вместе, хотя.
Возможно ли, что я пропускаю что-то маленькое? Любой совет?
Изменить: вот команды, которые я использовал для создания ключей -
Это создает закрытый ключ:
openssl genrsa -out private.pem 1024
Это создает открытый ключ:
openssl rsa -in private.pem -pubout > public.pem
4 ответа
Попробуйте следующий простой пример. Я использовал его только для шифрования пароля, но вы также можете использовать его для всей формы.
Он использует библиотеку JavaScript с открытым исходным кодом https://ziyan.info/2008/10/javascript-rsa/
HTML/JavaScript:
<script language="JavaScript" type="text/javascript" src="jsbn.js"></script>
<script language="JavaScript" type="text/javascript" src="rsa.js"></script>
<script language="JavaScript">
function encryptData(){
//Don't forget to escape the lines:
var pem="-----BEGIN PUBLIC KEY-----\
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDfmlc2EgrdhvakQApmLCDOgP0n\
NERInBheMh7J/r5aU8PUAIpGXET/8+kOGI1dSYjoux80AuHvkWp1EeHfMwC/SZ9t\
6rF4sYqV5Lj9t32ELbh2VNbE/7QEVZnXRi5GdhozBZtS1gJHM2/Q+iToyh5dfTaA\
U8bTnLEPMNC1h3qcUQIDAQAB\
-----END PUBLIC KEY-----";
var key = RSA.getPublicKey(pem);
element=document.getElementById('password');
element.value=RSA.encrypt(element.value, key);
}
</script>
<form method='POST' id='txtAuth' onsubmit='encryptData()'>
<input type='text' name='username'/>
<input type='password' name='password' id='password' placeholder="password"/>
<input name='submit' type='submit' value='Submit'>
</form>
PHP:
<?php
if (isset($_POST['password'])) {
//Load private key:
$private = "-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQDfmlc2EgrdhvakQApmLCDOgP0nNERInBheMh7J/r5aU8PUAIpG
XET/8+kOGI1dSYjoux80AuHvkWp1EeHfMwC/SZ9t6rF4sYqV5Lj9t32ELbh2VNbE
/7QEVZnXRi5GdhozBZtS1gJHM2/Q+iToyh5dfTaAU8bTnLEPMNC1h3qcUQIDAQAB
AoGAcbh6UFqewgnpGKIlZ89bpAsANVckv1T8I7QT6qGvyBrABut7Z8t3oEE5r1yX
UPGcOtkoRniM1h276ex9VtoGr09sUn7duoLiEsp8aip7p7SB3X6XXWJ9K733co6C
dpXotfO0zMnv8l3O9h4pHrrBkmWDBEKbUeuE9Zz7uy6mFAECQQDygylLjzX+2rvm
FYd5ejSaLEeK17AiuT29LNPRHWLu6a0zl923299FCyHLasFgbeuLRCW0LMCs2SKE
Y+cIWMSRAkEA7AnzWjby8j8efjvUwIWh/L5YJyWlSgYKlR0zdgKxxUy9+i1MGRkn
m81NLYza4JLvb8/qjUtvw92Zcppxb7E7wQJAIuQWC+X12c30nLzaOfMIIGpgfKxd
jhFivZX2f66frkn2fmbKIorCy7c3TIH2gn4uFmJenlaV/ghbe/q3oa7L0QJAFP19
ipRAXpKGX6tqbAR2N0emBzUt0btfzYrfPKtYq7b7XfgRQFogT5aeOmLARCBM8qCG
tzHyKnTWZH6ff9M/AQJBAIToUPachXPhDyOpDBcBliRNsowZcw4Yln8CnLqgS9H5
Ya8iBJilFm2UlcXfpUOk9bhBTbgFp+Bv6BZ2Alag7pY=
-----END RSA PRIVATE KEY-----";
if (!$privateKey = openssl_pkey_get_private($private)) die('Loading Private Key failed');
//Decrypt
$decrypted_text = "";
if (!openssl_private_decrypt(base64_decode($_POST['password']), $decrypted_text, $privateKey)) die('Failed to decrypt data');
//Decrypted :)
var_dump($decrypted_text);
//Free key
openssl_free_key($privateKey);
}
?>
Наслаждайтесь!
Ваши расшифрованные значения имеют кодировку base64, потому что pidCrypt использует кодировку base64 для обеспечения 8-битных символов до шифрования RSA. Так что просто base64-декодируй свои результаты.
См. https://sourceforge.net/projects/pidcrypt/forums/forum/923749/topic/3153476
В итоге я использовал Open ID. Это небезопасно, но, по крайней мере, это немного лучше, чем ничего. Конкретная реализация, которую я нашел, была LightOpenID.
Когда придет время обновлять, я выберу другой веб-хостинг, который позволит мне использовать SSL доступным способом.
Я так и не понял, почему мой код шифрования не работает.
Вы не можете безопасно зашифровать что-либо на стороне клиента. Это связано с тем, что клиент имеет полный контроль над любыми данными, которые будут отправлены, а также механизм шифрования.
В прошлом были споры об этом, и вывод всегда один и тот же. Это не может быть сделано любым безопасным способом.
Вопрос, который вы должны задать себе: от чего вы пытаетесь защитить себя / своих клиентов?
Если вы пытаетесь защитить себя от людей, которые прослушивают данные или вмешиваются в данные запроса, единственным приемлемым решением является SSL.
Во всяком случае, крипто не является решением для поиска.
(примечание: расшифрованная строка закодирована в base64, попробуйте base64_decode)