javascript实现国密sm4算法(支持微信小程序)

概述:

本人前端需要实现sm4计算的功能,最好是能做到分多次计算。
本文所写的代码在现有sm4的C++代码,反复测试对比计算过程参数,成功改造成sm4的javascript代码,并成功验证好分多次计算sm4数据

测试平台:

已经在如下环境中测试通过,其他平台(浏览器)应该也不会有问题:
1、nodejs中node.exe运行
本js脚本按照版本ES5编写代码,当然微信小程序也能用。

功能代码:

function strSm4CtxParams() {this.sk;
};var FK = [0xa3b1bac6,0x56aa3350,0x677d9197,0xb27022dc];
var CK =  [  0x00070e15,0x1c232a31,0x383f464d,0x545b6269,  0x70777e85,0x8c939aa1,0xa8afb6bd,0xc4cbd2d9,  0xe0e7eef5,0xfc030a11,0x181f262d,0x343b4249,  0x50575e65,0x6c737a81,0x888f969d,0xa4abb2b9,  0xc0c7ced5,0xdce3eaf1,0xf8ff060d,0x141b2229,  0x30373e45,0x4c535a61,0x686f767d,0x848b9299,  0xa0a7aeb5,0xbcc3cad1,0xd8dfe6ed,0xf4fb0209,  0x10171e25,0x2c333a41,0x484f565d,0x646b7279  
]; var SboxTable = [  0xd6,0x90,0xe9,0xfe,0xcc,0xe1,0x3d,0xb7,0x16,0xb6,0x14,0xc2,0x28,0xfb,0x2c,0x05,  0x2b,0x67,0x9a,0x76,0x2a,0xbe,0x04,0xc3,0xaa,0x44,0x13,0x26,0x49,0x86,0x06,0x99,  0x9c,0x42,0x50,0xf4,0x91,0xef,0x98,0x7a,0x33,0x54,0x0b,0x43,0xed,0xcf,0xac,0x62,  0xe4,0xb3,0x1c,0xa9,0xc9,0x08,0xe8,0x95,0x80,0xdf,0x94,0xfa,0x75,0x8f,0x3f,0xa6,  0x47,0x07,0xa7,0xfc,0xf3,0x73,0x17,0xba,0x83,0x59,0x3c,0x19,0xe6,0x85,0x4f,0xa8,  0x68,0x6b,0x81,0xb2,0x71,0x64,0xda,0x8b,0xf8,0xeb,0x0f,0x4b,0x70,0x56,0x9d,0x35,  0x1e,0x24,0x0e,0x5e,0x63,0x58,0xd1,0xa2,0x25,0x22,0x7c,0x3b,0x01,0x21,0x78,0x87,  0xd4,0x00,0x46,0x57,0x9f,0xd3,0x27,0x52,0x4c,0x36,0x02,0xe7,0xa0,0xc4,0xc8,0x9e,  0xea,0xbf,0x8a,0xd2,0x40,0xc7,0x38,0xb5,0xa3,0xf7,0xf2,0xce,0xf9,0x61,0x15,0xa1,  0xe0,0xae,0x5d,0xa4,0x9b,0x34,0x1a,0x55,0xad,0x93,0x32,0x30,0xf5,0x8c,0xb1,0xe3,  0x1d,0xf6,0xe2,0x2e,0x82,0x66,0xca,0x60,0xc0,0x29,0x23,0xab,0x0d,0x53,0x4e,0x6f,  0xd5,0xdb,0x37,0x45,0xde,0xfd,0x8e,0x2f,0x03,0xff,0x6a,0x72,0x6d,0x6c,0x5b,0x51,  0x8d,0x1b,0xaf,0x92,0xbb,0xdd,0xbc,0x7f,0x11,0xd9,0x5c,0x41,0x1f,0x10,0x5a,0xd8,  0x0a,0xc1,0x31,0x88,0xa5,0xcd,0x7b,0xbd,0x2d,0x74,0xd0,0x12,0xb8,0xe5,0xb4,0xb0,  0x89,0x69,0x97,0x4a,0x0c,0x96,0x77,0x7e,0x65,0xb9,0xf1,0x09,0xc5,0x6e,0xc6,0x84,  0x18,0xf0,0x7d,0xec,0x3a,0xdc,0x4d,0x20,0x79,0xee,0x5f,0x3e,0xd7,0xcb,0x39,0x48  
];  function sm4_init(keyArray, isToEncrypt) {var sm4CtxParams = new strSm4CtxParams();var i = 0;var tmpInt = 0;sm4CtxParams.sk = new Array(32);Setkey(sm4CtxParams, keyArray);if (isToEncrypt == false) {for (i = 0; i < 16; i++) {tmpInt = sm4CtxParams.sk[i];sm4CtxParams.sk[i] = sm4CtxParams.sk[31 - i];sm4CtxParams.sk[31 - i] = tmpInt;}}//for (i = 0; i < 32; i++) {//	console.log("%dsk=%d", i, sm4CtxParams.sk[i]);//}return sm4CtxParams;
}function sm4_encrypt(sm4CtxParams, byteArrayDataIn) {return sm4_crypt_round(sm4CtxParams, byteArrayDataIn);
}function sm4_decrypt(sm4CtxParams, byteArrayDataIn) {return sm4_crypt_round(sm4CtxParams, byteArrayDataIn);
}function sm4_crypt_round(sm4CtxParams, byteArrayDataIn) {//unsigned long i = 0;  //unsigned long ulbuf[36]; var i = 0;	var ulbuf = new Array(36);var output = new Uint8Array(16);//memset(ulbuf, 0, sizeof(ulbuf)); for (i = 0; i < ulbuf.length; i++) {ulbuf[i] = 0;}GET_ULONG_BE( ulbuf, 0, byteArrayDataIn, 0 );  GET_ULONG_BE( ulbuf, 1, byteArrayDataIn, 4 );  GET_ULONG_BE( ulbuf, 2, byteArrayDataIn, 8 );  GET_ULONG_BE( ulbuf, 3, byteArrayDataIn, 12 );  i = 0;while(i<32) {  ulbuf[i+4] = F(ulbuf[i], ulbuf[i+1], ulbuf[i+2], ulbuf[i+3], sm4CtxParams.sk[i]);  i++;  }  PUT_ULONG_BE(ulbuf, 35, output, 0);  PUT_ULONG_BE(ulbuf, 34, output, 4);  PUT_ULONG_BE(ulbuf, 33, output, 8);  PUT_ULONG_BE(ulbuf, 32, output, 12); return output;
}function GET_ULONG_BE(n, nindex, b,i) {                                                       n[nindex] = ( (parseInt(b[(i)    ]) & 0xff) << 24 )        | ( (parseInt(b[(i) + 1]) & 0xff) << 16 )        | ( (parseInt(b[(i) + 2]) & 0xff) <<  8 )        | ( (parseInt(b[(i) + 3]) & 0xff)       );       
}function PUT_ULONG_BE(n, nindex, b,i){(b)[(i)    ] = ( (n[nindex]) >> 24 ) & 0xff;       (b)[(i) + 1] = ( (n[nindex]) >> 16 ) & 0xff;       (b)[(i) + 2] = ( (n[nindex]) >>  8 ) & 0xff;       (b)[(i) + 3] = ( (n[nindex])       ) & 0xff;       
} function SHL(x,n) {return (((x) & 0xFFFFFFFF) << (n%32));
}function ROTL(x,n) {return (SHL((x),(n)) | ((x) >>> (32 - ((n)%32))));
}function Lt(ka) {  //unsigned long bb = 0;  //unsigned long c = 0;  //unsigned char a[4];  //unsigned char b[4];  var a = new Uint8Array(4);var b = new Uint8Array(4);var tmpInt = new Array(1);var bb = 0;tmpInt[0] = ka;PUT_ULONG_BE(tmpInt,0,a,0);  ka = tmpInt[0];b[0] = Sbox(a[0]);  b[1] = Sbox(a[1]);  b[2] = Sbox(a[2]);  b[3] = Sbox(a[3]); tmpInt[0] = bb;GET_ULONG_BE(tmpInt,0,b,0); bb = tmpInt[0];return bb^(ROTL(bb, 2))^(ROTL(bb, 10))^(ROTL(bb, 18))^(ROTL(bb, 24));  //return c;  
}  function F(x0, x1, x2, x3, rk) {  return (x0^Lt(x1^x2^x3^rk));  
} function Sbox(inch)  
{  //unsigned char *pTable = (unsigned char*)SboxTable;  //unsigned char retVal = (unsigned char)(pTable[inch]);  //return retVal;  return SboxTable[inch];
}  function CalciRK(ka) {  //unsigned long bb = 0;  //unsigned long rk = 0;  //unsigned char a[4];  //unsigned char b[4];var bb = 0;var rk = 0;var a = new Uint8Array(4);var b = new Uint8Array(4);var tmpInt = new Array(1);tmpInt[0] = ka;PUT_ULONG_BE(tmpInt, 0, a, 0);  ka = tmpInt[0];//console.log("ka = %d a = %d %d %d %d", ka, a[0], a[1], a[2], a[3]);b[0] = Sbox(a[0]);  b[1] = Sbox(a[1]);  b[2] = Sbox(a[2]);  b[3] = Sbox(a[3]); tmpInt[0] = bb;	GET_ULONG_BE(tmpInt, 0, b, 0); bb = tmpInt[0];rk = bb^(ROTL(bb, 13))^(ROTL(bb, 23));//console.log("rk = %d", rk);return rk;  
}function Setkey(sm4CtxParams, key) {  //unsigned long MK[4];  //unsigned long k[36];  //unsigned long i = 0;  var i = 0;var MK = new Array(4);var k = new Array(36);GET_ULONG_BE(MK, 0, key, 0 );  GET_ULONG_BE(MK, 1, key, 4 );  GET_ULONG_BE(MK, 2, key, 8 );  GET_ULONG_BE(MK, 3, key, 12 );  //console.log("mk = %d %d %d %d", MK[0], MK[1], MK[2], MK[3]);k[0] = MK[0]^FK[0];  k[1] = MK[1]^FK[1];  k[2] = MK[2]^FK[2];  k[3] = MK[3]^FK[3];  //console.log("k = %d %d %d %d", k[0], k[1], k[2], k[3]);for(; i<32; i++) {  k[i+4] = k[i] ^ (CalciRK(k[i+1]^k[i+2]^k[i+3]^CK[i]));  sm4CtxParams.sk[i] = k[i+4];  //console.log("sk%d=%d", i, sm4CtxParams.sk[i]);//return;}  
}  function sm4_str_to_array(strIn) {var bytesArray = new Uint8Array(strIn.length);var i = 0;for (i = 0; i < strIn.length; i++) {bytesArray[i] = strIn.charCodeAt(i);}return bytesArray;
}function sm4_hex_to_array(hexStrIn) {var i = 0;var cnt = 0;var ele = 0;var bytesArray = null;cnt = 0;for (i = 0; i < hexStrIn.length; i++) {ele = hexStrIn.charCodeAt(i);if (ele >= 48 && ele < 48 + 10) {cnt++;}if (ele >= 65 && ele < 65 + 6) {cnt++;}if (ele >= 97 && ele < 97 + 6) {cnt++;}}bytesArray = new Uint8Array(parseInt((cnt + 1) / 2));cnt = 0;for (i = 0; i < hexStrIn.length; i++) {ele = hexStrIn.charCodeAt(i);if (ele >= 48 && ele < 48 + 10) {ele -= 48;cnt++;} else if (ele >= 65 && ele < 65 + 6) {ele = ele - 65 + 10;cnt++;} else if (ele >= 97 && ele < 97 + 6) {ele = ele - 97 + 10;cnt++;} else {continue;}if ((cnt % 2) == 1) {bytesArray[parseInt((cnt - 1) / 2)] = (ele << 4) & 0xF0;} else {bytesArray[parseInt((cnt - 1) / 2)] |= ele;}}return bytesArray;
}function sm4_hex_to_str(data, len) {var hex_digits = "0123456789abcdef";var output = new String();var i = 0;for (i = 0; i < len; i++) {output += hex_digits.charAt((data[i] >>> 4) & 0x0f);output += hex_digits.charAt((data[i]) & 0x0f);}return output;
}

