简体   繁体   English

通过WebCryptoAPI而不是浏览器化的节点加密模块在浏览器中生成ECDH密钥

[英]Generating ECDH keys in the browser through WebCryptoAPI instead of the browserified node crypto module

I have a very tiny node script to create a public/private key Is there any way to do it on the client side without having to browserify hole crypto module? 我有一个非常小的节点脚本来创建公钥/私钥是否有任何方法可以在客户端进行,而无需浏览孔加密模块?

var crypto    = require('crypto');

var userCurve = crypto.createECDH('prime256v1');
var userPublicKey = userCurve.generateKeys()
var userPrivateKey = userCurve.getPrivateKey();

I have tried this so far: 到目前为止我试过这个:

// https://github.com/diafygi/webcrypto-examples#ecdh---generatekey
window.crypto.subtle.generateKey(
    {
        name: "ECDH",
        namedCurve: "P-256", //can be "P-256", "P-384", or "P-521"
    },
    true, //whether the key is extractable (i.e. can be used in exportKey)
    ["deriveKey", "deriveBits"] //can be any combination of "deriveKey" and "deriveBits"
)
.then(function(key){
    //returns a keypair object
    console.log(key);
    console.log(key.publicKey);
    console.log(key.privateKey);
})
.catch(function(err){
    console.error(err);
});

But it looks nothing like the node version when i log it 但是当我记录它时它看起来与节点版本完全不同

Let's do a complete elliptic curve Diffie-Hellman (ECDH) exchange to establish a shared secret between two parties. 让我们做一个完整的椭圆曲线Diffie-Hellman(ECDH)交换,以建立双方之间的共享秘密。 Alice uses Node.js and Bob sits at his browser (a recent version of Chrome or Firefox). Alice使用Node.js和Bob坐在他的浏览器(最新版本的Chrome或Firefox)上。 (No need to browserify anything.) (无需浏览任何东西。)

(1) Alice generates a private and public key. (1)Alice生成私钥和公钥。

const crypto = require('crypto');

const alice = crypto.createECDH('prime256v1');
alice.generateKeys()

const alicePublicKey = alice.getPublicKey('hex')
const alicePrivateKey = alice.getPrivateKey('hex')

console.log(`publicKey: ${alicePublicKey}`)
console.log(`privateKey: ${alicePrivateKey}`)

Example output: 示例输出:

publicKey: 043a3770a8068738ded16c9409e1a6fbf6dde2360ac5b3fd3e5bb8d9fd6adaed6ea83ff5153f58ae13098e86da89df1beb14ef46388d3df76e8fe2ee0ff9e926d5
privateKey: 03ce9cb317c8761699f174943dc9b2d2b7991515b48216a4c677fcf5ee879f2c

(2) Alice sends her public key to Bob ( 043a3770... ). (2)Alice将她的公钥发送给Bob( 043a3770... )。 Bob has written some helpers to convert hex strings to Uint8Arrays and buffers to hex strings. Bob编写了一些帮助器来将十六进制字符串转换为Uint8Arrays ,将缓冲区转换为十六进制字符串。

const hex2Arr = str => {
    if (!str) {
        return new Uint8Array()
    }
    const arr = []
    for (let i = 0, len = str.length; i < len; i+=2) {
        arr.push(parseInt(str.substr(i, 2), 16))
    }
    return new Uint8Array(arr)
}

const buf2Hex = buf => {
    return Array.from(new Uint8Array(buf))
        .map(x => ('00' + x.toString(16)).slice(-2))
        .join('')
}

