问题
I've been rather busy trying to get a secure exchange established between a browserclient, using the webcrypto api and PHP server using openssl. I've broken down things as much as I can. I wrote some javascript to generate a keypair, print out the values private and public, encrypt a simple string and print it out as well.
I've copied the values straight to a simple php script. Trying to decode it with the values from the javascipt.
Encoding and decoding works properly in the javascript (as posted below), decoding in php does not (also posted beneath the javascript). I also can't seem to find where to set the SHA-512 declaration in PHP. Does anyone have experience with this kind of exchange and perhaps point me in the right direction. RSA-OAEP was chosen because it's supported by chrome, mozilla, IE11 and Safari as well as PHP.
Kind regards, Gideon
// 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;
?>
回答1:
Guess I solved my own problem. I played around with phpseclib and got a hint about the hash being wrong. After replacing SHA-512 with SHA-1 it finally worked. In the PHP documentation its says that the crypt libe defaults to SHA-1. Things should have worked properly with phpseclib, being completely independent of the open_ssl php lib. But it didn't. Still at a loss why this happend. But at least I have a working solution to work from... Hope this helps other people working on the same thing.
Gideon
回答2:
Gideon,
Glad you found your answer. Your issue was not with PHP but with Safari, it does not support OAEP with anything other than SHA1, at least at this time.
If you are going to work with WebCrypto you may want to look at: https://peculiarventures.github.io/pv-webcrypto-tests/ which enumerates the combinations supported by each browser.
We did this as a test suite to help us build https://github.com/PeculiarVentures/webcrypto-liner which makes it easier to build interoperable WebCrypto applications.
来源:https://stackoverflow.com/questions/29615420/rsa-oaep-sha-512-encrypt-decrypt-from-javascriptwebcrypt-api-to-php-openssl