JavaScript(crypto.subtle)vs python(pycryptodomex)钥匙包装

发布于 2025-01-20 23:34:44 字数 1184 浏览 3 评论 0 原文

我的公钥加密在 Javascript 中运行良好。我使用的是 RSA-OAEP 封装的 AES-GCM。加密/解密在 Javascript 版本中运行良好。现在我正在尝试加密服务器端的某些内容(python)并使用我现有的解密客户端(window.crypto.subtle)。当我尝试打开密钥并出现以下错误时,它失败了:

OperationError: The operation failed for an operation-specific reason

超级有用的错误消息! python 中的相关代码是:

    from Cryptodome.Cipher import AES
    from Cryptodome.Random import get_random_bytes
    from Cryptodome.Cipher import PKCS1_OAEP
    from Cryptodome.PublicKey import RSA

    keyPub = RSA.import_key(base64.b64decode(public_key))
    rsa_cipher = PKCS1_OAEP.new(keyPub)

    aes = get_random_bytes(16)
    aes_cipher = AES.new(aes, AES.MODE_GCM)

    wrapped = str(base64.b64encode(rsa_cipher.encrypt(aes)), 'ascii')

要解开的代码是:

    window.crypto.subtle.unwrapKey(
        'raw',
        self.from64(wrapped),
        self.keyPair.privateKey,
        {
            name: "RSA-OAEP"
        },
        {
            name: "AES-GCM"
        },
        false,
        ["decrypt"]
    ).then((aesKey) => {

我对 base64 转换很有信心,因为 Python 代码很乐意接受我的公钥,但如果 ASN.1 被搞乱了,则不会。

当我尝试用 Javascript 解开密钥包装时,你能看出为什么 Python 中的密钥包装失败吗?

I have public key encryption working well in Javascript. I'm using AES-GCM wrapped with RSA-OAEP. Encryption/decryption work well in the Javascript version. Now I'm trying to encrypt something server-side (python) and use my existing decryption client-side (window.crypto.subtle). It's failing when I attempt to unwrap the key with this error:

OperationError: The operation failed for an operation-specific reason

Super helpful error messages! The relevant code in python is:

    from Cryptodome.Cipher import AES
    from Cryptodome.Random import get_random_bytes
    from Cryptodome.Cipher import PKCS1_OAEP
    from Cryptodome.PublicKey import RSA

    keyPub = RSA.import_key(base64.b64decode(public_key))
    rsa_cipher = PKCS1_OAEP.new(keyPub)

    aes = get_random_bytes(16)
    aes_cipher = AES.new(aes, AES.MODE_GCM)

    wrapped = str(base64.b64encode(rsa_cipher.encrypt(aes)), 'ascii')

The code to unwrap that is:

    window.crypto.subtle.unwrapKey(
        'raw',
        self.from64(wrapped),
        self.keyPair.privateKey,
        {
            name: "RSA-OAEP"
        },
        {
            name: "AES-GCM"
        },
        false,
        ["decrypt"]
    ).then((aesKey) => {

I'm confident in the base64 conversion, because the Python code happily takes my public key, which it wouldn't if the ASN.1 was messed up.

Can you spot why the key wrap in Python is failing when I try to unwrap it in Javascript?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

调妓 2025-01-27 23:34:44

不幸的是,错误消息非常不具体(WebCrypto API 经常出现这种情况)。但是,发布的 WebCrypto 代码可以正常工作,如以下代码片段所示。

(async () => {

// For this test a 512 bits RSA key was used. In practice, apply RSA key sizes >= 2048 bits for security reasons!!!
var pkcs8DerB64 = "MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEA2gdsVIRmg5IH0rG3u3w+gHCZq5o4OMQIeomC1NTeHgxbkrfznv7TgWVzrHpr3HHK8IpLlG04/aBo6U5W2umHQQIDAQABAkEAu7wulGvZFat1Xv+19BMcgl3yhCdsB70Mi+7CH98XTwjACk4T+IYv4N53j16gce7U5fJxmGkdq83+xAyeyw8U0QIhAPIMhbtXlRS7XpkB66l5DvN1XrKRWeB3RtvcUSf30RyFAiEA5ph7eWXbXWpIhdWMoe50yffF7pW+C5z07tzAIH6DKo0CIQCyveSTr917bdIxk2V/xNHxnx7LJuMEC5DcExorNanKMQIgUxHRQU1hNgjIsXXZoKgfaHaa1jUZbmOPlNDvYYVRyS0CIB9ZZee2zubyRla4qN8PQxCJb7DiICmH7nWP7CIvcQwB"
var wrappedKeyB64 = "LVumLtkD20pvX188VR2QTcDRIOuQlw4vxGFvj9vuEOlAsIvOv/vMcC9C6qCVjI4FuzNWEZ7Xo48Pnu2LnB1vcA=="

var wrappedKey = b642ab(wrappedKeyB64);
var wrappingKey = await importWrappingKey(pkcs8DerB64)
var unwrappedKey = await window.crypto.subtle.unwrapKey(
    'raw',
    wrappedKey,
    wrappingKey,
    {name: "RSA-OAEP"},
    {name: "AES-GCM"},
    false,
    ["decrypt"]
);
console.log(unwrappedKey)
 
// Helper --------------------------------------- 
 
async function importWrappingKey(pkcs8DerB64) {     
    return await window.crypto.subtle.importKey(
        "pkcs8",
        b642ab(pkcs8DerB64),
        {name: "RSA-OAEP", hash: "SHA-1"},
        false,
        ["unwrapKey"]
    );
}
  
function b642ab(base64_string){
    return Uint8Array.from(window.atob(base64_string), c => c.charCodeAt(0));
}

function ab2hex(ab) { 
    return Array.prototype.map.call(new Uint8Array(ab), x => ('00' + x.toString(16)).slice(-2)).join('');
}
  
})();

包装的密钥是使用发布的 Python 代码创建的。


检查您的代码是否存在差异。一个可能的错误可能是关键导入。检查您的代码是否在 importKey() 调用。 Python 代码默认对 OAEP 和 MGF1 摘要使用 SHA-1(请参阅 PKCS1_OAEP.new())。

Unfortunately, the error message is very unspecific (as is often the case with the WebCrypto API). However, the posted WebCrypto code works, as the following code snippet shows.

(async () => {

// For this test a 512 bits RSA key was used. In practice, apply RSA key sizes >= 2048 bits for security reasons!!!
var pkcs8DerB64 = "MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEA2gdsVIRmg5IH0rG3u3w+gHCZq5o4OMQIeomC1NTeHgxbkrfznv7TgWVzrHpr3HHK8IpLlG04/aBo6U5W2umHQQIDAQABAkEAu7wulGvZFat1Xv+19BMcgl3yhCdsB70Mi+7CH98XTwjACk4T+IYv4N53j16gce7U5fJxmGkdq83+xAyeyw8U0QIhAPIMhbtXlRS7XpkB66l5DvN1XrKRWeB3RtvcUSf30RyFAiEA5ph7eWXbXWpIhdWMoe50yffF7pW+C5z07tzAIH6DKo0CIQCyveSTr917bdIxk2V/xNHxnx7LJuMEC5DcExorNanKMQIgUxHRQU1hNgjIsXXZoKgfaHaa1jUZbmOPlNDvYYVRyS0CIB9ZZee2zubyRla4qN8PQxCJb7DiICmH7nWP7CIvcQwB"
var wrappedKeyB64 = "LVumLtkD20pvX188VR2QTcDRIOuQlw4vxGFvj9vuEOlAsIvOv/vMcC9C6qCVjI4FuzNWEZ7Xo48Pnu2LnB1vcA=="

var wrappedKey = b642ab(wrappedKeyB64);
var wrappingKey = await importWrappingKey(pkcs8DerB64)
var unwrappedKey = await window.crypto.subtle.unwrapKey(
    'raw',
    wrappedKey,
    wrappingKey,
    {name: "RSA-OAEP"},
    {name: "AES-GCM"},
    false,
    ["decrypt"]
);
console.log(unwrappedKey)
 
// Helper --------------------------------------- 
 
async function importWrappingKey(pkcs8DerB64) {     
    return await window.crypto.subtle.importKey(
        "pkcs8",
        b642ab(pkcs8DerB64),
        {name: "RSA-OAEP", hash: "SHA-1"},
        false,
        ["unwrapKey"]
    );
}
  
function b642ab(base64_string){
    return Uint8Array.from(window.atob(base64_string), c => c.charCodeAt(0));
}

function ab2hex(ab) { 
    return Array.prototype.map.call(new Uint8Array(ab), x => ('00' + x.toString(16)).slice(-2)).join('');
}
  
})();

The wrapped key was created using the posted Python code.


Inspect your code for differences. A possible bug could be the key import. Check in your code if SHA-1 is explicitly specified as digest in the 3rd parameter of the importKey() call. The Python code uses SHA-1 by default for the OAEP and MGF1 digest (see PKCS1_OAEP.new()).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文