在Nodejs中加密并使用WebCrypto API在客户端上解密

时间:2018-03-23 17:11:48

标签: javascript node.js encryption cryptography webcryptoapi

我正在尝试创建以下流程:

  1. 在客户端上创建密钥对
  2. 将公钥发送到服务器(nodejs)
  3. 使用WebCryptoAPI polyfill https://github.com/PeculiarVentures/node-webcrypto-ossl
  4. 加密服务器上的字符串
  5. 将加密数据发送回客户端进行解密
  6. 我正在努力(很长一段时间)使用数据类型。

    下面是代码,首先生成密钥(客户端):

    item_all

    然后导出:

    // some reusable settings objects
    const crypto = window.crypto.subtle;
    let publicKeyToExport = {};
    let privateKeyToStore = {};
    
    // function called to create a keypair
    const generateKeypair = () => {
        crypto.generateKey({
            name : 'RSA-OAEP',
            modulusLength : 2048, //can be 1024, 2048, or 4096
            publicExponent : new Uint8Array([0x01, 0x00, 0x01]),
            hash : {name: 'SHA-256'}, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512"
        }, true, ['encrypt', 'decrypt']
        ).then((key) => {
            publicKeyToExport = key.publicKey;
            privateKeyToStore = key.privateKey;
            console.log(key);
        }).catch((err) => {
            console.error(err);
        });
    }; 
    

    保存密钥:

    // function to export the generate publicKey
    const exportPublicKey = (publicKey) => {
        crypto.exportKey('jwk', publicKey)
            .then((keydata) => {
                fetch('/key2', {
                    method : 'POST',
                    mode : 'cors',
                    body : JSON.stringify(keydata),
                    headers : new Headers({
                        'Content-Type' : 'application/json'
                    })
                }).then(res => res.json())
                .catch(err => console.error(err))
                .then(res => console.log(res));
                console.log(keydata);
            })
            .catch((err) => {
                console.log(err);
        });
    };
    

    在服务器上加密:

    app.post('/key2', (req, res) => {
        webcrypto.subtle.importKey(
            'jwk', req.body, 
            {
                name : 'RSA-OAEP',
                hash : {name : 'SHA-256'},
            },
            false,
            ['encrypt']
        ).then((publicKey) => {
            keyStorage.setItem('alicePubKey', publicKey);
            if(publicKey == keyStorage.getItem('alicePubKey'));
            res.json({ 'success' : 'key received and saved' });
            console.log('saved key from client: ' + publicKey);
            return; 
        })
        .catch((err) => {
            console.error(err);
        });
    });
    

    获取加密数据并解密 - 不工作:)

    app.get('/challenge', (req, res) => {
        let challengeFromServer = null;
        let key = keyStorage.getItem('alicePubKey');
        let buf = new Buffer.from('decryptthis!');
    
        webcrypto.subtle.encrypt(
            {
                name : 'RSA-OAEP'
            }, key, buf
        )
        .then((encrypted) => {
            console.log('challenge created: ' + encrypted);
            res.json({'challenge' : new Uint8Array(encrypted) })
        })
        .catch((err) => {
            console.error(err);
        })
    

    以下是我认为的问题!

    const requestChallenge = () => {
        fetch('/challenge')
            .then((res) => {
                return res.json();
            })
            .then((data) => {
                console.log(data);
                console.log(ArrayBuffer.isView(data.challenge))
                console.log(new ArrayBuffer(data.challenge))
                crypto.decrypt({
                    name : 'RSA-OAEP'
                }, privateKeyToStore, new ArrayBuffer(data.challenge))
                .then((decrypted)=>{
                    console.log(decrypted)
                })
                .catch(err => console.error(err));
            })
            .catch(err => console.error(err));
    };
    

    小更新:

    console.log(ArrayBuffer.isView(data.challenge)) // false
    console.log(new ArrayBuffer(data.challenge)) // empty
    

2 个答案:

答案 0 :(得分:0)

考虑一下处理交换问题的更高级别的库;例如js-jose https://github.com/square/js-jose/tree/master/examples或PKIjs https://pkijs.org/examples/CMSEnvelopedExample.html

答案 1 :(得分:0)

解决!

问题在于数据类型。

如果有人遇到问题,解决此问题的方法是确保在您的服务器上将密文作为缓冲区发送,我的快递应用程序:

res.write(new Buffer(encrypted), 'binary')
res.end(null, 'binary')

在客户端接收并解码,如下所示:

const decryptedReadable = new TextDecoder().decode(decrypted)

快乐的编码。