首页 > 解决方案 > .Net Core 和 WebCrypto 握手

问题描述

我想通过以下步骤初始化服务器(.NET Core 3.1)和客户端浏览器应用程序(使用 WebCryptoAPI 的 JS)之间的安全通道:

  1. 服务器将其公共 RSA 密钥发送K给客户端
  2. 客户端使用其公共 RSA 密钥加密L并将K其发送到服务器
  3. 服务器解密获取的消息L,使用 AES 密钥加密L并将其发送回客户端
  4. 客户端解密包含 AES 密钥的消息,然后他们就可以安全地交谈

到目前为止,我设法达到了第二步:

TypeScript 客户端请求服务器的公钥

const hubConnection = new SignalR.HubConnectionBuilder().withUrl("/hub/myhub").build();
Crypto.generateKey({name: "RSA-OAEP", 
                    modulusLength: 2048, 
                    publicExponent: new Uint8Array([1, 0, 1]),
                    hash: "SHA-512"}, 
                    true,
                    ["encrypt", "decrypt"])
.then(key => {
    clientRSA = key;
    console.debug("Client RSA:", clientRSA);
    return hubConnection.start();
})
.then(() => hubConnection.invoke("requestServerKey"));

C# 后端创建一个新的密钥和答案

public class MyHub : Hub<IMyHub>
{
    public override async Task OnConnectedAsync()
    {
        using var rsa = RSA.Create(KeySize);
        //store it to in-memory DB
    }
}

public void RequestServerKey()
{
    RSA rsa = DB.Get(Context.ConnectionId);
    Clients.Caller.SetServerKey(Convert.ToBase64String(rsa.ExportSubjectPublicKeyInfo()));
}

Typescript 客户端接收公钥

hubConnection.on('setServerKey', (data: string) => {
    const buffer = Uint8Array.from(atob(data), c => c.charCodeAt(0));
    Crypto.importKey("spki", buffer, { name: "RSA-OAEP", hash: "SHA-512"}, false, ['encrypt'])
    .then(rsaPublicKey => { //by some reason I can't pull this promise out to the zero level
        serverKey = rsaPublicKey;
        return Crypto.exportKey("spki", clientRSA.publicKey);
    })
    //THE FOLLOWING CALL FAILS
    .then(clientPublicKey => Crypto.encrypt({name: "RSA-OAEP"}, serverKey, clientPublicKey))
    .then(message => {
        const str = btoa(String.fromCharCode(...new Uint8Array(message)));
        hubConnection.invoke("requestSymmetricKey", str);
    })
});

似乎服务器的公钥已成功导入,WebCrypto API但是当我尝试使用它在将客户端的公钥发送到服务器之前对其进行加密时,它失败了。我也试过这个wrapKey方法,但错误是一样的。我得到以下信息:

index.js:1 Uncaught Error: The error you provided does not contain a stack trace.
    at L (index.js:1)
    at Y (index.js:1)
    at index.js:1
    at index.js:1
    at l (index.js:1)

home:1 Uncaught (in promise) DOMException
Promise.then (async)
...

所以我正在寻找任何暗示这里可能是什么问题。我尝试了初始化参数的各种组合,查看了所有中间值,但没有任何迹象表明可能出了什么问题。除了我犯了一些愚蠢的复制错误外,我的代码应该遵循以下示例:

任何帮助表示赞赏!

标签: encryption.net-corersawebcrypto-api

解决方案


所以我在以下帖子的帮助下找到了解决方案:https ://crypto.stackexchange.com/questions/42097/what-is-the-maximum-size-of-the-plaintext-message-for-rsa-oaep

由于服务器的公钥是 2048 位并使用 SHA-512,因此最大消息长度仅为 126 字节。但是,我尝试传输的消息是 294 字节。遗憾的是 API 没有专门的错误消息,因为它可以很容易地自动检查。

在对我的问题的评论中进行了讨论之后,我将程序简化为:

  1. 服务器在其 API 中公开其公共 RSA 密钥并将其(或其哈希)发布到其他独立位置以进行验证
  2. 客户端生成对称 AES 密钥,通过服务器的公共 RSA 密钥对其进行加密并发送
  3. 服务器使用其私有 RSA 密钥解密对称 AES 密钥,然后他们就可以安全地交谈

现在我希望在 JS 和 C# 之间完成所有工作。


推荐阅读