Szyfruj w Javascript, odszyfruj w PHP, używając kryptografii klucza publicznego

Chciałbym szyfrować w JavaScript, odszyfrować w PHP, używając kryptografii klucza publicznego. Próbowałem znaleźć biblioteki, które mogą to osiągnąć, ale mam problemy.

obecnie patrzę na openpgpjs, ale potrzebuję wsparcia we wszystkich przeglądarkach, a nawet strona testowa ma błędy na jedynej wymienionej jako obsługiwana przeglądarka (Google Chrome).

Uwagi o ostatecznym celu:

Połączenie TCP jest już chronione przez SSL. Głównym celem tego warstwa ochrony chroni przed celowym lub niezamierzonym logowaniem serwera www, zrzutami awaryjnymi itp.

Po stronie PHP zostanie wygenerowany tymczasowy klucz prywatny (wygaśnie po krótkim czasie). Wywołujący (w Javascript) jest odpowiedzialny za pytanie o nowy klucz publiczny, gdy wygaśnie. Powodem wygaśnięcia klucza prywatnego jest uniemożliwienie odszyfrowania zalogowanych zaszyfrowanych danych, na wypadek, gdyby serwer przechowujący klucz prywatny został później naruszony.

Serwery skompromitowane scenariusz: ktoś dostaje kopie zapasowe wszystkich maszyn z wyjątkiem serwera bazy danych (i nie może uzyskać dostępu do bazy danych z powodu zapory, nawet jeśli znajdzie użytkownika i hasło). Ponieważ klucz prywatny, który zaszyfrował zarejestrowane dane, już nie istnieje, atakujący nie może nic zrobić.

Author: Scott Arciszewski, 2012-09-17

5 answers

Użyłem czegoś podobnego na mojej stronie logowania; szyfruje dane logowania za pomocą podanych informacji klucza publicznego (N, e), które można odszyfrować w PHP.

Używa następujących plików, które są częścią JSBN:

  • jsbn.js - do pracy z wielkimi liczbami całkowitymi
  • rsa.js - tylko dla szyfrowania RSA (używa jsbn.js)
  • rng.js - podstawowy kolektor entropii
  • prng4.js - ARC4 RNG backend

Aby zaszyfrować dane:

$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>

Oto jak rozszyfrowywałbyś wysłane DANE:

$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;
}
 29
Author: Ja͢ck,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-25 03:50:29

Sprawdź node-rsa.

To węzeł.moduł js

Ten moduł zapewnia dostęp do procedur klucza publicznego RSA z OpenSSL. Obsługa jest ograniczona do RSAES-oaep i szyfrowania kluczem publicznym, deszyfrowania kluczem prywatnym.

Być może można go przenieść do uruchomienia w przeglądarce.

UPDATE

Biblioteka po stronie klienta RSA dla javascript: (pidcrypt został oficjalnie wycofany, a domena witryny wygasła - patrz @ jack ' s odpowiedź, która zawiera te same biblioteki co pidcrypt) . https://www.pidder.com/pidcrypt/?page=rsa

Komponent po stronie serwera PHP: http://phpseclib.sourceforge.net/

Powodzenia!

 24
Author: Vlad Balmos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-25 08:10:57

Bądź ostrożny z wdrażaniem RSA. W rzeczywistości prawdopodobnie nie powinieneś w ogóle używać RSA. (Użyj zamiast tego libsodium!)

Nawet jeśli korzystasz z biblioteki (np. bezpośrednio z rozszerzenia OpenSSL PHP lub do niedawna, Zend\Crypt), jest jeszcze wiele rzeczy, które mogą pójść nie tak. W szczególności:

  • PKCS1v1.5 padding, który jest domyślnym (i w wielu przypadkach jedynym obsługiwanym trybem padding), jest podatny na klasę ataków zaszyfrowanych, zwanych padding wyrocznia. Odkrył ją Daniel Bleichenbacher. W 1998 roku.
  • RSA nie nadaje się do szyfrowania dużych wiadomości, więc implementatorzy często przyjmują długą wiadomość, dzielą ją na bloki o stałej wielkości i szyfrują każdy blok osobno. Nie tylko jest to powolne, ale jest analogiczne do trybu EBC dla kryptografii z kluczem symetrycznym.

The Best Thing to Do, with Libsodium

Możesz przeczytać JavaScript Kryptografia uważana za szkodliwą kilka razy przed pójściem tą trasą. Ale to powiedziane...

  1. używaj TLSv1. 2 z HSTS i HPKP, najlepiej z ChaCha20-Poly1305 i/lub AES-GCM i certyfikatem ECDSA-P256 (ważne: gdy IETF ochrzci Curve25519 i Ed25519, przełącz się na to).
  2. Dodaj libsodium.js do twojego projektu.
  3. użyj crypto_box_seal() z kluczem publicznym do szyfrowania wiadomości po stronie klienta.
  4. W PHP, użyj \Sodium\crypto_box_seal_open() z odpowiedni klucz tajny klucza publicznego do odszyfrowania wiadomości.

Muszę użyć RSA, aby rozwiązać ten problem.

Proszę nie . Kryptografia krzywej eliptycznej jest szybsza, prostsza i znacznie łatwiejsza do wdrożenia bez kanałów bocznych. Większość bibliotek robi to już za Ciebie. (Libsodium!)

Ale ja naprawdę chcę używać RSA!

Dobrze, wykonaj te zalecenia do listu i nie przychodź z płaczem do StackOverflow, gdy popełnij błąd (tak jak zrobił to SaltStack), który czyni twoją kryptografię bezużyteczną.

Jedną z opcji (która nie jest dostarczana z uzupełniającą implementacją JavaScript, i proszę o nią nie pytać), która ma na celu zapewnienie prostego i łatwego szyfrowania RSA jest paragonie/easyrsa.

  • unika usztywniania wyroczni używając RSA-OAEP z MGF1+SHA256 zamiast PKCS1v1.5.
  • unika trybu EBC dzięki sprytnemu projektowi protokołu:

The EasyRSA Encryption Protocol

  1. EasyRSA generuje losowy 128-bitowy klucz do kryptografii klucza symetrycznego (poprzez AES).
  2. twoja wiadomość tekstowa jest zaszyfrowana defuse / PHP-encryption.
  3. Twój klucz AES jest szyfrowany za pomocą RSA, dostarczonego przez phpseclib , przy użyciu prawidłowego trybu (wymienionego powyżej).
  4. Ta informacja jest spakowana razem jako prosty ciąg znaków (z sumą kontrolną).

Ale, naprawdę, jeśli znajdziesz poprawny przypadek użycia dla publicznego kryptografia kluczowa, zamiast niej chcesz libsodium.

 10
Author: Scott Arciszewski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-17 13:14:46

RSA przykładowe użycie dla pidCrypt (js) i phpseclib (php).

W tym przykładzie nie używaj ponownie klucza prywatnego.

PidCrypt encryption

//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);

.

Odszyfrowywanie 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);
 1
Author: Tiberiu-Ionuț Stan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-25 11:31:28

Jest to oparte na algorytmie Tiny Encryption , który jest symetrycznym (kluczem prywatnym) systemem szyfrowania. Może jednak być przydatny ze względu na niewielką wagę.

This is now at: http://babelfish.nl/Projecten/JavascriptPhpEncryption

 0
Author: Pum Walters,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-14 14:04:38