目的
使用するライブラリ
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側で秘密鍵で復号化しています。
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}`);
});
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化した方がいいと思うので使うことはないでしょう。