1, Front end
sm4.js
/** * base64js * base64js.toByteArray(d.input) * base64js.fromByteArray(c); *State secret SM4 encryption algorithm * @author wzk * @email 1216113487@qq.com *@ company Zhongke software */ (function(r){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=r()}else{if(typeof define=== "function"&&define.amd){define([],r)}else{var e;if(typeof window!=="undefined"){e=window}else{if(typeof global !=="undefined"){e=global}else{if(typeof self!=="undefined"){e=self}else{e=this}}}e.base64js=r()}}})(function(){ var r,e,t;return function r(e,t,n){function o(i,a){if(!t[i]){if(!e[i]){var u=typeof require=="function"&&require;if(!a&&u){ return u(i,!0)}if(f){return f(i,!0)}var d=new Error("Cannot find module '"+i+"'");throw d.code="MODULE_NOT_FOUND",d} var c=t[i]={exports:{}};e[i][0].call(c.exports,function(r){var t=e[i][1][r];return o(t?t:r)},c,c.exports,r,e,t,n)}return t[i].exports} var f=typeof require=="function"&&require;for(var i=0;i<n.length;i++){o(n[i])}return o}({"/":[function(r,e,t){t.byteLength=c; t.toByteArray=v;t.fromByteArray=s;var n=[];var o=[];var f=typeof Uint8Array!=="undefined"?Uint8Array:Array; var i="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";for(var a=0,u=i.length;a<u;++a){n[a]=i[a]; o[i.charCodeAt(a)]=a}o["-".charCodeAt(0)]=62;o["_".charCodeAt(0)]=63;function d(r){var e=r.length;if(e%4>0){ throw new Error("Invalid string. Length must be a multiple of 4")}return r[e-2]==="="?2:r[e-1]==="="?1:0} function c(r){return r.length*3/4-d(r)}function v(r){var e,t,n,i,a;var u=r.length;i=d(r);a=new f(u*3/4-i);t=i>0?u-4:u; var c=0;for(e=0;e<t;e+=4){n=o[r.charCodeAt(e)]<<18|o[r.charCodeAt(e+1)]<<12|o[r.charCodeAt(e+2)]<<6|o[r.charCodeAt(e+3)]; a[c++]=n>>16&255;a[c++]=n>>8&255;a[c++]=n&255}if(i===2){n=o[r.charCodeAt(e)]<<2|o[r.charCodeAt(e+1)]>>4;a[c++]=n&255} else{if(i===1){n=o[r.charCodeAt(e)]<<10|o[r.charCodeAt(e+1)]<<4|o[r.charCodeAt(e+2)]>>2;a[c++]=n>>8&255;a[c++]=n&255}}return a} function l(r){return n[r>>18&63]+n[r>>12&63]+n[r>>6&63]+n[r&63]}function h(r,e,t){var n;var o=[];for(var f=e;f<t;f+=3){ n=(r[f]<<16)+(r[f+1]<<8)+r[f+2];o.push(l(n))}return o.join("")}function s(r){var e;var t=r.length;var o=t%3;var f="";var i=[]; var a=16383;for(var u=0,d=t-o;u<d;u+=a){i.push(h(r,u,u+a>d?d:u+a))}if(o===1){e=r[t-1];f+=n[e>>2];f+=n[e<<4&63];f+="=="}else{if(o===2){ e=(r[t-2]<<8)+r[t-1];f+=n[e>>10];f+=n[e>>4&63];f+=n[e<<2&63];f+="="}}i.push(f);return i.join("")}},{}]},{},[])("/")});
/
- State secret SM4 encryption algorithm
- @author wzk
- @email 1216113487@qq.com
- @company Zhongke software
*/
function SM4_Context() {
this.mode=1;
this.isPadding = true;
this.sk = new Array(32);
}
function SM4() {
this.SM4_ENCRYPT=1;
this.SM4_DECRYPT = 0;
</span><span style="color: rgba(0, 0, 255, 1)">var</span> SboxTable = [0xd6,0x90,0xe9,0xfe,0xcc,0xe1,0x3d,0xb7,0x16,0xb6,0x14,0xc2,0x28,0xfb,0x2c,0x05<span style="color: rgba(0, 0, 0, 1)">, </span>0x2b,0x67,0x9a,0x76,0x2a,0xbe,0x04,0xc3,0xaa,0x44,0x13,0x26,0x49,0x86,0x06,0x99<span style="color: rgba(0, 0, 0, 1)">, </span>0x9c,0x42,0x50,0xf4,0x91,0xef,0x98,0x7a,0x33,0x54,0x0b,0x43,0xed,0xcf,0xac,0x62<span style="color: rgba(0, 0, 0, 1)">, </span>0xe4,0xb3,0x1c,0xa9,0xc9,0x08,0xe8,0x95,0x80,0xdf,0x94,0xfa,0x75,0x8f,0x3f,0xa6<span style="color: rgba(0, 0, 0, 1)">, </span>0x47,0x07,0xa7,0xfc,0xf3,0x73,0x17,0xba,0x83,0x59,0x3c,0x19,0xe6,0x85,0x4f,0xa8<span style="color: rgba(0, 0, 0, 1)">, </span>0x68,0x6b,0x81,0xb2,0x71,0x64,0xda,0x8b,0xf8,0xeb,0x0f,0x4b,0x70,0x56,0x9d,0x35<span style="color: rgba(0, 0, 0, 1)">, </span>0x1e,0x24,0x0e,0x5e,0x63,0x58,0xd1,0xa2,0x25,0x22,0x7c,0x3b,0x01,0x21,0x78,0x87<span style="color: rgba(0, 0, 0, 1)">, </span>0xd4,0x00,0x46,0x57,0x9f,0xd3,0x27,0x52,0x4c,0x36,0x02,0xe7,0xa0,0xc4,0xc8,0x9e<span style="color: rgba(0, 0, 0, 1)">, </span>0xea,0xbf,0x8a,0xd2,0x40,0xc7,0x38,0xb5,0xa3,0xf7,0xf2,0xce,0xf9,0x61,0x15,0xa1<span style="color: rgba(0, 0, 0, 1)">, </span>0xe0,0xae,0x5d,0xa4,0x9b,0x34,0x1a,0x55,0xad,0x93,0x32,0x30,0xf5,0x8c,0xb1,0xe3<span style="color: rgba(0, 0, 0, 1)">, </span>0x1d,0xf6,0xe2,0x2e,0x82,0x66,0xca,0x60,0xc0,0x29,0x23,0xab,0x0d,0x53,0x4e,0x6f<span style="color: rgba(0, 0, 0, 1)">, </span>0xd5,0xdb,0x37,0x45,0xde,0xfd,0x8e,0x2f,0x03,0xff,0x6a,0x72,0x6d,0x6c,0x5b,0x51<span style="color: rgba(0, 0, 0, 1)">, </span>0x8d,0x1b,0xaf,0x92,0xbb,0xdd,0xbc,0x7f,0x11,0xd9,0x5c,0x41,0x1f,0x10,0x5a,0xd8<span style="color: rgba(0, 0, 0, 1)">, </span>0x0a,0xc1,0x31,0x88,0xa5,0xcd,0x7b,0xbd,0x2d,0x74,0xd0,0x12,0xb8,0xe5,0xb4,0xb0<span style="color: rgba(0, 0, 0, 1)">, </span>0x89,0x69,0x97,0x4a,0x0c,0x96,0x77,0x7e,0x65,0xb9,0xf1,0x09,0xc5,0x6e,0xc6,0x84<span style="color: rgba(0, 0, 0, 1)">, </span>0x18,0xf0,0x7d,0xec,0x3a,0xdc,0x4d,0x20,0x79,0xee,0x5f,0x3e,0xd7,0xcb,0x39,0x48<span style="color: rgba(0, 0, 0, 1)">]; </span><span style="color: rgba(0, 0, 255, 1)">var</span> FK = [ 0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc<span style="color: rgba(0, 0, 0, 1)"> ]; </span><span style="color: rgba(0, 0, 255, 1)">var</span> CK = [ 0x00070e15,0x1c232a31,0x383f464d,0x545b6269<span style="color: rgba(0, 0, 0, 1)">, </span>0x70777e85,0x8c939aa1,0xa8afb6bd,0xc4cbd2d9<span style="color: rgba(0, 0, 0, 1)">, </span>0xe0e7eef5,0xfc030a11,0x181f262d,0x343b4249<span style="color: rgba(0, 0, 0, 1)">, </span>0x50575e65,0x6c737a81,0x888f969d,0xa4abb2b9<span style="color: rgba(0, 0, 0, 1)">, </span>0xc0c7ced5,0xdce3eaf1,0xf8ff060d,0x141b2229<span style="color: rgba(0, 0, 0, 1)">, </span>0x30373e45,0x4c535a61,0x686f767d,0x848b9299<span style="color: rgba(0, 0, 0, 1)">, </span>0xa0a7aeb5,0xbcc3cad1,0xd8dfe6ed,0xf4fb0209<span style="color: rgba(0, 0, 0, 1)">, </span>0x10171e25,0x2c333a41,0x484f565d,0x646b7279<span style="color: rgba(0, 0, 0, 1)"> ]; </span><span style="color: rgba(0, 0, 255, 1)">this</span>.GET_ULONG_BE=<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(b,i) { </span><span style="color: rgba(0, 0, 255, 1)">return</span> (b[i] & 0xff) << 24 | ((b[i + 1] & 0xff) << 16) | ((b[i + 2] & 0xff) << 8) | (b[i + 3] & 0xff) & 0xffffffff<span style="color: rgba(0, 0, 0, 1)">; } </span><span style="color: rgba(0, 0, 255, 1)">this</span>.PUT_ULONG_BE=<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">( n, b, i){ </span><span style="color: rgba(0, 0, 255, 1)">var</span> t1=(0xFF & (n >> 24<span style="color: rgba(0, 0, 0, 1)">)); </span><span style="color: rgba(0, 0, 255, 1)">var</span> t2=(0xFF & (n >> 16<span style="color: rgba(0, 0, 0, 1)">)); </span><span style="color: rgba(0, 0, 255, 1)">var</span> t3=(0xFF & (n >> 8<span style="color: rgba(0, 0, 0, 1)">)); </span><span style="color: rgba(0, 0, 255, 1)">var</span> t4=(0xFF &<span style="color: rgba(0, 0, 0, 1)"> (n)); b[i] </span>= t1>128?t1-256<span style="color: rgba(0, 0, 0, 1)">:t1; b[i </span>+ 1] = t2>128?t2-256<span style="color: rgba(0, 0, 0, 1)">:t2; b[i </span>+ 2] = t3>128?t3-256<span style="color: rgba(0, 0, 0, 1)">:t3; b[i </span>+ 3] = t4>128?t4-256<span style="color: rgba(0, 0, 0, 1)">:t4; } </span><span style="color: rgba(0, 0, 255, 1)">this</span>.SHL=<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(x,n){ </span><span style="color: rgba(0, 0, 255, 1)">return</span> (x & 0xFFFFFFFF) <<<span style="color: rgba(0, 0, 0, 1)"> n; } </span><span style="color: rgba(0, 0, 255, 1)">this</span>.ROTL=<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">( x, n){ </span><span style="color: rgba(0, 0, 255, 1)">var</span> s =<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.SHL(x, n); </span><span style="color: rgba(0, 0, 255, 1)">var</span> ss= x >> (32 -<span style="color: rgba(0, 0, 0, 1)"> n); </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">this</span>.SHL(x, n) | x >> (32 -<span style="color: rgba(0, 0, 0, 1)"> n); } </span><span style="color: rgba(0, 0, 255, 1)">this</span>.sm4Lt=<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(ka){ </span><span style="color: rgba(0, 0, 255, 1)">var</span> bb = 0<span style="color: rgba(0, 0, 0, 1)">; </span><span style="color: rgba(0, 0, 255, 1)">var</span> c = 0<span style="color: rgba(0, 0, 0, 1)">; </span><span style="color: rgba(0, 0, 255, 1)">var</span> a = <span style="color: rgba(0, 0, 255, 1)">new</span> Array(4<span style="color: rgba(0, 0, 0, 1)">); </span><span style="color: rgba(0, 0, 255, 1)">var</span> b = <span style="color: rgba(0, 0, 255, 1)">new</span> Array(4<span style="color: rgba(0, 0, 0, 1)">); </span><span style="color: rgba(0, 0, 255, 1)">this</span>.PUT_ULONG_BE(ka, a, 0<span style="color: rgba(0, 0, 0, 1)">); b[</span>0] = <span style="color: rgba(0, 0, 255, 1)">this</span>.sm4Sbox(a[0<span style="color: rgba(0, 0, 0, 1)">]); b[</span>1] = <span style="color: rgba(0, 0, 255, 1)">this</span>.sm4Sbox(a[1<span style="color: rgba(0, 0, 0, 1)">]); b[</span>2] = <span style="color: rgba(0, 0, 255, 1)">this</span>.sm4Sbox(a[2<span style="color: rgba(0, 0, 0, 1)">]); b[</span>3] = <span style="color: rgba(0, 0, 255, 1)">this</span>.sm4Sbox(a[3<span style="color: rgba(0, 0, 0, 1)">]); bb </span>= <span style="color: rgba(0, 0, 255, 1)">this</span>.GET_ULONG_BE(b, 0<span style="color: rgba(0, 0, 0, 1)">); c </span>= bb ^ <span style="color: rgba(0, 0, 255, 1)">this</span>.ROTL(bb, 2) ^ <span style="color: rgba(0, 0, 255, 1)">this</span>.ROTL(bb, 10) ^ <span style="color: rgba(0, 0, 255, 1)">this</span>.ROTL(bb, 18) ^ <span style="color: rgba(0, 0, 255, 1)">this</span>.ROTL(bb, 24<span style="color: rgba(0, 0, 0, 1)">); </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> c; } </span><span style="color: rgba(0, 0, 255, 1)">this</span>.sm4F=<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">( x0, x1, x2, x3, rk){ </span><span style="color: rgba(0, 0, 255, 1)">return</span> x0 ^ <span style="color: rgba(0, 0, 255, 1)">this</span>.sm4Lt(x1 ^ x2 ^ x3 ^<span style="color: rgba(0, 0, 0, 1)"> rk); } </span><span style="color: rgba(0, 0, 255, 1)">this</span>.sm4CalciRK=<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(ka){ </span><span style="color: rgba(0, 0, 255, 1)">var</span> bb = 0<span style="color: rgba(0, 0, 0, 1)">; </span><span style="color: rgba(0, 0, 255, 1)">var</span> rk = 0<span style="color: rgba(0, 0, 0, 1)">; </span><span style="color: rgba(0, 0, 255, 1)">var</span> a = <span style="color: rgba(0, 0, 255, 1)">new</span> Array(4<span style="color: rgba(0, 0, 0, 1)">); </span><span style="color: rgba(0, 0, 255, 1)">var</span> b = <span style="color: rgba(0, 0, 255, 1)">new</span> Array(4<span style="color: rgba(0, 0, 0, 1)">); </span><span style="color: rgba(0, 0, 255, 1)">this</span>.PUT_ULONG_BE(ka, a, 0<span style="color: rgba(0, 0, 0, 1)">); b[</span>0] = <span style="color: rgba(0, 0, 255, 1)">this</span>.sm4Sbox(a[0<span style="color: rgba(0, 0, 0, 1)">]); b[</span>1] = <span style="color: rgba(0, 0, 255, 1)">this</span>.sm4Sbox(a[1<span style="color: rgba(0, 0, 0, 1)">]); b[</span>2] = <span style="color: rgba(0, 0, 255, 1)">this</span>.sm4Sbox(a[2<span style="color: rgba(0, 0, 0, 1)">]); b[</span>3] = <span style="color: rgba(0, 0, 255, 1)">this</span>.sm4Sbox(a[3<span style="color: rgba(0, 0, 0, 1)">]); bb </span>= <span style="color: rgba(0, 0, 255, 1)">this</span>.GET_ULONG_BE(b, 0<span style="color: rgba(0, 0, 0, 1)">); rk </span>= bb ^ <span style="color: rgba(0, 0, 255, 1)">this</span>.ROTL(bb, 13) ^ <span style="color: rgba(0, 0, 255, 1)">this</span>.ROTL(bb, 23<span style="color: rgba(0, 0, 0, 1)">); </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> rk; } </span><span style="color: rgba(0, 0, 255, 1)">this</span>.sm4Sbox=<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(inch){ </span><span style="color: rgba(0, 0, 255, 1)">var</span> i = inch & 0xFF<span style="color: rgba(0, 0, 0, 1)">; </span><span style="color: rgba(0, 0, 255, 1)">var</span> retVal =<span style="color: rgba(0, 0, 0, 1)"> SboxTable[i]; </span><span style="color: rgba(0, 0, 255, 1)">return</span> retVal>128?retVal-256<span style="color: rgba(0, 0, 0, 1)">:retVal; } </span><span style="color: rgba(0, 0, 255, 1)">this</span>.sm4_setkey_enc = <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(ctx, key){ </span><span style="color: rgba(0, 0, 255, 1)">if</span> (ctx == <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">) { alert(</span>"ctx is null!"<span style="color: rgba(0, 0, 0, 1)">); </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">; } </span><span style="color: rgba(0, 0, 255, 1)">if</span> (key == <span style="color: rgba(0, 0, 255, 1)">null</span> || key.length != 16<span style="color: rgba(0, 0, 0, 1)">){ alert(</span>"key error!"<span style="color: rgba(0, 0, 0, 1)">); </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">; } ctx.mode </span>= <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.SM4_ENCRYPT; </span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.sm4_setkey(ctx.sk, key); }; </span><span style="color: rgba(0, 0, 255, 1)">this</span>.sm4_setkey = <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(SK, key){ </span><span style="color: rgba(0, 0, 255, 1)">var</span> MK = <span style="color: rgba(0, 0, 255, 1)">new</span> Array(4<span style="color: rgba(0, 0, 0, 1)">); </span><span style="color: rgba(0, 0, 255, 1)">var</span> k = <span style="color: rgba(0, 0, 255, 1)">new</span> Array(36<span style="color: rgba(0, 0, 0, 1)">); </span><span style="color: rgba(0, 0, 255, 1)">var</span> i = 0<span style="color: rgba(0, 0, 0, 1)">; MK[</span>0] = <span style="color: rgba(0, 0, 255, 1)">this</span>.GET_ULONG_BE(key, 0<span style="color: rgba(0, 0, 0, 1)">); MK[</span>1] = <span style="color: rgba(0, 0, 255, 1)">this</span>.GET_ULONG_BE(key, 4<span style="color: rgba(0, 0, 0, 1)">); MK[</span>2] = <span style="color: rgba(0, 0, 255, 1)">this</span>.GET_ULONG_BE(key, 8<span style="color: rgba(0, 0, 0, 1)">); MK[</span>3] = <span style="color: rgba(0, 0, 255, 1)">this</span>.GET_ULONG_BE(key, 12<span style="color: rgba(0, 0, 0, 1)">); k[</span>0] = MK[0] ^ FK[0<span style="color: rgba(0, 0, 0, 1)">]; k[</span>1] = MK[1] ^ FK[1<span style="color: rgba(0, 0, 0, 1)">]; k[</span>2] = MK[2] ^ FK[2<span style="color: rgba(0, 0, 0, 1)">]; k[</span>3] = MK[3] ^ FK[3<span style="color: rgba(0, 0, 0, 1)">]; </span><span style="color: rgba(0, 0, 255, 1)">for</span> (<span style="color: rgba(0, 0, 255, 1)">var</span> i=0; i < 32; i++<span style="color: rgba(0, 0, 0, 1)">){ k[(i </span>+ 4)] = (k[i] ^ <span style="color: rgba(0, 0, 255, 1)">this</span>.sm4CalciRK(k[(i + 1)] ^ k[(i + 2)] ^ k[(i + 3)] ^<span style="color: rgba(0, 0, 0, 1)"> CK[i])); SK[i] </span>= k[(i + 4<span style="color: rgba(0, 0, 0, 1)">)]; } } </span><span style="color: rgba(0, 0, 255, 1)">this</span>.padding=<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(input,mode){ </span><span style="color: rgba(0, 0, 255, 1)">if</span> (input == <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">){ </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">; } </span><span style="color: rgba(0, 0, 255, 1)">var</span> ret = <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">; </span><span style="color: rgba(0, 0, 255, 1)">if</span> (mode == <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.SM4_ENCRYPT){ </span><span style="color: rgba(0, 0, 255, 1)">var</span> p = parseInt(16 - input.length % 16<span style="color: rgba(0, 0, 0, 1)">); ret </span>= input.slice(0<span style="color: rgba(0, 0, 0, 1)">); </span><span style="color: rgba(0, 0, 255, 1)">for</span> (<span style="color: rgba(0, 0, 255, 1)">var</span> i = 0; i < p; i++<span style="color: rgba(0, 0, 0, 1)">){ ret[input.length </span>+ i] =<span style="color: rgba(0, 0, 0, 1)"> p; } }</span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)">{ </span><span style="color: rgba(0, 0, 255, 1)">var</span> p = input[input.length - 1<span style="color: rgba(0, 0, 0, 1)">]; ret</span>=input.slice(0,input.length -<span style="color: rgba(0, 0, 0, 1)"> p); } </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> ret; } </span><span style="color: rgba(0, 0, 255, 1)">this</span>.sm4_one_round=<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(sk, input, output){ </span><span style="color: rgba(0, 0, 255, 1)">var</span> i = 0<span style="color: rgba(0, 0, 0, 1)">; </span><span style="color: rgba(0, 0, 255, 1)">var</span> ulbuf = <span style="color: rgba(0, 0, 255, 1)">new</span> Array(36<span style="color: rgba(0, 0, 0, 1)">); ulbuf[</span>0] = <span style="color: rgba(0, 0, 255, 1)">this</span>.GET_ULONG_BE(input, 0<span style="color: rgba(0, 0, 0, 1)">); ulbuf[</span>1] = <span style="color: rgba(0, 0, 255, 1)">this</span>.GET_ULONG_BE(input, 4<span style="color: rgba(0, 0, 0, 1)">); ulbuf[</span>2] = <span style="color: rgba(0, 0, 255, 1)">this</span>.GET_ULONG_BE(input, 8<span style="color: rgba(0, 0, 0, 1)">); ulbuf[</span>3] = <span style="color: rgba(0, 0, 255, 1)">this</span>.GET_ULONG_BE(input, 12<span style="color: rgba(0, 0, 0, 1)">); </span><span style="color: rgba(0, 0, 255, 1)">while</span> (i < 32<span style="color: rgba(0, 0, 0, 1)">){ ulbuf[(i </span>+ 4)] = <span style="color: rgba(0, 0, 255, 1)">this</span>.sm4F(ulbuf[i], ulbuf[(i + 1)], ulbuf[(i + 2)], ulbuf[(i + 3<span style="color: rgba(0, 0, 0, 1)">)], sk[i]); i</span>++<span style="color: rgba(0, 0, 0, 1)">; } </span><span style="color: rgba(0, 0, 255, 1)">this</span>.PUT_ULONG_BE(ulbuf[35], output, 0<span style="color: rgba(0, 0, 0, 1)">); </span><span style="color: rgba(0, 0, 255, 1)">this</span>.PUT_ULONG_BE(ulbuf[34], output, 4<span style="color: rgba(0, 0, 0, 1)">); </span><span style="color: rgba(0, 0, 255, 1)">this</span>.PUT_ULONG_BE(ulbuf[33], output, 8<span style="color: rgba(0, 0, 0, 1)">); </span><span style="color: rgba(0, 0, 255, 1)">this</span>.PUT_ULONG_BE(ulbuf[32], output, 12<span style="color: rgba(0, 0, 0, 1)">); } </span><span style="color: rgba(0, 0, 255, 1)">this</span>.sm4_crypt_ecb=<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(ctx,input){ </span><span style="color: rgba(0, 0, 255, 1)">if</span> (input == <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">){ alert(</span>"input is null!"<span style="color: rgba(0, 0, 0, 1)">); } </span><span style="color: rgba(0, 0, 255, 1)">if</span> ((ctx.isPadding) && (ctx.mode == <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.SM4_ENCRYPT)){ input </span>= <span style="color: rgba(0, 0, 255, 1)">this</span>.padding(input, <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.SM4_ENCRYPT); } </span><span style="color: rgba(0, 0, 255, 1)">var</span> i=0<span style="color: rgba(0, 0, 0, 1)">; </span><span style="color: rgba(0, 0, 255, 1)">var</span> length =<span style="color: rgba(0, 0, 0, 1)"> input.length; </span><span style="color: rgba(0, 0, 255, 1)">var</span> bous = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Array(); </span><span style="color: rgba(0, 0, 255, 1)">for</span>(; length > 0; length -= 16<span style="color: rgba(0, 0, 0, 1)">) { </span><span style="color: rgba(0, 0, 255, 1)">var</span> out = <span style="color: rgba(0, 0, 255, 1)">new</span> Array(16<span style="color: rgba(0, 0, 0, 1)">); </span><span style="color: rgba(0, 0, 255, 1)">var</span> ins=input.slice(i*16,(16*(i+1<span style="color: rgba(0, 0, 0, 1)">))); </span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.sm4_one_round(ctx.sk, ins, out) bous</span>=<span style="color: rgba(0, 0, 0, 1)">bous.concat(out); i</span>++<span style="color: rgba(0, 0, 0, 1)">; } </span><span style="color: rgba(0, 0, 255, 1)">var</span> output =<span style="color: rgba(0, 0, 0, 1)"> bous; </span><span style="color: rgba(0, 0, 255, 1)">if</span> (ctx.isPadding && ctx.mode == <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.SM4_DECRYPT) { output </span>= <span style="color: rgba(0, 0, 255, 1)">this</span>.padding(output, <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.SM4_DECRYPT); } </span><span style="color: rgba(0, 0, 255, 1)">for</span>(<span style="color: rgba(0, 0, 255, 1)">var</span> i=0;i<output.length;i++<span style="color: rgba(0, 0, 0, 1)">){ </span><span style="color: rgba(0, 0, 255, 1)">if</span>(output[i]<0<span style="color: rgba(0, 0, 0, 1)">){ output[i]</span>=output[i]+256<span style="color: rgba(0, 0, 0, 1)">; } } </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> output; } </span><span style="color: rgba(0, 0, 255, 1)">this</span>.sm4_crypt_cbc=<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(ctx, iv, input){ </span><span style="color: rgba(0, 0, 255, 1)">if</span> (iv == <span style="color: rgba(0, 0, 255, 1)">null</span> || iv.length != 16<span style="color: rgba(0, 0, 0, 1)">) { alert(</span>"iv error!"<span style="color: rgba(0, 0, 0, 1)">); } </span><span style="color: rgba(0, 0, 255, 1)">if</span> (input == <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">){ alert(</span>"input is null!"<span style="color: rgba(0, 0, 0, 1)">); } </span><span style="color: rgba(0, 0, 255, 1)">if</span> (ctx.isPadding && ctx.mode == <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.SM4_ENCRYPT) { input </span>= <span style="color: rgba(0, 0, 255, 1)">this</span>.padding(input, <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.SM4_ENCRYPT); } </span><span style="color: rgba(0, 0, 255, 1)">var</span> i = 0<span style="color: rgba(0, 0, 0, 1)">; </span><span style="color: rgba(0, 0, 255, 1)">var</span> length =<span style="color: rgba(0, 0, 0, 1)"> input.length; </span><span style="color: rgba(0, 0, 255, 1)">var</span> bous =<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Array(); </span><span style="color: rgba(0, 0, 255, 1)">if</span> (ctx.mode == <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.SM4_ENCRYPT){ </span><span style="color: rgba(0, 0, 255, 1)">var</span> k=0<span style="color: rgba(0, 0, 0, 1)">; </span><span style="color: rgba(0, 0, 255, 1)">for</span>(; length > 0; length -= 16<span style="color: rgba(0, 0, 0, 1)">){ </span><span style="color: rgba(0, 0, 255, 1)">var</span> out = <span style="color: rgba(0, 0, 255, 1)">new</span> Array(16<span style="color: rgba(0, 0, 0, 1)">); </span><span style="color: rgba(0, 0, 255, 1)">var</span> out1 = <span style="color: rgba(0, 0, 255, 1)">new</span> Array(16<span style="color: rgba(0, 0, 0, 1)">); </span><span style="color: rgba(0, 0, 255, 1)">var</span> ins=input.slice(k*16,(16*(k+1<span style="color: rgba(0, 0, 0, 1)">))); </span><span style="color: rgba(0, 0, 255, 1)">for</span> (i = 0; i < 16; i++<span style="color: rgba(0, 0, 0, 1)">) { out[i] </span>= (ins[i] ^<span style="color: rgba(0, 0, 0, 1)"> iv[i]); } </span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.sm4_one_round(ctx.sk, out, out1); iv</span>=out1.slice(0,16<span style="color: rgba(0, 0, 0, 1)">); bous</span>=<span style="color: rgba(0, 0, 0, 1)">bous.concat(out1); k</span>++<span style="color: rgba(0, 0, 0, 1)">; } } </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> { </span><span style="color: rgba(0, 0, 255, 1)">var</span> temp =<span style="color: rgba(0, 0, 0, 1)"> []; </span><span style="color: rgba(0, 0, 255, 1)">var</span> k=0<span style="color: rgba(0, 0, 0, 1)">; </span><span style="color: rgba(0, 0, 255, 1)">for</span>(; length > 0; length -= 16<span style="color: rgba(0, 0, 0, 1)">) { </span><span style="color: rgba(0, 0, 255, 1)">var</span> out = <span style="color: rgba(0, 0, 255, 1)">new</span> Array(16<span style="color: rgba(0, 0, 0, 1)">); </span><span style="color: rgba(0, 0, 255, 1)">var</span> out1 = <span style="color: rgba(0, 0, 255, 1)">new</span> Array(16<span style="color: rgba(0, 0, 0, 1)">); </span><span style="color: rgba(0, 0, 255, 1)">var</span> ins=input.slice(k*16,(16*(k+1<span style="color: rgba(0, 0, 0, 1)">))); temp</span>=ins.slice(0,16<span style="color: rgba(0, 0, 0, 1)">); sm4_one_round(ctx.sk, ins, out); </span><span style="color: rgba(0, 0, 255, 1)">for</span> (i = 0; i < 16; i++<span style="color: rgba(0, 0, 0, 1)">) { out1[i] </span>= (out[i] ^<span style="color: rgba(0, 0, 0, 1)"> iv[i]); } iv</span>=temp.slice(0,16<span style="color: rgba(0, 0, 0, 1)">); bous</span>=<span style="color: rgba(0, 0, 0, 1)">bous.concat(out1); k</span>++<span style="color: rgba(0, 0, 0, 1)">; } } </span><span style="color: rgba(0, 0, 255, 1)">var</span> output =<span style="color: rgba(0, 0, 0, 1)"> bous; </span><span style="color: rgba(0, 0, 255, 1)">if</span> (ctx.isPadding && ctx.mode == <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.SM4_DECRYPT) { output </span>= <span style="color: rgba(0, 0, 255, 1)">this</span>.padding(output, <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.SM4_DECRYPT); } </span><span style="color: rgba(0, 0, 255, 1)">for</span>(<span style="color: rgba(0, 0, 255, 1)">var</span> i=0;i<output.length;i++<span style="color: rgba(0, 0, 0, 1)">){ </span><span style="color: rgba(0, 0, 255, 1)">if</span>(output[i]<0<span style="color: rgba(0, 0, 0, 1)">){ output[i]</span>=output[i]+256<span style="color: rgba(0, 0, 0, 1)">; } } </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> output; }
}
function SM4Util() {
//Consistent with the backend key
this.secretKey="GJwsXX_BzW=gJWJW";
//When CBC mode was used
this.iv = "ZkR_SiNoSOFT=568";
this.hexString = false;
</span><span style="color: rgba(0, 128, 0, 1)">//< / span > < span style = "color: RGBA (0, 128, 0, 1)" > ECB mode encryption</span> <span style="color: rgba(0, 0, 255, 1)">this</span>.encryptData_ECB=<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(plainText){ </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)">{ </span><span style="color: rgba(0, 0, 255, 1)">var</span> sm4 = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> SM4(); </span><span style="color: rgba(0, 0, 255, 1)">var</span> ctx = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> SM4_Context(); ctx.isPadding </span>= <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">; ctx.mode </span>=<span style="color: rgba(0, 0, 0, 1)"> sm4.SM4_ENCRYPT; </span><span style="color: rgba(0, 0, 255, 1)">var</span> keyBytes= stringToByte(<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.secretKey); sm4.sm4_setkey_enc(ctx, keyBytes); </span><span style="color: rgba(0, 0, 255, 1)">var</span> encrypted =<span style="color: rgba(0, 0, 0, 1)"> sm4.sm4_crypt_ecb(ctx, stringToByte(plainText)); </span><span style="color: rgba(0, 0, 255, 1)">var</span> cipherText =<span style="color: rgba(0, 0, 0, 1)"> base64js.fromByteArray(encrypted); </span><span style="color: rgba(0, 0, 255, 1)">if</span> (cipherText != <span style="color: rgba(0, 0, 255, 1)">null</span> && cipherText.trim().length > 0<span style="color: rgba(0, 0, 0, 1)">) { cipherText.replace(</span>/(\s*|\t|\r|\n)/g, ""<span style="color: rgba(0, 0, 0, 1)">); } </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> cipherText; }</span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (e){ console.error(e); </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">; } } </span><span style="color: rgba(0, 128, 0, 1)">//< / span > < span style = "color: RGBA (0, 128, 0, 1)" > CBC mode encryption</span> <span style="color: rgba(0, 0, 255, 1)">this</span>.encryptData_CBC=<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(plainText){ </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)">{ </span><span style="color: rgba(0, 0, 255, 1)">var</span> sm4 = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> SM4(); </span><span style="color: rgba(0, 0, 255, 1)">var</span> ctx = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> SM4_Context(); ctx.isPadding </span>= <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">; ctx.mode </span>=<span style="color: rgba(0, 0, 0, 1)"> sm4.SM4_ENCRYPT; </span><span style="color: rgba(0, 0, 255, 1)">var</span> keyBytes = stringToByte(<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.secretKey) ; </span><span style="color: rgba(0, 0, 255, 1)">var</span> ivBytes= stringToByte(<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.iv) ; sm4.sm4_setkey_enc(ctx, keyBytes); </span><span style="color: rgba(0, 0, 255, 1)">var</span> encrypted =<span style="color: rgba(0, 0, 0, 1)"> sm4.sm4_crypt_cbc(ctx, ivBytes, stringToByte(plainText)); </span><span style="color: rgba(0, 0, 255, 1)">var</span> cipherText =<span style="color: rgba(0, 0, 0, 1)"> base64js.fromByteArray(encrypted); </span><span style="color: rgba(0, 0, 255, 1)">if</span> (cipherText != <span style="color: rgba(0, 0, 255, 1)">null</span> && cipherText.trim().length > 0<span style="color: rgba(0, 0, 0, 1)">) { cipherText.replace(</span>/(\s*|\t|\r|\n)/g, ""<span style="color: rgba(0, 0, 0, 1)">); } </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> cipherText; } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> ( e) { console.error(e); </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">; } } stringToByte</span>=<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(str) { </span><span style="color: rgba(0, 0, 255, 1)">var</span> bytes = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Array(); </span><span style="color: rgba(0, 0, 255, 1)">var</span><span style="color: rgba(0, 0, 0, 1)"> len, c; len </span>=<span style="color: rgba(0, 0, 0, 1)"> str.length; </span><span style="color: rgba(0, 0, 255, 1)">for</span>(<span style="color: rgba(0, 0, 255, 1)">var</span> i = 0; i < len; i++<span style="color: rgba(0, 0, 0, 1)">) { c </span>=<span style="color: rgba(0, 0, 0, 1)"> str.charCodeAt(i); </span><span style="color: rgba(0, 0, 255, 1)">if</span>(c >= 0x010000 && c <= 0x10FFFF<span style="color: rgba(0, 0, 0, 1)">) { bytes.push(((c </span>>> 18) & 0x07) | 0xF0<span style="color: rgba(0, 0, 0, 1)">); bytes.push(((c </span>>> 12) & 0x3F) | 0x80<span style="color: rgba(0, 0, 0, 1)">); bytes.push(((c </span>>> 6) & 0x3F) | 0x80<span style="color: rgba(0, 0, 0, 1)">); bytes.push((c </span>& 0x3F) | 0x80<span style="color: rgba(0, 0, 0, 1)">); } </span><span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">if</span>(c >= 0x000800 && c <= 0x00FFFF<span style="color: rgba(0, 0, 0, 1)">) { bytes.push(((c </span>>> 12) & 0x0F) | 0xE0<span style="color: rgba(0, 0, 0, 1)">); bytes.push(((c </span>>> 6) & 0x3F) | 0x80<span style="color: rgba(0, 0, 0, 1)">); bytes.push((c </span>& 0x3F) | 0x80<span style="color: rgba(0, 0, 0, 1)">); } </span><span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">if</span>(c >= 0x000080 && c <= 0x0007FF<span style="color: rgba(0, 0, 0, 1)">) { bytes.push(((c </span>>> 6) & 0x1F) | 0xC0<span style="color: rgba(0, 0, 0, 1)">); bytes.push((c </span>& 0x3F) | 0x80<span style="color: rgba(0, 0, 0, 1)">); } </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> { bytes.push(c </span>& 0xFF<span style="color: rgba(0, 0, 0, 1)">); } } </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> bytes; } byteToString</span>=<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(arr) { </span><span style="color: rgba(0, 0, 255, 1)">if</span>(<span style="color: rgba(0, 0, 255, 1)">typeof</span> arr === 'string'<span style="color: rgba(0, 0, 0, 1)">) { </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> arr; } </span><span style="color: rgba(0, 0, 255, 1)">var</span> str = ''<span style="color: rgba(0, 0, 0, 1)">, _arr </span>=<span style="color: rgba(0, 0, 0, 1)"> arr; </span><span style="color: rgba(0, 0, 255, 1)">for</span>(<span style="color: rgba(0, 0, 255, 1)">var</span> i = 0; i < _arr.length; i++<span style="color: rgba(0, 0, 0, 1)">) { </span><span style="color: rgba(0, 0, 255, 1)">var</span> one = _arr[i].toString(2<span style="color: rgba(0, 0, 0, 1)">), v </span>= one.match(/^1+?(?=0)/<span style="color: rgba(0, 0, 0, 1)">); </span><span style="color: rgba(0, 0, 255, 1)">if</span>(v && one.length == 8<span style="color: rgba(0, 0, 0, 1)">) { </span><span style="color: rgba(0, 0, 255, 1)">var</span> bytesLength = v[0<span style="color: rgba(0, 0, 0, 1)">].length; </span><span style="color: rgba(0, 0, 255, 1)">var</span> store = _arr[i].toString(2).slice(7 -<span style="color: rgba(0, 0, 0, 1)"> bytesLength); </span><span style="color: rgba(0, 0, 255, 1)">for</span>(<span style="color: rgba(0, 0, 255, 1)">var</span> st = 1; st < bytesLength; st++<span style="color: rgba(0, 0, 0, 1)">) { store </span>+= _arr[st + i].toString(2).slice(2<span style="color: rgba(0, 0, 0, 1)">); } str </span>+= String.fromCharCode(parseInt(store, 2<span style="color: rgba(0, 0, 0, 1)">)); i </span>+= bytesLength - 1<span style="color: rgba(0, 0, 0, 1)">; } </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> { str </span>+=<span style="color: rgba(0, 0, 0, 1)"> String.fromCharCode(_arr[i]); } } </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> str; }
};
2, Java backend
SM4.java
1 package cn.com.sinosoft.cas.util.sm4; 2 3 import java.io.ByteArrayInputStream; 4 import java.io.ByteArrayOutputStream; 5 6 /** 7 * SM4 encryption and decryption 8 * @author wzk 9 * 10 */ 11 public class SM4 { 12 public static final int SM4_ENCRYPT = 1; 13 14 public static final int SM4_DECRYPT = 0; 15 16 private int GET_ULONG_BE(byte[] b, int i) { 17 int n = (int) (b[i] & 0xff) << 24 | (int) ((b[i + 1] & 0xff) << 16) | (int) ((b[i + 2] & 0xff) << 8) 18 | (int) (b[i + 3] & 0xff) & 0xffffffff; 19 return n; 20 } 21 22 private void PUT_ULONG_BE(int n, byte[] b, int i) { 23 b[i] = (byte) (int) (0xFF & n >> 24); 24 b[i + 1] = (byte) (int) (0xFF & n >> 16); 25 b[i + 2] = (byte) (int) (0xFF & n >> 8); 26 b[i + 3] = (byte) (int) (0xFF & n); 27 } 28 29 private int SHL(int x, int n) { 30 return (x & 0xFFFFFFFF) << n; 31 } 32 33 private int ROTL(int x, int n) { 34 return SHL(x, n) | x >> (32 - n); 35 } 36 37 public static final byte[] SboxTable = { (byte) 0xd6, (byte) 0x90, (byte) 0xe9, (byte) 0xfe, (byte) 0xcc, 38 (byte) 0xe1, 0x3d, (byte) 0xb7, 0x16, (byte) 0xb6, 0x14, (byte) 0xc2, 0x28, (byte) 0xfb, 0x2c, 0x05, 0x2b, 39 0x67, (byte) 0x9a, 0x76, 0x2a, (byte) 0xbe, 0x04, (byte) 0xc3, (byte) 0xaa, 0x44, 0x13, 0x26, 0x49, 40 (byte) 0x86, 0x06, (byte) 0x99, (byte) 0x9c, 0x42, 0x50, (byte) 0xf4, (byte) 0x91, (byte) 0xef, (byte) 0x98, 41 0x7a, 0x33, 0x54, 0x0b, 0x43, (byte) 0xed, (byte) 0xcf, (byte) 0xac, 0x62, (byte) 0xe4, (byte) 0xb3, 0x1c, 42 (byte) 0xa9, (byte) 0xc9, 0x08, (byte) 0xe8, (byte) 0x95, (byte) 0x80, (byte) 0xdf, (byte) 0x94, 43 (byte) 0xfa, 0x75, (byte) 0x8f, 0x3f, (byte) 0xa6, 0x47, 0x07, (byte) 0xa7, (byte) 0xfc, (byte) 0xf3, 0x73, 44 0x17, (byte) 0xba, (byte) 0x83, 0x59, 0x3c, 0x19, (byte) 0xe6, (byte) 0x85, 0x4f, (byte) 0xa8, 0x68, 0x6b, 45 (byte) 0x81, (byte) 0xb2, 0x71, 0x64, (byte) 0xda, (byte) 0x8b, (byte) 0xf8, (byte) 0xeb, 0x0f, 0x4b, 0x70, 46 0x56, (byte) 0x9d, 0x35, 0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, (byte) 0xd1, (byte) 0xa2, 0x25, 0x22, 0x7c, 47 0x3b, 0x01, 0x21, 0x78, (byte) 0x87, (byte) 0xd4, 0x00, 0x46, 0x57, (byte) 0x9f, (byte) 0xd3, 0x27, 0x52, 48 0x4c, 0x36, 0x02, (byte) 0xe7, (byte) 0xa0, (byte) 0xc4, (byte) 0xc8, (byte) 0x9e, (byte) 0xea, (byte) 0xbf, 49 (byte) 0x8a, (byte) 0xd2, 0x40, (byte) 0xc7, 0x38, (byte) 0xb5, (byte) 0xa3, (byte) 0xf7, (byte) 0xf2, 50 (byte) 0xce, (byte) 0xf9, 0x61, 0x15, (byte) 0xa1, (byte) 0xe0, (byte) 0xae, 0x5d, (byte) 0xa4, (byte) 0x9b, 51 0x34, 0x1a, 0x55, (byte) 0xad, (byte) 0x93, 0x32, 0x30, (byte) 0xf5, (byte) 0x8c, (byte) 0xb1, (byte) 0xe3, 52 0x1d, (byte) 0xf6, (byte) 0xe2, 0x2e, (byte) 0x82, 0x66, (byte) 0xca, 0x60, (byte) 0xc0, 0x29, 0x23, 53 (byte) 0xab, 0x0d, 0x53, 0x4e, 0x6f, (byte) 0xd5, (byte) 0xdb, 0x37, 0x45, (byte) 0xde, (byte) 0xfd, 54 (byte) 0x8e, 0x2f, 0x03, (byte) 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51, (byte) 0x8d, 0x1b, (byte) 0xaf, 55 (byte) 0x92, (byte) 0xbb, (byte) 0xdd, (byte) 0xbc, 0x7f, 0x11, (byte) 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, 56 (byte) 0xd8, 0x0a, (byte) 0xc1, 0x31, (byte) 0x88, (byte) 0xa5, (byte) 0xcd, 0x7b, (byte) 0xbd, 0x2d, 0x74, 57 (byte) 0xd0, 0x12, (byte) 0xb8, (byte) 0xe5, (byte) 0xb4, (byte) 0xb0, (byte) 0x89, 0x69, (byte) 0x97, 0x4a, 58 0x0c, (byte) 0x96, 0x77, 0x7e, 0x65, (byte) 0xb9, (byte) 0xf1, 0x09, (byte) 0xc5, 0x6e, (byte) 0xc6, 59 (byte) 0x84, 0x18, (byte) 0xf0, 0x7d, (byte) 0xec, 0x3a, (byte) 0xdc, 0x4d, 0x20, 0x79, (byte) 0xee, 0x5f, 60 0x3e, (byte) 0xd7, (byte) 0xcb, 0x39, 0x48 }; 61 62 public static final int[] FK = { 0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc }; 63 64 public static final int[] CK = { 0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269, 0x70777e85, 0x8c939aa1, 0xa8afb6bd, 65 0xc4cbd2d9, 0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249, 0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9, 66 0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229, 0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299, 0xa0a7aeb5, 67 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209, 0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279 }; 68 69 private byte sm4Sbox(byte inch) { 70 int i = inch & 0xFF; 71 byte retVal = SboxTable[i]; 72 return retVal; 73 } 74 75 private int sm4Lt(int ka) { 76 int bb = 0; 77 int c = 0; 78 byte[] a = new byte[4]; 79 byte[] b = new byte[4]; 80 PUT_ULONG_BE(ka, a, 0); 81 b[0] = sm4Sbox(a[0]); 82 b[1] = sm4Sbox(a[1]); 83 b[2] = sm4Sbox(a[2]); 84 b[3] = sm4Sbox(a[3]); 85 bb = GET_ULONG_BE(b, 0); 86 c = bb ^ ROTL(bb, 2) ^ ROTL(bb, 10) ^ ROTL(bb, 18) ^ ROTL(bb, 24); 87 return c; 88 } 89 90 private int sm4F(int x0, int x1, int x2, int x3, int rk) { 91 return x0 ^ sm4Lt(x1 ^ x2 ^ x3 ^ rk); 92 } 93 94 private int sm4CalciRK(int ka) { 95 int bb = 0; 96 int rk = 0; 97 byte[] a = new byte[4]; 98 byte[] b = new byte[4]; 99 PUT_ULONG_BE(ka, a, 0); 100 b[0] = sm4Sbox(a[0]); 101 b[1] = sm4Sbox(a[1]); 102 b[2] = sm4Sbox(a[2]); 103 b[3] = sm4Sbox(a[3]); 104 bb = GET_ULONG_BE(b, 0); 105 rk = bb ^ ROTL(bb, 13) ^ ROTL(bb, 23); 106 return rk; 107 } 108 109 private void sm4_setkey(int[] SK, byte[] key) { 110 int[] MK = new int[4]; 111 int[] k = new int[36]; 112 int i = 0; 113 MK[0] = GET_ULONG_BE(key, 0); 114 MK[1] = GET_ULONG_BE(key, 4); 115 MK[2] = GET_ULONG_BE(key, 8); 116 MK[3] = GET_ULONG_BE(key, 12); 117 k[0] = MK[0] ^ (int) FK[0]; 118 k[1] = MK[1] ^ (int) FK[1]; 119 k[2] = MK[2] ^ (int) FK[2]; 120 k[3] = MK[3] ^ (int) FK[3]; 121 for (; i < 32; i++) { 122 k[(i + 4)] = (k[i] ^ sm4CalciRK(k[(i + 1)] ^ k[(i + 2)] ^ k[(i + 3)] ^ (int) CK[i])); 123 SK[i] = k[(i + 4)]; 124 } 125 } 126 127 private void sm4_one_round(int[] sk, byte[] input, byte[] output) { 128 int i = 0; 129 int[] ulbuf = new int[36]; 130 ulbuf[0] = GET_ULONG_BE(input, 0); 131 ulbuf[1] = GET_ULONG_BE(input, 4); 132 ulbuf[2] = GET_ULONG_BE(input, 8); 133 ulbuf[3] = GET_ULONG_BE(input, 12); 134 while (i < 32) { 135 ulbuf[(i + 4)] = sm4F(ulbuf[i], ulbuf[(i + 1)], ulbuf[(i + 2)], ulbuf[(i + 3)], sk[i]); 136 i++; 137 } 138 PUT_ULONG_BE(ulbuf[35], output, 0); 139 PUT_ULONG_BE(ulbuf[34], output, 4); 140 PUT_ULONG_BE(ulbuf[33], output, 8); 141 PUT_ULONG_BE(ulbuf[32], output, 12); 142 } 143 144 private byte[] padding(byte[] input, int mode) { 145 if (input == null) { 146 return null; 147 } 148 149 byte[] ret = (byte[]) null; 150 if (mode == SM4_ENCRYPT) { 151 int p = 16 - input.length % 16; 152 ret = new byte[input.length + p]; 153 System.arraycopy(input, 0, ret, 0, input.length); 154 for (int i = 0; i < p; i++) { 155 ret[input.length + i] = (byte) p; 156 } 157 } else { 158 int p = input[input.length - 1]; 159 ret = new byte[input.length - p]; 160 System.arraycopy(input, 0, ret, 0, input.length - p); 161 } 162 return ret; 163 } 164 165 public void sm4_setkey_enc(SM4_Context ctx, byte[] key) throws Exception { 166 if (ctx == null) { 167 throw new Exception("ctx is null!"); 168 } 169 170 if (key == null || key.length != 16) { 171 throw new Exception("key error!"); 172 } 173 174 ctx.mode = SM4_ENCRYPT; 175 sm4_setkey(ctx.sk, key); 176 } 177 178 public byte[] sm4_crypt_ecb(SM4_Context ctx, byte[] input) throws Exception { 179 if (input == null) { 180 throw new Exception("input is null!"); 181 } 182 183 if ((ctx.isPadding) && (ctx.mode == SM4_ENCRYPT)) { 184 input = padding(input, SM4_ENCRYPT); 185 } 186 187 int length = input.length; 188 ByteArrayInputStream bins = new ByteArrayInputStream(input); 189 ByteArrayOutputStream bous = new ByteArrayOutputStream(); 190 for (; length > 0; length -= 16) { 191 byte[] in = new byte[16]; 192 byte[] out = new byte[16]; 193 bins.read(in); 194 sm4_one_round(ctx.sk, in, out); 195 bous.write(out); 196 } 197 198 byte[] output = bous.toByteArray(); 199 if (ctx.isPadding && ctx.mode == SM4_DECRYPT) { 200 output = padding(output, SM4_DECRYPT); 201 } 202 bins.close(); 203 bous.close(); 204 return output; 205 } 206 207 public void sm4_setkey_dec(SM4_Context ctx, byte[] key) throws Exception { 208 if (ctx == null) { 209 throw new Exception("ctx is null!"); 210 } 211 212 if (key == null || key.length != 16) { 213 throw new Exception("key error!"); 214 } 215 216 int i = 0; 217 ctx.mode = SM4_DECRYPT; 218 sm4_setkey(ctx.sk, key); 219 for (i = 0; i < 16; i++) { 220 SWAP(ctx.sk, i); 221 } 222 } 223 224 private void SWAP(int[] sk, int i) { 225 int t = sk[i]; 226 sk[i] = sk[(31 - i)]; 227 sk[(31 - i)] = t; 228 } 229 230 public byte[] sm4_crypt_cbc(SM4_Context ctx, byte[] iv, byte[] input) throws Exception { 231 if (iv == null || iv.length != 16) { 232 throw new Exception("iv error!"); 233 } 234 235 if (input == null) { 236 throw new Exception("input is null!"); 237 } 238 239 if (ctx.isPadding && ctx.mode == SM4_ENCRYPT) { 240 input = padding(input, SM4_ENCRYPT); 241 } 242 243 int i = 0; 244 int length = input.length; 245 ByteArrayInputStream bins = new ByteArrayInputStream(input); 246 ByteArrayOutputStream bous = new ByteArrayOutputStream(); 247 if (ctx.mode == SM4_ENCRYPT) { 248 for (; length > 0; length -= 16) { 249 byte[] in = new byte[16]; 250 byte[] out = new byte[16]; 251 byte[] out1 = new byte[16]; 252 253 bins.read(in); 254 for (i = 0; i < 16; i++) { 255 out[i] = ((byte) (in[i] ^ iv[i])); 256 } 257 sm4_one_round(ctx.sk, out, out1); 258 System.arraycopy(out1, 0, iv, 0, 16); 259 bous.write(out1); 260 } 261 } else { 262 byte[] temp = new byte[16]; 263 for (; length > 0; length -= 16) { 264 byte[] in = new byte[16]; 265 byte[] out = new byte[16]; 266 byte[] out1 = new byte[16]; 267 268 bins.read(in); 269 System.arraycopy(in, 0, temp, 0, 16); 270 sm4_one_round(ctx.sk, in, out); 271 for (i = 0; i < 16; i++) { 272 out1[i] = ((byte) (out[i] ^ iv[i])); 273 } 274 System.arraycopy(temp, 0, iv, 0, 16); 275 bous.write(out1); 276 } 277 } 278 279 byte[] output = bous.toByteArray(); 280 if (ctx.isPadding && ctx.mode == SM4_DECRYPT) { 281 output = padding(output, SM4_DECRYPT); 282 } 283 bins.close(); 284 bous.close(); 285 return output; 286 } 287 288 }
SM4_Context.java
1 package cn.com.sinosoft.cas.util.sm4; 2 3 /** 4 * SM4 encryption and decryption 5 * @author wzk 6 * 7 */ 8 public class SM4_Context { 9 public int mode; 10 11 public int[] sk; 12 13 public boolean isPadding; 14 15 public SM4_Context() { 16 this.mode = 1; 17 this.isPadding = true; 18 this.sk = new int[32]; 19 } 20 }
Util.java
1 package cn.com.sinosoft.cas.util.sm4; 2 3 import java.math.BigInteger; 4 5 /** 6 * SM4 encryption and decryption tool class 7 * @author wzk 8 * 9 */ 10 public class Util { 11 /** 12 * shaping and converting into byte stream (byte array) data transmitted by the network 13 * 14 * @param num 15 * one integer data 16 * @ return 4-byte array 17 */ 18 public static byte[] intToBytes(int num) { 19 byte[] bytes = new byte[4]; 20 bytes[0] = (byte) (0xff & (num >> 0)); 21 bytes[1] = (byte) (0xff & (num >> 8)); 22 bytes[2] = (byte) (0xff & (num >> 16)); 23 bytes[3] = (byte) (0xff & (num >> 24)); 24 return bytes; 25 } 26 27 /** 28 * convert four bytes of byte data into an integer data 29 * 30 * @param bytes 31 * 4-byte byte array 32 * @ return an integer data 33 */ 34 public static int byteToInt(byte[] bytes) { 35 int num = 0; 36 int temp; 37 temp = (0x000000ff & (bytes[0])) << 0; 38 num = num | temp; 39 temp = (0x000000ff & (bytes[1])) << 8; 40 num = num | temp; 41 temp = (0x000000ff & (bytes[2])) << 16; 42 num = num | temp; 43 temp = (0x000000ff & (bytes[3])) << 24; 44 num = num | temp; 45 return num; 46 } 47 48 /** 49 * long shaping is converted into byte stream (byte array) data transmitted over the network 50 * 51 * @param num 52 * one long integer data 53 * @ return 4-byte array 54 */ 55 public static byte[] longToBytes(long num) { 56 byte[] bytes = new byte[8]; 57 for (int i = 0; i < 8; i++) { 58 bytes[i] = (byte) (0xff & (num >> (i * 8))); 59 } 60 61 return bytes; 62 } 63 64 /** 65 * large number conversion byte stream (byte array) data 66 * 67 * @param n 68 * @return 69 */ 70 public static byte[] byteConvert32Bytes(BigInteger n) { 71 byte tmpd[] = (byte[]) null; 72 if (n == null) { 73 return null; 74 } 75 76 if (n.toByteArray().length == 33) { 77 tmpd = new byte[32]; 78 System.arraycopy(n.toByteArray(), 1, tmpd, 0, 32); 79 } else if (n.toByteArray().length == 32) { 80 tmpd = n.toByteArray(); 81 } else { 82 tmpd = new byte[32]; 83 for (int i = 0; i < 32 - n.toByteArray().length; i++) { 84 tmpd[i] = 0; 85 } 86 System.arraycopy(n.toByteArray(), 0, tmpd, 32 - n.toByteArray().length, n.toByteArray().length); 87 } 88 return tmpd; 89 } 90 91 /** 92 * convert byte stream (byte array) data to large number 93 * 94 * @param b 95 * @return 96 */ 97 public static BigInteger byteConvertInteger(byte[] b) { 98 if (b[0] < 0) { 99 byte[] temp = new byte[b.length + 1]; 100 temp[0] = 0; 101 System.arraycopy(b, 0, temp, 1, b.length); 102 return new BigInteger(temp); 103 } 104 return new BigInteger(b); 105 } 106 107 /** 108 * get value from byte array (hexadecimal digit) 109 * 110 * @param bytes 111 * @return 112 */ 113 public static String getHexString(byte[] bytes) { 114 return getHexString(bytes, true); 115 } 116 117 /** 118 * get value from byte array (hexadecimal digit) 119 * 120 * @param bytes 121 * @param upperCase 122 * @return 123 */ 124 public static String getHexString(byte[] bytes, boolean upperCase) { 125 String ret = ""; 126 for (int i = 0; i < bytes.length; i++) { 127 ret += Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1); 128 } 129 return upperCase ? ret.toUpperCase() : ret; 130 } 131 132 /** 133 * print hex string 134 * 135 * @param bytes 136 */ 137 public static void printHexString(byte[] bytes) { 138 for (int i = 0; i < bytes.length; i++) { 139 String hex = Integer.toHexString(bytes[i] & 0xFF); 140 if (hex.length() == 1) { 141 hex = '0' + hex; 142 } 143 System.out.print("0x" + hex.toUpperCase() + ","); 144 } 145 System.out.println(""); 146 } 147 148 /** 149 * Convert hex string to byte[] 150 * 151 * @param hexString 152 * the hex string 153 * @return byte[] 154 */ 155 public static byte[] hexStringToBytes(String hexString) { 156 if (hexString == null || hexString.equals("")) { 157 return null; 158 } 159 160 hexString = hexString.toUpperCase(); 161 int length = hexString.length() / 2; 162 char[] hexChars = hexString.toCharArray(); 163 byte[] d = new byte[length]; 164 for (int i = 0; i < length; i++) { 165 int pos = i * 2; 166 d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1])); 167 } 168 return d; 169 } 170 171 /** 172 * Convert char to byte 173 * 174 * @param c 175 * char 176 * @return byte 177 */ 178 public static byte charToByte(char c) { 179 return (byte) "0123456789ABCDEF".indexOf(c); 180 } 181 182 /** 183 * lowercase character array used to establish the output of hexadecimal characters 184 */ 185 private static final char[] DIGITS_LOWER = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 186 'e', 'f' }; 187 188 /** 189 * uppercase character array used to establish the output of hexadecimal characters 190 */ 191 private static final char[] DIGITS_UPPER = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 192 'E', 'F' }; 193 194 /** 195 * convert byte array to hexadecimal character array 196 * 197 * @param data 198 * byte[] 199 * @ return hex char [] 200 */ 201 public static char[] encodeHex(byte[] data) { 202 return encodeHex(data, true); 203 } 204 205 /** 206 * convert byte array to hexadecimal character array 207 * 208 * @param data 209 * byte[] 210 * @param toLowerCase 211 * < code > true < / code > is converted to lowercase format, < code > false < / code > is converted to uppercase format 212 * @ return hex char [] 213 */ 214 public static char[] encodeHex(byte[] data, boolean toLowerCase) { 215 return encodeHex(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER); 216 } 217 218 /** 219 * convert byte array to hexadecimal character array 220 * 221 * @param data 222 * byte[] 223 * @param toDigits 224 * char [] for control output 225 * @ return hex char [] 226 */ 227 protected static char[] encodeHex(byte[] data, char[] toDigits) { 228 int l = data.length; 229 char[] out = new char[l << 1]; 230 // two characters form the hex value. 231 for (int i = 0, j = 0; i < l; i++) { 232 out[j++] = toDigits[(0xF0 & data[i]) >>> 4]; 233 out[j++] = toDigits[0x0F & data[i]]; 234 } 235 return out; 236 } 237 238 /** 239 * convert byte array to hexadecimal string 240 * 241 * @param data 242 * byte[] 243 * @ return hex String 244 */ 245 public static String encodeHexString(byte[] data) { 246 return encodeHexString(data, true); 247 } 248 249 /** 250 * convert byte array to hexadecimal string 251 * 252 * @param data 253 * byte[] 254 * @param toLowerCase 255 * < code > true < / code > is converted to lowercase format, < code > false < / code > is converted to uppercase format 256 * @ return hex String 257 */ 258 public static String encodeHexString(byte[] data, boolean toLowerCase) { 259 return encodeHexString(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER); 260 } 261 262 /** 263 * convert byte array to hexadecimal string 264 * 265 * @param data 266 * byte[] 267 * @param toDigits 268 * char [] for control output 269 * @ return hex String 270 */ 271 protected static String encodeHexString(byte[] data, char[] toDigits) { 272 return new String(encodeHex(data, toDigits)); 273 } 274 275 /** 276 * convert hexadecimal character array to byte array 277 * 278 * @param data 279 * hex char [] 280 * @return byte[] 281 * @throws RuntimeException 282 * if the source hexadecimal character array is an odd length, a runtime exception will be thrown 283 */ 284 public static byte[] decodeHex(char[] data) { 285 int len = data.length; 286 287 if ((len & 0x01) != 0) { 288 throw new RuntimeException("Odd number of characters."); 289 } 290 291 byte[] out = new byte[len >> 1]; 292 293 // two characters form the hex value. 294 for (int i = 0, j = 0; j < len; i++) { 295 int f = toDigit(data[j], j) << 4; 296 j++; 297 f = f | toDigit(data[j], j); 298 j++; 299 out[i] = (byte) (f & 0xFF); 300 } 301 302 return out; 303 } 304 305 /** 306 * converts hexadecimal characters to an integer 307 * 308 * @param ch 309 * hex char 310 * @param index 311 * position of hexadecimal characters in character array 312 * @ return an integer 313 * @throws RuntimeException 314 * throw a runtime exception when ch is not a legal hexadecimal character 315 */ 316 protected static int toDigit(char ch, int index) { 317 int digit = Character.digit(ch, 16); 318 if (digit == -1) { 319 throw new RuntimeException("Illegal hexadecimal character " + ch + " at index " + index); 320 } 321 return digit; 322 } 323 324 /** 325 * numeric string to ASCII string 326 * 327 * @param String 328 * string 329 * @ return ascii string 330 */ 331 public static String StringToAsciiString(String content) { 332 String result = ""; 333 int max = content.length(); 334 for (int i = 0; i < max; i++) { 335 char c = content.charAt(i); 336 String b = Integer.toHexString(c); 337 result = result + b; 338 } 339 return result; 340 } 341 342 /** 343 * hex to string 344 * 345 * @param hexString 346 * hexadecimal string 347 * @param encodeType 348 * encoding type 4: Unicode, 2: normal encoding 349 * @ return string 350 */ 351 public static String hexStringToString(String hexString, int encodeType) { 352 String result = ""; 353 int max = hexString.length() / encodeType; 354 for (int i = 0; i < max; i++) { 355 char c = (char) hexStringToAlgorism(hexString.substring(i * encodeType, (i + 1) * encodeType)); 356 result += c; 357 } 358 return result; 359 } 360 361 /** 362 * hexadecimal string packed decimal 363 * 364 * @param hex 365 * hex string 366 * @ return decimal value 367 */ 368 public static int hexStringToAlgorism(String hex) { 369 hex = hex.toUpperCase(); 370 int max = hex.length(); 371 int result = 0; 372 for (int i = max; i > 0; i--) { 373 char c = hex.charAt(i - 1); 374 int algorism = 0; 375 if (c >= '0' && c <= '9') { 376 algorism = c - '0'; 377 } else { 378 algorism = c - 55; 379 } 380 result += Math.pow(16, max - i) * algorism; 381 } 382 return result; 383 } 384 385 /** 386 * 16 to binary 387 * 388 * @param hex 389 * hex string 390 * @ return binary string 391 */ 392 public static String hexStringToBinary(String hex) { 393 hex = hex.toUpperCase(); 394 String result = ""; 395 int max = hex.length(); 396 for (int i = 0; i < max; i++) { 397 char c = hex.charAt(i); 398 switch (c) { 399 case '0': 400 result += "0000"; 401 break; 402 case '1': 403 result += "0001"; 404 break; 405 case '2': 406 result += "0010"; 407 break; 408 case '3': 409 result += "0011"; 410 break; 411 case '4': 412 result += "0100"; 413 break; 414 case '5': 415 result += "0101"; 416 break; 417 case '6': 418 result += "0110"; 419 break; 420 case '7': 421 result += "0111"; 422 break; 423 case '8': 424 result += "1000"; 425 break; 426 case '9': 427 result += "1001"; 428 break; 429 case 'A': 430 result += "1010"; 431 break; 432 case 'B': 433 result += "1011"; 434 break; 435 case 'C': 436 result += "1100"; 437 break; 438 case 'D': 439 result += "1101"; 440 break; 441 case 'E': 442 result += "1110"; 443 break; 444 case 'F': 445 result += "1111"; 446 break; 447 } 448 } 449 return result; 450 } 451 452 /** 453 * ascii string to numeric string 454 * 455 * @param String 456 * ascii string 457 * @ return string 458 */ 459 public static String AsciiStringToString(String content) { 460 String result = ""; 461 int length = content.length() / 2; 462 for (int i = 0; i < length; i++) { 463 String c = content.substring(i * 2, i * 2 + 2); 464 int a = hexStringToAlgorism(c); 465 char b = (char) a; 466 String d = String.valueOf(b); 467 result += d; 468 } 469 return result; 470 } 471 472 /** 473 * converts decimal to a hexadecimal string of the specified length 474 * 475 * @param algorism 476 * int decimal digits 477 * @param maxLength 478 * hexadecimal string length after int conversion 479 * @ return string hexadecimal string after conversion 480 */ 481 public static String algorismToHexString(int algorism, int maxLength) { 482 String result = ""; 483 result = Integer.toHexString(algorism); 484 485 if (result.length() % 2 == 1) { 486 result = "0" + result; 487 } 488 return patchHexString(result.toUpperCase(), maxLength); 489 } 490 491 /** 492 * byte array to normal string (ASCII corresponding character) 493 * 494 * @param bytearray 495 * byte[] 496 * @return String 497 */ 498 public static String byteToString(byte[] bytearray) { 499 String result = ""; 500 char temp; 501 502 int length = bytearray.length; 503 for (int i = 0; i < length; i++) { 504 temp = (char) bytearray[i]; 505 result += temp; 506 } 507 return result; 508 } 509 510 /** 511 * binary string to decimal 512 * 513 * @param binary 514 * binary string 515 * @ return decimal value 516 */ 517 public static int binaryToAlgorism(String binary) { 518 int max = binary.length(); 519 int result = 0; 520 for (int i = max; i > 0; i--) { 521 char c = binary.charAt(i - 1); 522 int algorism = c - '0'; 523 result += Math.pow(2, max - i) * algorism; 524 } 525 return result; 526 } 527 528 /** 529 * convert decimal to hexadecimal string 530 * 531 * @param algorism 532 * int decimal number 533 * @ return string hexadecimal string 534 */ 535 public static String algorismToHEXString(int algorism) { 536 String result = ""; 537 result = Integer.toHexString(algorism); 538 539 if (result.length() % 2 == 1) { 540 result = "0" + result; 541 542 } 543 result = result.toUpperCase(); 544 545 return result; 546 } 547 548 /** 549 * hex string is preceded by 0, which is mainly used for insufficient length digits. 550 * 551 * @param str 552 * string hexadecimal string with supplementary length required 553 * @param maxLength 554 * int length of hexadecimal string after complement 555 * @ return supplementary result 556 */ 557 static public String patchHexString(String str, int maxLength) { 558 String temp = ""; 559 for (int i = 0; i < maxLength - str.length(); i++) { 560 temp = "0" + temp; 561 } 562 str = (temp + str).substring(0, maxLength); 563 return str; 564 } 565 566 /** 567 * convert a string to int 568 * 569 * @param s 570 * string string to convert 571 * @param defaultInt 572 * int if an exception occurs, the number returned by default 573 * @param radix 574 * int what is the base of the string to be converted, such as 16 8 10 575 * @ return int converted number 576 */ 577 public static int parseToInt(String s, int defaultInt, int radix) { 578 int i = 0; 579 try { 580 i = Integer.parseInt(s, radix); 581 } catch (NumberFormatException ex) { 582 i = defaultInt; 583 } 584 return i; 585 } 586 587 /** 588 * converts a decimal numeric string to int 589 * 590 * @param s 591 * string the string to convert 592 * @param defaultInt 593 * int if an exception occurs, the number returned by default 594 * @ return int converted number 595 */ 596 public static int parseToInt(String s, int defaultInt) { 597 int i = 0; 598 try { 599 i = Integer.parseInt(s); 600 } catch (NumberFormatException ex) { 601 i = defaultInt; 602 } 603 return i; 604 } 605 606 /** 607 * convert hex string to byte array 608 * 609 * @return the array of byte 610 */ 611 public static byte[] hexToByte(String hex) throws IllegalArgumentException { 612 if (hex.length() % 2 != 0) { 613 throw new IllegalArgumentException(); 614 } 615 char[] arr = hex.toCharArray(); 616 byte[] b = new byte[hex.length() / 2]; 617 for (int i = 0, j = 0, l = hex.length(); i < l; i++, j++) { 618 String swap = "" + arr[i++] + arr[i]; 619 int byteint = Integer.parseInt(swap, 16) & 0xFF; 620 b[j] = new Integer(byteint).byteValue(); 621 } 622 return b; 623 } 624 625 /** 626 * byte array converted to hexadecimal string 627 * 628 * @param b 629 * byte [] byte array to be converted 630 * @ return string hex string 631 */ 632 public static String byteToHex(byte b[]) { 633 if (b == null) { 634 throw new IllegalArgumentException("Argument b ( byte array ) is null! "); 635 } 636 String hs = ""; 637 String stmp = ""; 638 for (int n = 0; n < b.length; n++) { 639 stmp = Integer.toHexString(b[n] & 0xff); 640 if (stmp.length() == 1) { 641 hs = hs + "0" + stmp; 642 } else { 643 hs = hs + stmp; 644 } 645 } 646 return hs.toUpperCase(); 647 } 648 649 public static byte[] subByte(byte[] input, int startIndex, int length) { 650 byte[] bt = new byte[length]; 651 for (int i = 0; i < length; i++) { 652 bt[i] = input[i + startIndex]; 653 } 654 return bt; 655 } 656 }
SM4Utils.java
package cn.com.sinosoft.cas.util.sm4;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import java.io.UnsupportedEncodingException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
- sm4 encryption and decryption
- CBC and ECB modes
- @author wzk
/
@SuppressWarnings("restriction")
public class SM4Utils {
/**
*Consistent with the front-end key
/
private static String secretKey = "11sade343f";
/**
*Consistent with front-end iv
*/
private static String iv = "3evfgt65334";
</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">static</span> String UTF_8 = "UTF-8"<span style="color: rgba(0, 0, 0, 1)">; </span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">final</span> <span style="color: rgba(0, 0, 255, 1)">boolean</span> hexString = <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">; </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> SM4Utils() { } </span><span style="color: rgba(0, 128, 0, 1)">//< / span > < span style = "color: RGBA (0, 128, 0, 1)" > ECB mode encryption</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span><span style="color: rgba(0, 0, 0, 1)"> String encryptData_ECB(String plainText) { </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> { SM4_Context ctx </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> SM4_Context(); ctx.isPadding </span>= <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">; ctx.mode </span>=<span style="color: rgba(0, 0, 0, 1)"> SM4.SM4_ENCRYPT; </span><span style="color: rgba(0, 0, 255, 1)">byte</span><span style="color: rgba(0, 0, 0, 1)">[] keyBytes; keyBytes </span>=<span style="color: rgba(0, 0, 0, 1)"> secretKey.getBytes(); SM4 sm4 </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> SM4(); sm4.sm4_setkey_enc(ctx, keyBytes); </span><span style="color: rgba(0, 0, 255, 1)">byte</span>[] encrypted =<span style="color: rgba(0, 0, 0, 1)"> sm4.sm4_crypt_ecb(ctx, plainText.getBytes(UTF_8)); String cipherText </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> BASE64Encoder().encode(encrypted); </span><span style="color: rgba(0, 0, 255, 1)">if</span> (cipherText != <span style="color: rgba(0, 0, 255, 1)">null</span> && cipherText.trim().length() > 0<span style="color: rgba(0, 0, 0, 1)">) { Pattern p </span>= Pattern.compile("\\s*|\t|\r|\n"<span style="color: rgba(0, 0, 0, 1)">); Matcher m </span>=<span style="color: rgba(0, 0, 0, 1)"> p.matcher(cipherText); cipherText </span>= m.replaceAll(""<span style="color: rgba(0, 0, 0, 1)">); } </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> cipherText; } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (Exception e) { e.printStackTrace(); </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">; } } </span><span style="color: rgba(0, 128, 0, 1)">//< / span > < span style = "color: RGBA (0, 128, 0, 1)" > ECB mode decryption</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span><span style="color: rgba(0, 0, 0, 1)"> String decryptData_ECB(String cipherText) { </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> { SM4_Context ctx </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> SM4_Context(); ctx.isPadding </span>= <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">; ctx.mode </span>=<span style="color: rgba(0, 0, 0, 1)"> SM4.SM4_DECRYPT; </span><span style="color: rgba(0, 0, 255, 1)">byte</span><span style="color: rgba(0, 0, 0, 1)">[] keyBytes; keyBytes </span>=<span style="color: rgba(0, 0, 0, 1)"> secretKey.getBytes(); SM4 sm4 </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> SM4(); sm4.sm4_setkey_dec(ctx, keyBytes); </span><span style="color: rgba(0, 0, 255, 1)">byte</span>[] decrypted = sm4.sm4_crypt_ecb(ctx, <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> BASE64Decoder().decodeBuffer(cipherText)); </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> String(decrypted, UTF_8); } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (Exception e) { e.printStackTrace(); </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">; } } </span><span style="color: rgba(0, 128, 0, 1)">//< / span > < span style = "color: RGBA (0, 128, 0, 1)" > CBC mode encryption</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span><span style="color: rgba(0, 0, 0, 1)"> String encryptData_CBC(String plainText) { </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> { SM4_Context ctx </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> SM4_Context(); ctx.isPadding </span>= <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">; ctx.mode </span>=<span style="color: rgba(0, 0, 0, 1)"> SM4.SM4_ENCRYPT; </span><span style="color: rgba(0, 0, 255, 1)">byte</span><span style="color: rgba(0, 0, 0, 1)">[] keyBytes; </span><span style="color: rgba(0, 0, 255, 1)">byte</span><span style="color: rgba(0, 0, 0, 1)">[] ivBytes; keyBytes </span>=<span style="color: rgba(0, 0, 0, 1)"> secretKey.getBytes(); ivBytes </span>=<span style="color: rgba(0, 0, 0, 1)"> iv.getBytes(); SM4 sm4 </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> SM4(); sm4.sm4_setkey_enc(ctx, keyBytes); </span><span style="color: rgba(0, 0, 255, 1)">byte</span>[] encrypted =<span style="color: rgba(0, 0, 0, 1)"> sm4.sm4_crypt_cbc(ctx, ivBytes, plainText.getBytes(UTF_8)); String cipherText </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> BASE64Encoder().encode(encrypted); </span><span style="color: rgba(0, 0, 255, 1)">if</span> (cipherText != <span style="color: rgba(0, 0, 255, 1)">null</span> && cipherText.trim().length() > 0<span style="color: rgba(0, 0, 0, 1)">) { Pattern p </span>= Pattern.compile("\\s*|\t|\r|\n"<span style="color: rgba(0, 0, 0, 1)">); Matcher m </span>=<span style="color: rgba(0, 0, 0, 1)"> p.matcher(cipherText); cipherText </span>= m.replaceAll(""<span style="color: rgba(0, 0, 0, 1)">); } </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> cipherText; } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (Exception e) { e.printStackTrace(); </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">; } } </span><span style="color: rgba(0, 128, 0, 1)">//< / span > < span style = "color: RGBA (0, 128, 0, 1)" > CBC mode decryption</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span><span style="color: rgba(0, 0, 0, 1)"> String decryptData_CBC(String cipherText) { </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> { SM4_Context ctx </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> SM4_Context(); ctx.isPadding </span>= <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">; ctx.mode </span>=<span style="color: rgba(0, 0, 0, 1)"> SM4.SM4_DECRYPT; </span><span style="color: rgba(0, 0, 255, 1)">byte</span><span style="color: rgba(0, 0, 0, 1)">[] keyBytes; </span><span style="color: rgba(0, 0, 255, 1)">byte</span><span style="color: rgba(0, 0, 0, 1)">[] ivBytes; </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (hexString) { keyBytes </span>=<span style="color: rgba(0, 0, 0, 1)"> Util.hexStringToBytes(secretKey); ivBytes </span>=<span style="color: rgba(0, 0, 0, 1)"> Util.hexStringToBytes(iv); } </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> { keyBytes </span>=<span style="color: rgba(0, 0, 0, 1)"> secretKey.getBytes(); ivBytes </span>=<span style="color: rgba(0, 0, 0, 1)"> iv.getBytes(); } SM4 sm4 </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> SM4(); sm4.sm4_setkey_dec(ctx, keyBytes); </span><span style="color: rgba(0, 0, 255, 1)">byte</span>[] decrypted = sm4.sm4_crypt_cbc(ctx, ivBytes, <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> BASE64Decoder().decodeBuffer(cipherText)); </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> String(decrypted, UTF_8); } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (Exception e) { e.printStackTrace(); </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">; } } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span> main(String[] args) <span style="color: rgba(0, 0, 255, 1)">throws</span><span style="color: rgba(0, 0, 0, 1)"> UnsupportedEncodingException { String plainText </span>= "Zhongke soft"<span style="color: rgba(0, 0, 0, 1)">; String cipherText </span>=<span style="color: rgba(0, 0, 0, 1)"> SM4Utils.encryptData_ECB(plainText); System.out.println(</span>"ECB Pattern encryption ciphertext: " +<span style="color: rgba(0, 0, 0, 1)"> cipherText); plainText </span>=<span style="color: rgba(0, 0, 0, 1)"> SM4Utils.decryptData_ECB(cipherText); System.out.println(</span>"ECB Mode decryption plaintext: " +<span style="color: rgba(0, 0, 0, 1)"> plainText); cipherText </span>=<span style="color: rgba(0, 0, 0, 1)"> SM4Utils.encryptData_CBC(plainText); System.out.println(</span>"CBC Pattern encryption ciphertext: " +<span style="color: rgba(0, 0, 0, 1)"> cipherText); plainText </span>=<span style="color: rgba(0, 0, 0, 1)"> SM4Utils.decryptData_CBC(cipherText); System.out.println(</span>"CBC Mode decryption plaintext: " +<span style="color: rgba(0, 0, 0, 1)"> plainText); }
}
III. test
1. CBC mode (double salt, safer) front end: var sm4=new SM4Util(); sm4.encryptData_CBC('');
Back end:
SM4Utils.decryptData_CBC("");
2. ECB mode
front end:
var sm4=new SM4Util();
sm4.encryptData_ECB('');
Back end:
SM4Utils.decryptData_ECB("");