测试代码:

var sm4Ctx = null;
var result = null;
var result2 = null;sm4Ctx = sm4_init(sm4_hex_to_array("00112233445566778888888800000000"), true);
result = sm4_encrypt(sm4Ctx, sm4_hex_to_array("1234567890ABCDEF0000007788552233"));
console.log("sm4 encrypt:" + sm4_hex_to_str(result, 16));sm4Ctx = sm4_init(sm4_hex_to_array("00112233445566778888888800000000"), false);
result2 = sm4_decrypt(sm4Ctx, result);
console.log("sm4 decrypt:" + sm4_hex_to_str(result2, 16));

测试结果:

在这里插入图片描述
加密的数据,能够解密得到原来的明文数据。经过其他平台工具验证,结果是对的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/468741.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深度解读AI在数字档案馆中的创新应用:高效识别与智能档案管理

一、项目背景介绍 在信息化浪潮推动下&#xff0c;基于OCR技术的纸质档案电子化方案成为解决档案管理难题的有效途径。该方案通过先进的OCR技术&#xff0c;能够统一采集各类档案数据&#xff0c;无论是手写文件、打印文件、复古文档还是照片或扫描的历史资料&#xff0c;都能实…

C++ | Leetcode C++题解之第554题砖墙

题目&#xff1a; 题解&#xff1a; class Solution { public:int leastBricks(vector<vector<int>>& wall) {unordered_map<int, int> cnt;for (auto& widths : wall) {int n widths.size();int sum 0;for (int i 0; i < n - 1; i) {sum wi…

