JavaScriptでHTTPSなしで暗号化したデータを送りたい。

# 目的

## 使用するライブラリ
https://github.com/kjur/jsrsasign

jsrsasignはJavaScriptのライブラリでブラウザサイド、node.js側のサーバーサイドで以下のような暗号化を行えます。

RSA/RSAPSS/ECDSA/DSA signing/validation, ASN.1, PKCS#1/5/8 private/public key, X.509 certificate, CRL, OCSP, CMS SignedData, TimeStamp, CAdES JSON Web Signature/Token/Key

## 事前準備
opensslで公開鍵と秘密鍵を作成します。

```
openssl genrsa 2024 > secret.key 
openssl rsa -pubout < secret.key > public.key
```

## サンプル
以下の例ではブラウザ側で公開鍵で暗号化したデータをnode.js側で秘密鍵で復号化しています。

```javascript:server.js
const express = require("express");
const app = express();
const fs = require('fs');
const bodyParser = require('body-parser')

const port = 3000; // 1024以下にした場合は管理者権限が必要になります.

const http = require("http");
const server = http.createServer(app);

const rs = require('jsrsasign');
const　rsu = require('jsrsasign-util')
/**
openssl genrsa 2024 > secret.key 
openssl rsa -pubout < secret.key > public.key
 */
const secretKey = rs.KEYUTIL.getKey(rsu.readFile('secret.key'))

app.use(express.static(__dirname + "/public"));
app.use(bodyParser.urlencoded({ extended: true }))
app.use(bodyParser.json())

app.post('/login', async (req, res) => {
  console.log(req.body.data)
  const data = JSON.parse(rs.KJUR.crypto.Cipher.decrypt(req.body.data,secretKey,'RSA'))
  console.log(data.time, (new Date).getTime(), (new Date).getTime()-data.time)
  if ((new Date).getTime()-data.time > 1000 * 60) {
    res.status(401).send('時間切れ')
    return
  }
  const result = {
    message: '応答：' + data.message,
  }

  res.status(200).send(result)
})

server.listen(port, () => {
  console.log(`Server is running on port ${port}`);
});
```

```html:public/index.html
<!DOCTYPE html>
<html>
  <head>
    <title>シンプルチャット</title>
    <meta charset="UTF-8" />
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jsrsasign/8.0.20/jsrsasign-all-min.js"></script>
  </head>
  <body>
    <div id="app">
      <div>
        <input v-model="sendName"></input>
        <button v-on:click="send">Send</button>
      </div>
    </div>
<script>
  console.log('app')
const app = new Vue({
  el: '#app',
  data: {
    sendName : "abcde"
  },
  computed: {
  },
  created : function() {
  },
  methods: {
    send : function() {
      console.log('send')
      // 以下のコマンドで作った公開キー
      // openssl genrsa 2024 > secret.key 
      // openssl rsa -pubout < secret.key > public.key
      const publicKeyStr = `
-----BEGIN PUBLIC KEY-----
MIIBHjANBgkqhkiG9w0BAQEFAAOCAQsAMIIBBgKB/gC1UZYJkhTJpfitHn0Jv6Ms
b15tHhsYO1DHICrRwNMkePCm1hWUbK3aG+Q173SrO1yR1qadPsz3heMbDwwqaU3t
0CMsdaLzPdCLiTT7HFXHkc1TI/ltwg0NAo4YrHN89WFk7/zGquy8ekeZFX21b2Xf
sqtiQCkHf6W2XIOgSo5AbH8V6wPgzCPBn1hu2lL5btF10Rbt9KkW/3WiRt/U06wD
5QgwJZ4A140dzea3mBSH6r0bje9h3nHmzqpwA5a9QxSL1HYH4E9VEV8FDwIAI3Qw
O2kxvpTKG0qst3i6nxcvRHmeWFakPnCqnyuqV31FJVf8cebbMlVePUb2IfCbAgMB
AAE=
-----END PUBLIC KEY-----
`
      console.log(this.sendName)
      const data = {
        message: this.sendName,
        time: new Date().getTime()
      }
      const publicKey = KEYUTIL.getKey(publicKeyStr)
      const encyptData = KJUR.crypto.Cipher.encrypt(JSON.stringify(data), publicKey, 'RSA')

      axios.post('/login', {data: encyptData})
      .then(function (response) {
        alert(JSON.stringify(response.data))
      })
      .catch(function (error) {
        alert(error)
      })
    },

  }
})

</script>
  </body>
</html>

```

## まとめ
jsrsasignを利用することでブラウザ側でも暗号化できます。
でも、素直にHTTPS化した方がいいと思うので使うことはないでしょう。