我正在开发一个会话加密方案,但是当我尝试使用私钥解密会话密钥时,我收到一个
OperationError
。
// This method generates the keys
static async generateKeysForUser(): Promise<{ publicKey: string, privateKey: string }> {
const keyPair = await window.crypto.subtle.generateKey(
{
name: "RSA-OAEP",
modulusLength: 2048,
publicExponent: new Uint8Array([1, 0, 1]), // 65537
hash: "SHA-1",
},
true,
["encrypt", "decrypt"]
);
const publicKey = await window.crypto.subtle.exportKey("jwk", keyPair.publicKey);
const privateKey = await window.crypto.subtle.exportKey("jwk", keyPair.privateKey);
const publicKeyStr = JSON.stringify(publicKey);
const privateKeyStr = JSON.stringify(privateKey);
await this.storeKeys(privateKeyStr, publicKeyStr);
return publicKey;
}
// This method encrypts the session on the backend
public static function generateSessionKey($length = 32)
{
return bin2hex(random_bytes($length)); // 32 bytes = 256 bits
}
public static function jsonToPem($publicKeyJson)
{
$jwkObject = new JWK($publicKeyJson);
$rsaKey = RSAKey::createFromJWK($jwkObject);
return $rsaKey->toPEM();
}
public static function encryptSessionKey($sessionKey, $publicKeyJson): string
{
$publicKeyPem = self::jsonToPem($publicKeyJson);
$publicKey = openssl_pkey_get_public($publicKeyPem);
openssl_public_encrypt($sessionKey, $encryptedSessionKey, $publicKey);
return base64_encode($encryptedSessionKey);
}
// This method decrypts the session key on the front end
private static async importKey(jwk: JsonWebKey, keyType: 'private' | 'public'): Promise<CryptoKey> {
console.log(jwk);
let operation = keyType == 'private' ? 'decrypt' : 'encrypt';
console.log(keyType, operation);
let result = await window.crypto.subtle.importKey(
"jwk",
jwk,
{
name: "RSA-OAEP",
hash: "SHA-1"
},
true,
[operation]
);
console.log(result);
return result;
}
static async decryptSessionKey(encryptedSessionKeyBase64: string, jwk: JsonWebKey): Promise<ArrayBuffer | null> {
try {
let privateKey = await this.importKey(jwk, "private");
const encryptedSessionKey = Uint8Array.from(atob(encryptedSessionKeyBase64), c => c.charCodeAt(0));
console.log('Encrypted Session Key (Uint8Array):', encryptedSessionKey);
console.log('Private Key:', privateKey);
const result = await window.crypto.subtle.decrypt(
{
name: "RSA-OAEP"
},
privateKey,
encryptedSessionKey
);
console.log('Decrypted Result (ArrayBuffer):', result);
return result;
} catch (e) {
console.error('Decryption failed:', e);
return null;
}
}
我已经尝试检查后端和前端的密钥是否匹配,以确保发送正确的密钥,并且我还尝试将密钥生成密码从 SHA-256 更改为 SHA-1。
我发现问题出在 PADDING 上
public static function encryptSessionKey($sessionKey, $publicKeyJson): string
{
$publicKeyPem = self::jsonToPem($publicKeyJson);
$publicKey = openssl_pkey_get_public($publicKeyPem);
openssl_public_encrypt($sessionKey, $encryptedSessionKey, $publicKey,OPENSSL_PKCS1_OAEP_PADDING );
return base64_encode($encryptedSessionKey);
}
我发现了问题;我使用了错误的填充进行加密。我切换到 OPENSSL_PKCS1_OAEP_PADDING 并且它有效。