181 lines
7.8 KiB
HTML
181 lines
7.8 KiB
HTML
<!DOCTYPE html>
|
||
<html>
|
||
|
||
<head>
|
||
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||
<meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
|
||
<link href="/jscss/style.css" rel="stylesheet" type="text/css" />
|
||
<script type="text/javascript" charset="utf-8" src="/jscss/theme.js"></script>
|
||
<style>
|
||
.container>div {
|
||
padding: 1em;
|
||
background: var(--bg1);
|
||
margin-bottom: 1em;
|
||
border: 1px solid var(--bg5);
|
||
}
|
||
</style>
|
||
</head>
|
||
|
||
<body>
|
||
<div class="container">
|
||
|
||
<blockquote>生成RSA密钥对</blockquote>
|
||
<div>
|
||
需在https协议下使用,原理是调用现代浏览器的Web Crypto API。
|
||
<br /><button class='btn' onclick="gen()">生成密钥对</button>
|
||
<br />-----BEGIN PRIVATE KEY-----
|
||
<br /><textarea id="rsa_prikey" style="width: 100%; height: 5em;"></textarea>
|
||
-----END PRIVATE KEY-----
|
||
<br />
|
||
<br />-----BEGIN PUBLIC KEY-----
|
||
<br /><textarea id="rsa_pubkey" style="width: 100%; height: 5em;"></textarea>
|
||
-----END PUBLIC KEY-----
|
||
</div>
|
||
|
||
<blockquote>RSA签名</blockquote>
|
||
<div>
|
||
<textarea id="rsa_data" style="width: 100%; height: 5em;">待签名数据</textarea>
|
||
<br /><button class='btn' onclick="hashData()">数据hash</button>
|
||
<br />hash:<input id="rsa_hash" type="text" style="width: 100%;" />
|
||
<br /><button class='btn' onclick="rsasignjs()">RSA 前端签名</button>
|
||
<button class='btn' onclick="rsasignback()">RSA 后端签名</button>
|
||
<br /><span id="sign_from"></span>签名:
|
||
<br /><textarea id="rsa_signature" style="width: 100%; height: 5em;"></textarea>
|
||
</div>
|
||
|
||
<blockquote>RSA验签</blockquote>
|
||
<div>
|
||
<br /><button class='btn' onclick="checksignjs()">RSA 前端验签</button>
|
||
<button class='btn' onclick="checksignback()">RSA 后端验签</button>
|
||
<div id="check_result"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<script type="text/javascript" src="/jscss/ciy.js"></script>
|
||
<script type="text/javascript" src="../common.js"></script>
|
||
<script type="text/javascript">
|
||
'use strict';
|
||
function rsasignback() {
|
||
var postparam = {};
|
||
postparam.prikey = document.getElementById("rsa_prikey").value;
|
||
postparam.hash = document.getElementById("rsa_hash").value;
|
||
ciyfn.callfunc("signrsa", postparam, function (json) {
|
||
document.getElementById("rsa_signature").value = json.sign;
|
||
$5('#sign_from').html(json.from);
|
||
});
|
||
}
|
||
function checksignback() {
|
||
var postparam = {};
|
||
postparam.sign = document.getElementById("rsa_signature").value;
|
||
postparam.pubkey = document.getElementById("rsa_pubkey").value;
|
||
postparam.hash = document.getElementById("rsa_hash").value;
|
||
ciyfn.callfunc("checkrsa", postparam, function (json) {
|
||
document.getElementById("check_result").innerHTML = `php验签结果: ${json.msg}`;
|
||
});
|
||
}
|
||
async function checksignjs() {
|
||
const signature = document.getElementById("rsa_signature").value;
|
||
var publicKeyPem = document.getElementById("rsa_pubkey").value;
|
||
const hash = document.getElementById("rsa_hash").value;
|
||
publicKeyPem = publicKeyPem.replace(/(-----(BEGIN|END) PUBLIC KEY-----|-----(BEGIN|END) RSA PUBLIC KEY-----|\r|\n)/g, '');
|
||
const binaryDerString = atob(publicKeyPem);
|
||
const binaryDer = new Uint8Array(binaryDerString.length);
|
||
for (let i = 0; i < binaryDerString.length; i++) {
|
||
binaryDer[i] = binaryDerString.charCodeAt(i);
|
||
}
|
||
|
||
const publicKey = await window.crypto.subtle.importKey(
|
||
"spki",
|
||
binaryDer,
|
||
{
|
||
name: "RSASSA-PKCS1-v1_5",
|
||
hash: { name: "SHA-256" }
|
||
},
|
||
true,
|
||
["verify"]
|
||
);
|
||
const dataBuffer = hexToArrayBuffer(hash);
|
||
const signatureBuffer = hexToArrayBuffer(signature);
|
||
const result = await window.crypto.subtle.verify(
|
||
"RSASSA-PKCS1-v1_5",
|
||
publicKey,
|
||
signatureBuffer,
|
||
dataBuffer
|
||
);
|
||
document.getElementById("check_result").innerHTML = `js验签结果: ${result ? '成功' : '失败'}`;
|
||
}
|
||
async function rsasignjs() {
|
||
var privateKeyPem = document.getElementById("rsa_prikey").value;
|
||
var data = document.getElementById("rsa_hash").value;
|
||
privateKeyPem = privateKeyPem.replace(/(-----(BEGIN|END) PRIVATE KEY-----|-----(BEGIN|END) RSA PRIVATE KEY-----|\r|\n)/g, '');
|
||
const binaryDerString = atob(privateKeyPem);
|
||
const binaryDer = new Uint8Array(binaryDerString.length);
|
||
for (let i = 0; i < binaryDerString.length; i++) {
|
||
binaryDer[i] = binaryDerString.charCodeAt(i);
|
||
}
|
||
|
||
const privateKey = await window.crypto.subtle.importKey(
|
||
"pkcs8",
|
||
binaryDer,
|
||
{
|
||
name: "RSASSA-PKCS1-v1_5",
|
||
hash: { name: "SHA-256" }
|
||
},
|
||
true,
|
||
["sign"]
|
||
);
|
||
|
||
const encoder = new TextEncoder();
|
||
const dataBuffer = hexToArrayBuffer(data);
|
||
const signature = await window.crypto.subtle.sign(
|
||
"RSASSA-PKCS1-v1_5",
|
||
privateKey,
|
||
dataBuffer
|
||
);
|
||
document.getElementById("rsa_signature").value = arrayBufferToHex(signature);
|
||
$5('#sign_from').html('js');
|
||
|
||
}
|
||
function hashData() {
|
||
const data = document.getElementById("rsa_data").value;
|
||
sha256(data).then(hash => document.getElementById("rsa_hash").value = hash);
|
||
}
|
||
async function gen() {
|
||
const keyPair = await window.crypto.subtle.generateKey({
|
||
name: "RSASSA-PKCS1-v1_5",
|
||
modulusLength: 2048, // RSA-2048
|
||
publicExponent: new Uint8Array([0x01, 0x00, 0x01]), // 65537
|
||
hash: { name: "SHA-256" }
|
||
},
|
||
true,
|
||
["sign", "verify"]
|
||
);
|
||
const exportedpub = await window.crypto.subtle.exportKey("spki", keyPair.publicKey);
|
||
document.getElementById("rsa_pubkey").value = btoa(String.fromCharCode.apply(null, new Uint8Array(exportedpub)));
|
||
|
||
const exportedpri = await window.crypto.subtle.exportKey("pkcs8", keyPair.privateKey);
|
||
document.getElementById("rsa_prikey").value = btoa(String.fromCharCode.apply(null, new Uint8Array(exportedpri)));
|
||
}
|
||
async function sha256(message) {
|
||
const msgBuffer = new TextEncoder().encode(message);
|
||
const hashBuffer = await crypto.subtle.digest('SHA-256', msgBuffer);
|
||
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
||
const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
|
||
return hashHex;
|
||
}
|
||
|
||
function hexToArrayBuffer(hexString) {
|
||
const bytes = new Uint8Array(hexString.length / 2);
|
||
for (let i = 0; i < hexString.length; i += 2) {
|
||
bytes[i / 2] = parseInt(hexString.substr(i, 2), 16);
|
||
}
|
||
return bytes.buffer;
|
||
}
|
||
function arrayBufferToHex(buffer) {
|
||
return Array.from(new Uint8Array(buffer)).map(b => b.toString(16).padStart(2, '0')).join('');
|
||
}
|
||
</script>
|
||
</body>
|
||
|
||
</html> |