【机器学习】强化学习(1)——强化学习原理浅析(区分强化学习、监督学习和启发式算法)

文章目录 强化学习介绍强化学习和监督学习比较监督学习强化学习 强化学习的数学和过程表达动作空间序列决策策略&#xff08;policy&#xff09;价值函数&#xff08;value function&#xff09;模型&#xff08;model&#xff09; 强化学习和启发式算法比较强化学习步骤代码走…

模糊搜索:在不确定性中寻找精确结果

目录 模糊搜索&#xff1a;在不确定性中寻找精确结果 一、引言 二、模糊搜索的背景 三、模糊搜索的原理 1、编辑距离&#xff08;Levenshtein Distance&#xff09;&#xff1a; 2、Jaccard 相似系数&#xff1a; 3、Soundex 算法&#xff1a; 4、TF-IDF&#xff08;词…

MyBatis5-缓存

目录 一级缓存 二级缓存 MyBatis缓存查询的顺序 整合第三方缓存EHCache 一级缓存 一级缓存是 SqlSession 级别的&#xff0c;通过同一个 SqlSession 查询的数据会被缓存&#xff0c;下次查询相同的数据&#xff0c;就会从缓存中直接获取&#xff0c;不会从数据库重新访问 一…

95.【C语言】数据结构之双向链表的头插,头删,查找,中间插入,中间删除和销毁函数