(3) Bob receives Alices's key and computes the shared secret (3)Bob接收Alices的密钥并计算共享密钥

  • He generates his own private and public key 他生成自己的私钥和公钥
  • He exports his public key and sends it to Alice 他导出他的公钥并将其发送给Alice
  • He imports Alice's public key 他导入了Alice的公钥
  • He computes the shared secret using his private and Alice's public key 他使用私人和Alice的公钥计算共享秘密

     // Alice's public key (received over an [insecure] connection) const alicePublicKeyHex = '043a3770a8068738ded16c9409e1a6fbf6dde2360ac5b3fd3e5bb8d9fd6adaed6ea83ff5153f58ae13098e86da89df1beb14ef46388d3df76e8fe2ee0ff9e926d5' const alicePublicKey = hex2Arr(alicePublicKeyHex) console.log(`Alice's publicKey: ${alicePublicKeyHex}`) let bob = null // generate Bob's private and public key window.crypto.subtle.generateKey( { name: 'ECDH', namedCurve: 'P-256' }, false, // no need to make Bob's private key exportable ['deriveKey', 'deriveBits']) .then(bobKey => { bob = bobKey // export Bob's public key return window.crypto.subtle.exportKey( 'raw', bobKey.publicKey ) }) .then(bobPublicKeyExported => { const bobPublicKeyHex = buf2Hex(bobPublicKeyExported) // display and send Bob's public key to Alice console.log(`Bob's publicKey: ${bobPublicKeyHex}`) // import Alice's public key return window.crypto.subtle.importKey( 'raw', alicePublicKey, { name: 'ECDH', namedCurve: 'P-256' }, true, []) }) .then(aliceKeyImported => { // use Alice's imported public key and // Bob's private key to compute the shared secret return window.crypto.subtle.deriveBits( { name: 'ECDH', namedCurve: 'P-256', public: aliceKeyImported }, bob.privateKey, 256) }) .then(sharedSecret => { const sharedSecretHex = buf2Hex(sharedSecret) console.log(`sharedSecret: ${sharedSecretHex}`) }) .catch(err => { console.log(err) }) 

Example output: 示例输出:

Alice's publicKey: 043a3770a8068738ded16c9409e1a6fbf6dde2360ac5b3fd3e5bb8d9fd6adaed6ea83ff5153f58ae13098e86da89df1beb14ef46388d3df76e8fe2ee0ff9e926d5
Bob's publicKey: 04aeceba6ae783c9b705833c2fa8822281f47f6f36bc867e4d398fa7a744d4fc63a010cbce1e6c9ac8858ad376a24ee8551615560f01c8bb63c86335c046b18962
sharedSecret: c26c9f370f001a947d7fec4dc9282d3e9ea718e1de487eb4f6fa7d6f0a311b97

(4) Alice receives Bob's public key ( 04aece... ). (4)Alice收到Bob的公钥( 04aece... )。 She computes the shared secret as well. 她也计算共享秘密。

const crypto = require('crypto')
const alice = crypto.createECDH('prime256v1')

// Alice's privateKey (generated previously)
const alicePrivateKey = '937cdd11062b612ff3cb3e4a3c183254b9728b4c8c3a64de799ed196b672734b'

// Bob's publicKey transmitted to Alice
const bobPublicKey = '04aeceba6ae783c9b705833c2fa8822281f47f6f36bc867e4d398fa7a744d4fc63a010cbce1e6c9ac8858ad376a24ee8551615560f01c8bb63c86335c046b18962'

// set Alice's private key (not needed if continuing from (1))
alice.setPrivateKey(alicePrivateKey, 'hex')

const sharedSecret = alice.computeSecret(bobPublicKey, 'hex', 'hex')
console.log(`sharedSecret: ${sharedSecret}`)

Examle output: 考试输出:

sharedSecret: c26c9f370f001a947d7fec4dc9282d3e9ea718e1de487eb4f6fa7d6f0a311b97

The secret is shared (the same). 秘密是共享的(相同)。

(5) The shared secret is typically used to derive a symmetric key for encrypting messages between Alice and Bob (and they communicated happily ever after). (5)共享秘密通常用于导出用于加密Alice和Bob之间的消息的对称密钥(并且他们之后通过愉快的方式进行通信)。

Remarks: 备注:

  • Usually there is no need to display or export the private key. 通常不需要显示或导出私钥。 Alice would typically continue the computation of the shared secret from step (1) (and omit alice.setPrivateKey(alicePrivateKey, 'hex') ). Alice通常会继续计算步骤(1)中的共享秘密(并省略alice.setPrivateKey(alicePrivateKey, 'hex') )。

  • As the shared secret is most often used to derive a symmetric key, there is window.crypto.subtle.deriveKey and deriveBits can be ommitted. 作为共享秘密是最经常用来导出一个对称密钥,有window.crypto.subtle.deriveKeyderiveBits可以忽略。 deriveBits was used here to illustrate that Alice and Bob indeed agreed on a shared secret. 这里使用deriveBits来说明Alice和Bob确实同意共享秘密。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM