RSA-OAEP SHA-512 Шифрование / дешифрование из API Javascriptwebcrypt в PHP openssl?

Я был довольно занят, пытаясь установить безопасный обмен между клиентом браузера, используя webcrypto api и сервер PHP, используя openssl. Я сломал вещи столько, сколько смог. Я написал некоторый javascript для генерации пары ключей, распечатал значения private и public, зашифровал простую строку и распечатал ее.

Я скопировал значения прямо в простой скрипт php. Попытка расшифровать его значениями из javascipt.

Кодирование и декодирование работает должным образом в javascript (как опубликовано ниже), декодирование в php - нет (также размещено под javascript). Я также не могу найти, где установить объявление SHA-512 в PHP. Есть ли у кого-нибудь опыт такого обмена и, возможно, указывает мне правильное направление. RSA-OAEP был выбран потому, что он поддерживается chrome, mozilla, IE11 и Safari, а также PHP.

С уважением, Гедеон

// JavaScript Document
var keyPair;
var pemPublicKey;
var pemPrivateKey;

var _spki;
var _pkcs8;

 window.crypto.subtle.generateKey({
  name: "RSA-OAEP",
  modulusLength: 2048,
  publicExponent: new Uint8Array([1, 0, 1]),  // 24 bit representation of 65537
  hash: {name: "SHA-512"}
 }, true, ["encrypt", "decrypt"])
 .then(function(newKeyPair) {
  keyPair = newKeyPair;
  return keyPair;
 })
 .then(function(keyPair) {
  window.crypto.subtle.exportKey('spki', keyPair.publicKey)
  .then(function(spki) {
   _spki = spki;
   var pemPublicKey = convertBinaryToPem(spki, "PUBLIC KEY");
   document.writeln(pemPublicKey);
   sendToPhp();
  });
 
  window.crypto.subtle.exportKey('pkcs8', keyPair.privateKey)
  .then(function(pkcs8) {
   _pkcs8 = pkcs8;
   var pemPrivateKey = convertBinaryToPem(pkcs8, "PRIVATE KEY");
   document.writeln(pemPrivateKey);
  })
 });
 
 function sendToPhp() {
  window.crypto.subtle.importKey('spki', _spki, {name:"RSA-OAEP", hash: {name: "SHA-512"}}, false, ["encrypt"])
  .then(function(cryptokey) {
   window.crypto.subtle.encrypt({ name: "RSA-OAEP"}, cryptokey, str2ab('mijn geheimpje') )
   .then(function(encrypted){
    //returns an ArrayBuffer containing the encrypted data
    document.writeln(arrayBufferToBase64String(encrypted));
    receivedFromPhp(arrayBufferToBase64String(encrypted));
   });
  });
 }
 
 function receivedFromPhp(encrypted) {
  window.crypto.subtle.importKey('pkcs8', _pkcs8, {name:"RSA-OAEP", hash: {name: "SHA-512"}}, false, ["decrypt"])
  .then(function(cryptokey) {
   window.crypto.subtle.decrypt({ name: "RSA-OAEP"}, cryptokey, base64StringToArrayBuffer(encrypted) )
   .then(function(decrypted){
    //returns an ArrayBuffer containing the encrypted data
    var decryp = ab2str(decrypted);
    debugger;
   });
  });
 }
 
 function ab2str(buf) {
  return String.fromCharCode.apply(null, new Uint16Array(buf));
 }

 function str2ab(str) {
  var buf = new ArrayBuffer(str.length*2); // 2 bytes for each char
  var bufView = new Uint16Array(buf);
  for (var i=0, strLen=str.length; i<strLen; i++) {
   bufView[i] = str.charCodeAt(i);
  }
  return buf;
 }
 function base64StringToArrayBuffer(base64) {
  var binary_string =  atob(base64);
  var len = binary_string.length;
  var bytes = new Uint8Array( len );
  for (var i = 0; i < len; i++)        {
   bytes[i] = binary_string.charCodeAt(i);
  }
  return bytes.buffer;
 }
 function arrayBufferToBase64String(arrayBuffer) {
  var byteArray = new Uint8Array(arrayBuffer)
  var byteString = '';
  for (var i=0; i<byteArray.byteLength; i++) {
   byteString += String.fromCharCode(byteArray[i]);
  }
  return btoa(byteString);
 }

 function convertBinaryToPem(binaryData, label) {
  var base64Cert = arrayBufferToBase64String(binaryData);

  var pemCert = "-----BEGIN " + label + "-----\r\n";

  var nextIndex = 0;
  var lineLength;
  while (nextIndex < base64Cert.length) {
   if (nextIndex + 64 <= base64Cert.length) {
    pemCert += base64Cert.substr(nextIndex, 64) + "\r\n";
   } else {
    pemCert += base64Cert.substr(nextIndex) + "\r\n";
   }
   nextIndex += 64;
  }

  pemCert += "-----END " + label + "-----\r\n";
  return pemCert;
 }