目录 1.双向链表的头插 方法一 方法二 2.双向链表的头删 3.双向链表的销毁 4.双向链表的某个节点的数据查找 5.双向链表的中间插入 5.双向链表的中间删除 6.对比顺序表和链表 承接94.【C语言】数据结构之双向链表的初始化,尾插,打印和尾删文章 1.双向链表的头插 方法…

24-11-9-读书笔记(三十二)-《契诃夫文集》(六)上([俄] 契诃夫 [译] 汝龙)药品是甜的,真理是美的,咖啡是苦的,生活是什么啊?

文章目录 《契诃夫文集》&#xff08;六&#xff09;上&#xff08;[俄] 契诃夫 [译] 汝龙&#xff09;药品是甜的&#xff0c;真理是美的&#xff0c;咖啡是苦的&#xff0c;生活是什么啊&#xff1f;目录阅读笔记1. 新年的苦难2. 香槟3. 乞丐4. 仇敌5.薇罗琪卡6.在家里7. 太早…

【从零开始鸿蒙开发:01】自定义闪屏页

文章目录 大体介绍文件介绍各部分代码SplashPage.etsIndex.etsHomePage.etsroute_map.jsonmodule.json5 流程 大体介绍 文件介绍 其中&#xff1a; pages为我们的页面内容&#xff08;我个人理解功能性小于activity但是大于fragment&#xff09;route_map.json 为自定义的路由…

【Spring】获取Cookie和Session(@CookieValue()和@SessionAttribute())

文章目录 获取 Cookie传统获取 Cookie简洁获取 Cookie&#xff08;注解&#xff09; 获取 SessionSession 存储和获取简洁获取 Session (1)简洁获取 Session (2) 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给…

【机器学习】任务十:从函数分析到机器学习应用与BP神经网络

目录 1.从函数分析到机器学习应用 1.1 3D曲面图可视化报告 1.1.1 目标 1.1.2 代码分析 1.1.3 结果分析 1.1.4 观察与总结 1.1.5 结论 1.2 一元函数梯度计算报告 1.2.1 目标 1.2.2 代码分析 1.2.4 计算结果 1.2.5 优势与意义 1.2.6 结论 1.3 一元函数梯度和二阶导…

