JavaScript 公钥/私钥加密

7

我想在JavaScript中生成公私钥对,并使用公钥加密消息和私钥解密消息。

我更喜欢原生浏览器支持而不是外部库。 如何在JavaScript中实现呢?

现代浏览器实现了window.crypto.subtle.generateKey。 我可以使用它来生成ECDSA私钥/公钥以签名/验证消息,这很有效。但我找不到一种方法来使用它来生成用于加密/解密的公私钥对。如果我尝试为推荐的AES-GCM算法使用generateKey,则仅会生成一个cryptoKey,可能可用于加密和解密。但我更喜欢获取一个密钥对(公钥/私钥),而不只是一个密钥。有什么建议吗?

该表列出了当前支持的方法,但似乎没有绿色算法是我需要的: https://diafygi.github.io/webcrypto-examples/


3
由于JavaScript在用户的浏览器中运行,这怎么可能是安全的?任何调试程序都可以很容易地隔离您的私钥,从而使加密的整个目的失效。我的建议是将私钥托管在PHP、ASP或其他服务器端进程中,这样代码就无法被用户浏览。 - Jim
当然可以,但我的问题是,所有标记为绿色的算法都根本不生成私钥。 - Tomas M
@Jim 有时候目标是从服务器上隔离密钥(为用户提供端到端加密)。但这样做的实际操作可能会引发一系列问题。 - TheGreatContini
AES不是对称密钥算法吗? 我只期望它只产生一个私钥。如果要生成公/私钥对,您需要使用不同的算法。 - zero298
3个回答

2
由于ProtonMail的努力,现在浏览器中有一个开源的对称密钥加密实现,网址为:https://openpgpjs.org/。这个实现已经接受了多次安全审计,并且是protonmail.com的基础,因此它有一个相当好的记录和维护者。他们还提供了重要的安全浏览器模型的良好概述。

1
问题是关于非对称密钥加密,而不是对称密钥加密。 - Ozymandias

0

幸运的是,您指向的页面显示支持ECDH - 包括ECDH密钥对生成。这可以用于实现ECIES加密方案。然后,您可以将原始位作为原始AES密钥使用,并将其用于AES-GCM模式。

安全性当然取决于系统,而Java Script加密通常很难正确处理。这种方案应该仅在TLS之外使用,并且即使在此情况下也要非常小心。


我不确定我是否理解你的意思。我需要一个公钥,将其发送给其他人以加密消息,同时我还需要一个私钥,在浏览器中保留该密钥以便稍后解密该消息。使用您的方案,我将拥有ECDH密钥对(公钥和私钥),但这些仅可用于派生密钥。因此,如果我从中派生出一个AES密钥,它能否用作公钥进行加密,并且我能够使用我的私人(ECDH)密钥进行解密? - Tomas M
你需要对方的 可信公钥 才能向他发送加密消息,无论你做什么。如果没有这个公钥,任何人都可以创建自己的密钥对并要求你进行加密。或者,如果你发送给他们私钥,任何人都可以使用它解密消息。一旦收到了对方的公钥,你可以创建一个临时密钥对来生成一个秘密的AES密钥。然后,你将加密的消息和(不可信的)公钥发送给对方。对方也会生成AES密钥并解密消息。从"Once"开始的内容只是对IES的描述。 - Maarten Bodewes

-1

mdn example

请注意,这不是一个完整的代码示例。它只是一个指向 MDN 上相关示例的链接。如果你对该主题感兴趣,可以点击链接查看详细内容。

const encode = (e => e.encode.bind(e))(new TextEncoder)

let { publicKey: pub, privateKey: key } = await crypto.subtle.generateKey({ name: 'ECDH', namedCurve: 'P-521' }, true, ['deriveKey']) // generate key pairs

// get server ecdh public key
let jwk = await fetch('/others public key').then(res=>res.json())
let spub = await crypto.subtle.importKey('jwk', jwk, { name: 'ECDH', namedCurve: 'P-521' }, false, [])

// use spub and key derive a ase key
let gcm = crypto.subtle.deriveKey({ name: 'ECDH', namedCurve: 'P-521', public: spub }, key, { name: 'AES-GCM', length: 256 }, true, ["encrypt", "decrypt"])

// now use gcm to encrypt or decrypt
let text = crypto.subtle.encrypt({ name: 'AES', length: 256 }, gcm, encode('hello world'))

// same on the server


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接