js读国密SM2的x509证书的公钥

jsrsasign很好用但没支持sm2的椭圆曲线,可以自己加一下支持。

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width; initial-scale=1.0; minimum-scale=1.0; maximum-scale=2.0">
<title>国密SM2的x509证书读公钥XY</title>
<style> 

*{margin:0; padding:0; font-size:12px; font-family:微软雅黑;}
div{word-break: break-all; padding:10px;}

</style>
<script language="JavaScript" type="text/javascript" src="../../res/js/jsrsasign-all-min.js"></script>
<script type="text/javascript">

//基础js使用:https://kjur.github.io/jsrsasign/
//椭圆曲线参数:https://github.com/wechat-miniprogram/sm-crypto/

//html转义
//HtmlUtil.htmlEncodeByRegExp(data)
var HtmlUtil = {
		
		 /*1.用正则表达式实现html转码*/
		 htmlEncodeByRegExp:function (str){  
		     var s = "";
		     if(str.length == 0) return "";
		     s = str.replace(/&/g,"&amp;");
		     s = s.replace(/</g,"&lt;");
		     s = s.replace(/>/g,"&gt;");
		     s = s.replace(/ /g,"&nbsp;");
		     s = s.replace(/\'/g,"&#39;");
		     s = s.replace(/\"/g,"&quot;");
		     return s;  
		 },

		 /*2.用正则表达式实现html解码*/
		 htmlDecodeByRegExp:function (str){  
		     var s = "";
		     if(str.length == 0) return "";
		     s = str.replace(/&amp;/g,"&");
		     s = s.replace(/&lt;/g,"<");
		     s = s.replace(/&gt;/g,">");
		     s = s.replace(/&nbsp;/g," ");
		     s = s.replace(/&#39;/g,"\'");
		     s = s.replace(/&quot;/g,"\"");
		     return s;  
		 }
	};

if (!String.prototype.trim) {
	  String.prototype.trim = function () {
	    return this.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
	};
}

KJUR.crypto.ECParameterDB.regist(
	"sm2p256v1", // name / p = 2^128 - 2^97 - 1
	256,
	"FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF", // p
	"FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC", // a
	"28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93", // b
	"FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123", // n
	"1", // h
	"32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7", // gx
	"BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0", // gy
	[], // alias
	"", // oid
	"sm2p256v1 : sm2"); // info


KJUR.crypto.ECDSA.getName = function(s) {
	if (s === "2a811ccf5501822d") return "sm2p256v1"; 
	if (s === "2b8104001f") return "secp192k1"; // 1.3.132.0.31
	if (s === "2a8648ce3d030107") return "secp256r1"; // 1.2.840.10045.3.1.7
	if (s === "2b8104000a") return "secp256k1"; // 1.3.132.0.10
	if (s === "2b81040021") return "secp224r1"; // 1.3.132.0.33
	if (s === "2b81040022") return "secp384r1"; // 1.3.132.0.34
	if ("|secp256r1|NIST P-256|P-256|prime256v1|".indexOf(s) !== -1) return "secp256r1";
	if ("|secp256k1|".indexOf(s) !== -1) return "secp256k1";
	if ("|secp224r1|NIST P-224|P-224|".indexOf(s) !== -1) return "secp224r1";
	if ("|secp384r1|NIST P-384|P-384|".indexOf(s) !== -1) return "secp384r1";
	return null;
};

var openFile2 = function(event) { //https://www.javascripture.com/FileReader
    var input = event.target;

    var file = input.files[0];
    if(file === undefined) return;
    var name = file.name;

    var reader = new FileReader();
    reader.readAsArrayBuffer(file);
    reader.onload = function(){
    	var arrayBuffer = reader.result;

    	var text = new TextDecoder("utf-8").decode(arrayBuffer);
    	if(text.indexOf("-----BEGIN") != -1){
			var key = KEYUTIL.getKey(text);
    	}

		if(key == null){
			var key = KEYUTIL.getKey(ArrayBuffertohex(arrayBuffer), null, "x509pub");
		}

		if(key == null){
			alert("解析失败");
			return;
		}
		
		//console.log(key);
		if (!key.getPublicKeyXYHex) {
			alert("证书能解析,但公钥非sm2公钥");
			return;
		}
		var xy = key.getPublicKeyXYHex();
		//console.log(xy);
		//console.log(xy.x);
		//console.log(xy.y);
		
		var outputElmt = document.getElementById('output2');
		var outStr = "结果:\nx:" + xy.x + "\ny:" + xy.y;
		outputElmt.innerHTML = HtmlUtil.htmlEncodeByRegExp(outStr).replace(/\n/g, "<br>");
    }
}

var clearResult = function() { 
	var outputElmt = document.getElementById('output2');
	outputElmt.innerHTML = "";
}

</script>

</head>
<body>
<div>
国密SM2的x509证书读公钥XY(๑•́ωก̀๑)<br>
浏览器要求较高,建议用高版本chrome。<br>
--------------------<br>
</div>
<div>
<input type='file' onchange='openFile2(event)'> <input type="button" value="清空结果" onclick="clearResult()"/>
</div>
<div id='output2'></div>
</body>
</html>

### 国密SM2公钥算法的具体实现及原理 #### 1. 椭圆曲线参数定义 国密SM2基于椭圆曲线上离散对数问题的安全性。所选的椭圆曲线方程形式为 \(y^2 \equiv x^3 + ax + b\pmod{p}\),其中\(a\)、\(b\)以及模数\(p\)都是固定的常量,在国家标准中已经明确规定[^1]。 #### 2. 密钥对生成过程 为了创建一对用于加密通信的钥匙——即公开可分享的公钥和必须保密保存起来的私钥,会随机选取一个小于阶\(n\)(另一个由官方指定的大素数)的秘密整数值d作为私钥;接着利用选定的基点G通过多次执行椭圆曲线上的加法操作来计算对应的公钥Q=dG。 #### 3. 加密机制解析 当发送者想要向接收者传递消息m时,先要获取对方的公钥PUB_KEY=Q。之后选择临时私钥t并将它转换成相应的临时公钥T=tG。随后依据特定规则构造两个分量C1=T,C2=m⊕H_1(C1||ID_A||k),C3=k,这里H_1表示采用SM3杂凑算法得到固定长度的消息摘要,ID_A代表接收者的身份标识符,k则是通过对共享秘密Z=(x_T,y_T)=tQ应用KDF派生出来的密钥材料[^2]。 ```python def sm2_encrypt(public_key, message): t = random.randint(1, n - 1) # Generate ephemeral private key T = ec_point_mul(G, t) # Calculate ephemeral public key Z = ec_point_mul(public_key, t) k = KDF(Z) C1 = T C2 = xor(message, hash_function(concatenate(C1, ID_A, k))) C3 = k return (C1, C2, C3) ``` #### 4. 解密流程说明 拥有匹配私钥d的人可以轻松恢复原始明文。因为只有他知道如何从收到的数据包里提取出正确的k值:\[k'=KDF((x_{C1}, y_{C1}) * d)\],进而完成最终解码工作。\[(M') = C2 ⊕ H'(C1 || ID_A || k')\] ```python def sm2_decrypt(private_key, ciphertext): C1, C2, _ = ciphertext Z_prime = ec_point_mul(C1, private_key) k_prime = KDF(Z_prime) M_prime = xor(C2, hash_function(concatenate(C1, ID_A, k_prime))) return M_prime ```
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值