ios打包文件上传App Store windows工具

在苹果开发者中心上架IOS APP的时候&#xff0c;在苹果开发者中心不能直接上传打包文件&#xff0c;需要下载mac的xcode这些工具进行上传&#xff0c;但这些工具无法安装在windows或linux电脑上。 这里&#xff0c;我们可以不用xcode这些工具来上传&#xff0c;可以用国内的香…

Rust @绑定(Rust@绑定)(在模式匹配的同时将值绑定到变量)

文章目录 Rust中的绑定基础概念示例&#xff1a;基本模式匹配 绑定的使用示例&#xff1a;范围匹配并绑定变量 深入探索绑定的好处示例&#xff1a;复杂数据结构中的应用 总结 附加 Rust中的绑定 Rust 语言以其强类型系统和内存安全的特性著称。在进行模式匹配时&#xff0c;R…

JVM知识点大全(未完...)

JVM运行时数据区域 堆 堆是Java虚拟机中用于存储对象的主要区域&#xff0c;包括字符串常量池。绝大多数对象都是在堆中创建的&#xff08;少部分对象可能会在栈上分配&#xff09;。为了更好地进行垃圾回收&#xff0c;堆被划分为年轻代和老年代两部分。年轻代又被进一步分为E…

Nginx(编译)+Lua脚本+Redis 实现自动封禁访问频率过高IP

1.安装lua 1.1安装LuaJIT yum install readline-devel mkdir -p lua-file cd lua-file/ wget https://github.com/LuaJIT/LuaJIT/archive/refs/tags/v2.0.5.tar.gz tar -zxvf LuaJIT-2.0.5.tar.gz cd LuaJIT-2.0.5 make && make install PREFIX/usr/local/luajit 1.2…

Transformer-GRU、Transformer、CNN-GRU、GRU、CNN五模型多变量回归预测

Transformer-GRU、Transformer、CNN-GRU、GRU、CNN五模型多变量回归预测 目录 Transformer-GRU、Transformer、CNN-GRU、GRU、CNN五模型多变量回归预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 Transformer-GRU、Transformer、CNN-GRU、GRU、CNN五模型多变量回归预…

Java - SpringBoot之logback设置日期分割并设置指定时间自动清除,Linux启动运行

一、SpringBoot之logback-spring.xml配置 在Spring Boot中&#xff0c;要设置日志按照日期进行分割输出&#xff0c;并设置日志文件的大小自动清除&#xff0c;可以使用logback日志框架的配置 1、创建文件 在项目的resources目录下&#xff0c;创建logback-spring.xml文件 …

window11安装elasticsearch+Kibana

1、下载elasticsearch与elasticsearch 下载elasticsearch 查看elasticsearch对应的Kibana版本 下载elasticsearch解压后文件目录如下 可执行脚本文件,包括启动elasticsearch服务、插件管理、函数命令等 bin配置文件目录,如elasticsearch配置、角色配置、jvm配置等 conf 默认…

【HCIP园区网综合拓扑实验】配置步骤与详解(已施工完毕)

一、实验要求 实验拓扑图如上图所示 1、按照图示的VLAN及IP地址需求&#xff0c;完成相关配置 2、要求SW1为VLAN 2/3的主根及主网关 SW2为vlan 20/30的主根及主网关 SW1和SW2互为备份 3、可以使用super vlan&#xff08;本实验未使用&#xff09; 4、上层…

【基于PSINS工具箱】以速度为观测量的SINS/GNSS组合导航,UKF滤波

基于【PSINS工具箱】&#xff0c;提供一个MATLAB例程&#xff0c;仅以速度为观测量的SINS/GNSS组合导航&#xff08;滤波方式为UKF&#xff09; 文章目录 工具箱程序简述运行结果 代码程序讲解MATLAB 代码教程&#xff1a;使用UKF进行速度观测1. 引言与基本设置2. 初始设置3. U…

java访问华为网管软件iMaster NCE的北向接口时传递参数问题

上一篇文章介绍了利用《java访问华为网管软件iMaster NCE的北向接口》的一般性步骤&#xff0c;这里详细介绍其中一个读取性能数据的示例。原因是读取华为网管软件北向接口&#xff0c;完全找不到可供参考的例子。如果不需要传递什么参数&#xff0c;就能获取到结果&#xff0c…