<?php

 error_reporting(E_ALL);
 ini_set("display_errors", 1);
 $pemPublicKey =  '-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvzJ07T/SiZsUPfC4ymwj
G/TqVdO04QZRUMcsmHeUG0BawSxlwoz+0YD48UZFYyTetw3egoasQfkvOPIUKuqq
mPEXwGsVlLbkqvPsgNA2K6Zye8El9DEp83eoPqylopU0L9zSnQp9VaNpSgsOlltr
0RRyq3q8gBJb7PkzuDzmXrr5KEuGmkLmOE3TH0Ck9u+c4xE87g3s5HtQ6uGa6jB6
JooTN1edPum+kBJdJajOW5FvOfDnEHQBsKZPd4HiYcOlM7crt2Y9XnBSBIIZ1uR6
a4Qs+EP6CwczPA6/J5a+GOV9ch1xZLsW5JuO55lCDpwrvKr7VVqwQG3qNewk8vVA
iwIDAQAB
-----END PUBLIC KEY-----';

 $pemPrivateKey = '-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC/MnTtP9KJmxQ9
8LjKbCMb9OpV07ThBlFQxyyYd5QbQFrBLGXCjP7RgPjxRkVjJN63Dd6ChqxB+S84
8hQq6qqY8RfAaxWUtuSq8+yA0DYrpnJ7wSX0MSnzd6g+rKWilTQv3NKdCn1Vo2lK
Cw6WW2vRFHKreryAElvs+TO4POZeuvkoS4aaQuY4TdMfQKT275zjETzuDezke1Dq
4ZrqMHomihM3V50+6b6QEl0lqM5bkW858OcQdAGwpk93geJhw6Uztyu3Zj1ecFIE
ghnW5HprhCz4Q/oLBzM8Dr8nlr4Y5X1yHXFkuxbkm47nmUIOnCu8qvtVWrBAbeo1
7CTy9UCLAgMBAAECggEBAK1i7HZacmsnn2usaWfoOM6ZhAjhPB70w7klZmO9zSoJ
akPUJ1QO2ObUtuzWdQY74VzPzwE/b+dEOnbB0Vg6Bws7V/a/JYr/cM829Tq7luRu
xVNFDU4tZ4XK9WAg4PRXqkPdVYHkiVSoJEtpS4k+zr+Ec5jebSMXgxWbyDNDxwYP
p6TenCVIhLGK3cR2uWADsXLAQQ5p5QMnpXDhr2m8cbe7496B4lTwe/gyjomzNutD
ZnIQCfAY9r1r7U7ryT2eoNXmb9uDG+fqSaAvaB/kujOT6y1takSxf7Ij26dUL9iA
7h59c2Ztu4PMrISV+04DGYfFs1MzYeBfoz7pxqHEHMECgYEA4IVY54trkJ5/8CId
ad1s+bV3exNTJNgTAiqZE/a4eNnBzQD85SGbUAnk9PGzGvW9o3spQkcnJIqqDWJQ
cOJlh8HQJqm/0pkWJKonoHUy05SleB67sZz97gAFj/NsPOSSQ6yMnf/pEeKwbrIa
/fkOhdjAXk//WnECvo11o6MC7cUCgYEA2gEHoyRS5dbv+FtL1WFn0lNTlMl8tHz3
fAdXuPi5dp3gPhqfxcP5n3QpT9Jc3rhQQaRswbKCjo2YAOhSdHR6nqYTyte+F+H2
ImsqTGFlunIMpXmYK4ssOl00gnG+9cLHDNbHtjCb+oZy9sh8pZZniafSg0aYImo0
VG4RGesbKg8CgYEAq1179vaV+gLP+ZPASX4k4A7ejAS68CMvlva2ceNc93iVEAiR
/b0B0zxKEZ6tKoWn4bBuVFUEjkJ7+s0wQoi6H70RR4FGlNIdcYyhxDnPumf5R86F
SdJeihpgJHgSBAQdkyOPDEU4OluAeGzeZzyCFizS3ulGKFybUJ+dy3DvGlUCgYBp
KjwD8F7pL2G9/lS7z+xkovvb98Ln0q0UsPoZaisV1J07eF6A6cQ+rqvLLODOND3L
HMW2PyYKHLYqIei88v/ADr/Xh3HVVZUGD4ptJEMNyTzeiqTkxJOGaDYPg02qgtbB
E89tzU9BcKB++kJfIwo5drLvzxtO5srtu9cWGLuW8wKBgQCK0k/hYZyvB+9vELyH
fNaVxj+jn5BWOmFtk6/TC/J5dQzldt7uyxkwoWOsJinpc0JByG9TKftaTEZI35xb
tcNv214uLovTSNoxk2Yd++Ltg1O2vvjD39NXPIZH8et/unz9PEQXSJjO09Pi9AiH
8a+VdAUhcHLNwqea8T6y5N9N9w==
-----END PRIVATE KEY-----';

 $encrMessage = 'd14QunL/M8XwYvsogvjkExe24LP1aYY51OM3ACyl3xJam5DnhwBB4o+cf6/tRaBp+AzoZYQuemd7IP3NjYYEHj23DPaxDzoPNfHoWxNfKC9xqcgoLDywEjJvwtvNaJDAO+mGfNHfsi4TFtsSFRvJ8rkxNOYhoprD2XMIEeklSpFHC3V9hnadHunP+Vgwc5TNRCRPZ1AEcEiSlNmBkvd8pB+iMyAwA7P2tmamrpNQYbEjoQu0mCNPUVrft1QI1IS4XWAL4+HP2vBWV41AttL8XjFxicrR3mXXZVukwiu7PJFPjwW9cLGEgTMkcpBkPZoTGPefiCQYVh4LEq6fYb4kdw==';

    //just for testing if it works with the public/private keys supplied by javascript, which it does
 //$publicKey = openssl_pkey_get_public($pemPublicKey);
 //openssl_public_encrypt('mijn geheimpje',$encr,$publicKey,OPENSSL_PKCS1_OAEP_PADDING); 
 //$encr64 = base64_encode($encr); 
 
 $privateKey = openssl_get_privatekey($pemPrivateKey);
 if (!$privateKey) {
  echo "Cannot get private key";
 }
 
 $encr = base64_decode($encrMessage);
 
 $b = openssl_private_decrypt($encr,$decr,$privateKey,OPENSSL_PKCS1_OAEP_PADDING);
 if (!$b) {
  echo "Cannot decode message";
 }
 echo "String decrypt :". $decr;
?>

2 ответа

Думаю, я решил свою проблему. Я поиграл с phpseclib и получил подсказку о том, что хеш-код неверен. После замены SHA-512 на SHA-1 все заработало. В документации PHP написано, что в crypt libe по умолчанию используется SHA-1. Вещи должны были работать правильно с phpseclib, будучи полностью независимым от open_ssl php lib. Но это не так. Все еще в недоумении, почему это случилось. Но, по крайней мере, у меня есть рабочее решение для работы... Надеюсь, это поможет другим людям, работающим над тем же.

Гидеон

Гидеон,

Рад, что вы нашли свой ответ. Ваша проблема была не с PHP, а с Safari, он не поддерживает OAEP ни с чем, кроме SHA1, по крайней мере, на данный момент.

Если вы собираетесь работать с WebCrypto, вы можете посмотреть на: https://peculiarventures.github.io/pv-webcrypto-tests/ где перечислены комбинации, поддерживаемые каждым браузером.

Мы сделали это как набор тестов, чтобы помочь нам создать https://github.com/PeculiarVentures/webcrypto-liner который облегчает создание совместимых приложений WebCrypto.

Другие вопросы по тегам