SM4前端加密

1.新建一个.js文件夹,sm4用的是ECB模式,没有偏移值iv

import {SM4} from '@/utils/sm4/sm4'  
import {Hex} from '@/utils/sm4/hex'

//加密
export function encrypt(option) {
  let paramJson = '';
  let params=''
  if(option=='undefined'){
    return;
  }else if (typeof (option) == 'object') {
    paramJson = JSON.stringify(option);
  } else if (typeof (option) == 'string') {
    // &字符串
    paramJson = JSON.parse(option);
  }
  let paramBytes = Hex.utf8StrToBytes(paramJson);
  if (paramBytes.length > 0) {
//后端提供的密匙
    let key = Hex.decode('765A0CD3E7C9A0E0E9DCF2C14FF93824');
    let sm4 = new SM4();
    let paramsCipher = sm4.encrypt_ecb(key, paramBytes);
    params = Hex.encode(paramsCipher, 0, paramsCipher.length);
  }
  return params;
}
//解密
export function decrypt(option) {
  if(option!==null){
    var paramJson = Hex.decode(option);
    let data=''
    let key = Hex.decode('765A0CD3E7C9A0E0E9DCF2C14FF93824');
    let sm4 = new SM4();
    let paramsCipher = sm4.decrypt_ecb(key, paramJson);
    data = Hex.bytesToUtf8Str(paramsCipher)
    return JSON.parse(data);
  }else{
    return false
  }
}

2.引入的两个方法是写好的,不是下载依赖,代码放下面了  可以直接复制,有些引入路径可能要修改

 

SM4.JS

/*
 * sm4.js
 * 
 * Copyright (c) 
 */
/**
 * @name sm4.js
 * @author 
 * @version 
 */
import {byteArrayToIntArray,intToByte,intArrayToByteArray,arrayCopy,longToByte,byteToInt} from '@/utils/sm4/byteUtil'
export function SM4(){
  this.sbox = new Array(
   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
  );
  
  this.fk = new Array(0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc);
  this.ck = new Array(
   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
  );
}

SM4.prototype = {
  expandKey:function(key){
   var k = new Array(36);
   var mk = byteArrayToIntArray(key);
   k[0] = mk[0] ^ this.fk[0];
   k[1] = mk[1] ^ this.fk[1];
   k[2] = mk[2] ^ this.fk[2];
   k[3] = mk[3] ^ this.fk[3];
   var rk = new Array(32);
   for (var i = 0; i < 32; i++)
   {
    k[(i + 4)] = (k[i] ^ this.T1(k[(i + 1)] ^ k[(i + 2)] ^ k[(i + 3)] ^ this.ck[i]));
    rk[i] = k[(i + 4)];
   }
   return rk;
  },
  T1:function(ta){
   var rk = 0;
   var b = new Array(4);
   var a = intToByte(ta);
   b[0] = this.sbox[a[0] & 0xFF];
   b[1] = this.sbox[a[1] & 0xFF];
   b[2] = this.sbox[a[2] & 0xFF];
   b[3] = this.sbox[a[3] & 0xFF];
   var bint = byteToInt(b,0);
   var rk = bint ^ (bint<<13|(bint>>>(32-13))) ^ (bint<<23|(bint>>>(32-23)));
   return rk;
  },
  one_encrypt:function(rk, data){
   var x = new Array(36);
   x[0] = byteToInt(data, 0);
   x[1] = byteToInt(data, 4);
   x[2] = byteToInt(data, 8);
   x[3] = byteToInt(data, 12);
   for(var i = 0;i < 32;i++)
   {
    x[(i + 4)] = x[i] ^ this.T0(x[(i + 1)]^x[(i + 2)]^x[(i + 3)]^rk[i]);
   }
   var tmpx = new Array(4); 
   for(var i = 35;i >= 32;i--){
    tmpx[35-i] = x[i];
   }
   var xbyte = intArrayToByteArray(tmpx);
   
   return xbyte;
  },
  T0:function(ta){
   var a = intToByte(ta);
   var b = new Array(4);
   b[0] = this.sbox[a[0] & 0xFF];
   b[1] = this.sbox[a[1] & 0xFF];
   b[2] = this.sbox[a[2] & 0xFF];
   b[3] = this.sbox[a[3] & 0xFF];
   var bint = byteToInt(b,0);
   var c = bint ^ (bint<<2|(bint>>>(32-2))) ^ (bint<<10|(bint>>>(32-10))) ^ (bint<<18|(bint>>>(32-18))) ^ (bint<<24|(bint>>>(32-24)));
   return c;
  },
  pkcs7padding:function(input,mode){
   if (input == null)
   {
    return null;
   }

   var ret = null;
   if (mode == 1)//填充
   {
    var p = 16 - input.length % 16;
    ret = new Array(input.length + p);
    arrayCopy(input, 0, ret, 0, input.length);
    for (var i = 0; i < p; i++)
    {
     ret[input.length + i] = p;
    }
   }
   else//去除填充
   {
    var p = input[input.length - 1];
    ret = new Array(input.length - p);
    arrayCopy(input, 0, ret, 0, input.length - p);
   }
   return ret;
  },
  /*ECB加密*/
  encrypt_ecb:function(key,data){
    if(key == undefined || key == null || key.length%16 != 0){
    console.log("sm4 key is error!");
    return null;
   }
   if(data == undefined || data == null || data.length <= 0){
    console.log("data is error!");
    return null;
   }
   var rk = this.expandKey(key);
   /*if(debug){
    var rkb = intArrayToByteArray(rk);
    console.log(Hex.encode(rkb,0,rkb.length));
   }*/
   
   var blockLen = 16;
   var loop = parseInt(data.length/blockLen);//注意不能整除会有小数,要取整
   var cipher = new Array((loop+1)*blockLen);
   var tmp = new Array(blockLen);
   var oneCipher = null;
   
   for(var i = 0;i<loop;i++){
    arrayCopy(data,i*blockLen,tmp,0,blockLen);
    oneCipher = this.one_encrypt(rk,tmp);
    arrayCopy(oneCipher,0,cipher,i*blockLen,blockLen);
   }
   
   var lessData = new Array(data.length%blockLen);
   if(lessData.length > 0){
    arrayCopy(data,loop*blockLen,lessData,0,data.length%blockLen);
   }
   var padding = this.pkcs7padding(lessData,1);
   oneCipher = this.one_encrypt(rk,padding);
   arrayCopy(oneCipher,0,cipher,loop*blockLen,blockLen);
   
   return cipher;
  },
  /*ECB解密*/
  decrypt_ecb:function(key,data){
   if(key == undefined || key == null || key.length%16 != 0){
    console.log("sm4 key is error!");
    return null;
   }
   if(data == undefined || data == null || data.length%16 != 0){
    console.log("data is error!");
    return null;
   }
   var rk = this.expandKey(key);
   var nrk = new Array(32);
   for(var i = 0;i<rk.length;i++){
    nrk[i] = rk[32-i-1];
   }
   /*if(debug){
    var rkb = intArrayToByteArray(rk);
    console.log(Hex.encode(rkb,0,rkb.length));
   }*/
   var blockLen = 16;
   var loop = data.length/blockLen - 1;
   var tmp = new Array(blockLen);
   var onePlain = null;
   var plain = null;
   //先解密最后一部分,确定数据长度
   arrayCopy(data,loop*blockLen,tmp,0,blockLen);
   onePlain = this.one_encrypt(nrk,tmp);
   var lastPart = this.pkcs7padding(onePlain,0);
   
   plain = new Array(loop*blockLen+lastPart.length);
   arrayCopy(lastPart,0,plain,loop*blockLen,lastPart.length);
   
   //解密剩下部分数据
   for(var i = 0;i<loop;i++){
    arrayCopy(data,i*blockLen,tmp,0,blockLen);
    onePlain = this.one_encrypt(nrk,tmp);
    arrayCopy(onePlain,0,plain,i*blockLen,blockLen);
   }
   
   return plain;
  },
  /*CBC加密*/
  encrypt_cbc:function(key,iv,data){
   if(key == undefined || key == null || key.length%16 != 0){
    console.log("sm4 key is error!");
    return null;
   }
   if(data == undefined || data == null || data.length <= 0){
    console.log("data is error!");
    return null;
   }
   if(iv == undefined || iv == null || iv.length%16 != 0){
    console.log("iv is error!");
    return null;
   }
   var rk = this.expandKey(key);
   /*if(debug){
    var rkb = intArrayToByteArray(rk);
    console.log(Hex.encode(rkb,0,rkb.length));
   }*/
   
   var blockLen = 16;
   var loop = parseInt(data.length/blockLen);//注意不能整除会有小数,要取整
   var cipher = new Array((loop+1)*blockLen);
   var tmp = new Array(blockLen);
   var oneCipher = null;
   
   for(var i = 0;i<loop;i++){
    arrayCopy(data,i*blockLen,tmp,0,blockLen);
    for(var j = 0;j<blockLen;j++){
     tmp[j] = tmp[j] ^ iv[j];
    }
    iv = this.one_encrypt(rk,tmp);
    arrayCopy(iv,0,cipher,i*blockLen,blockLen);
   }
   
   var lessData = new Array(data.length%blockLen);
   if(lessData.length > 0){
    arrayCopy(data,loop*blockLen,lessData,0,data.length%blockLen);
   }
   var padding = this.pkcs7padding(lessData,1);
   for(var i = 0;i<blockLen;i++){
    padding[i] = padding[i] ^ iv[i];
   }
   iv = this.one_encrypt(rk,padding);
   arrayCopy(iv,0,cipher,loop*blockLen,blockLen);
   
   return cipher;
  },
  /*CBC解密*/
  decrypt_cbc:function(key,iv,data){
   if(key == undefined || key == null || key.length%16 != 0){
    console.log("sm4 key is error!");
    return null;
   }
   if(data == undefined || data == null || data.length%16 != 0){
    console.log("data is error!");
    return null;
   }
   if(iv == undefined || iv == null || iv.length%16 != 0){
    console.log("iv is error!");
    return null;
   }
   var rk = this.expandKey(key);
   var nrk = new Array(32);
   for(var i = 0;i<rk.length;i++){
    nrk[i] = rk[32-i-1];
   }
   /*if(debug){
    var rkb = intArrayToByteArray(rk);
    console.log(Hex.encode(rkb,0,rkb.length));
   }*/
   var blockLen = 16;
   var loop = data.length/blockLen;
   var tmp = new Array(blockLen);
   var onePlain = null;
   var plain = null;
   
   
   //解密
   plain = new Array(data.length);
   for(var i = 0;i<loop;i++){
    arrayCopy(data,i*blockLen,tmp,0,blockLen);
    onePlain = this.one_encrypt(nrk,tmp);
    for(var j = 0;j<blockLen;j++){
     onePlain[j] = onePlain[j] ^ iv[j];
    }
    arrayCopy(tmp,0,iv,0,blockLen);
    arrayCopy(onePlain,0,plain,i*blockLen,blockLen);
   }
   
   //去填充,确定数据长度
   //arrayCopy(data,data.length-blockLen,tmp,0,blockLen);
   var lastPart = this.pkcs7padding(onePlain,0);
   
   var realPlain = new Array(plain.length-blockLen+lastPart.length);
   arrayCopy(plain,0,realPlain,0,plain.length-blockLen);
   arrayCopy(lastPart,0,realPlain,plain.length-blockLen,lastPart.length);
   
   
   //先解密最后一部分,确定数据长度
   /*arrayCopy(data,loop*blockLen,tmp,0,blockLen);
   onePlain = this.one_encrypt(nrk,tmp);
   for(var i = 0;i<blockLen;i++){
    onePlain[i] = onePlain[i] ^ iv[i];
   }
   var lastPart = this.pkcs7padding(onePlain,0);
   
   plain = new Array(loop*blockLen+lastPart.length);
   arrayCopy(lastPart,0,plain,loop*blockLen,lastPart.length);
   
   //解密剩下部分数据
   for(var i = 0;i<loop;i++){
    arrayCopy(data,i*blockLen,tmp,0,blockLen);
    onePlain = this.one_encrypt(nrk,tmp);
    arrayCopy(onePlain,0,plain,i*blockLen,blockLen);
   }*/
   
   
   return realPlain;
  }
}

HEX.JS

export function Hex(){
    
}

Hex.encode = function(b,pos,len) {
    var hexCh = new Array(len*2);
    var hexCode = new Array('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F');
    
    for(var i = pos,j = 0;i<len+pos;i++,j++) {
        hexCh[j] = hexCode[(b[i]&0xFF)>>4];
        hexCh[++j] = hexCode[(b[i]&0x0F)];
    }
    
    return hexCh.join('');
}

Hex.decode = function(hex) {
    
    if(hex == null || hex == '') {
        return null;
    }
    if(hex.length%2 != 0) {
        return null;
    }
    
    var ascLen = hex.length/2;
    var hexCh = this.toCharCodeArray(hex);
    var asc = new Array(ascLen);
    
    for(var i = 0;i<ascLen;i++) {
        
        if(hexCh[2*i]>=0x30 && hexCh[2*i]<=0x39) {
            asc[i] = ((hexCh[2*i]-0x30)<<4);
        }else if(hexCh[2*i]>=0x41 && hexCh[2*i]<=0x46) {//A-F : 0x41-0x46
            asc[i] = ((hexCh[2*i]-0x41+10)<<4);
        }else if(hexCh[2*i]>=0x61 && hexCh[2*i]<=0x66) {//a-f  : 0x61-0x66
            asc[i] = ((hexCh[2*i]-0x61+10)<<4);
        }else {
            return null;
        }
        
        if(hexCh[2*i+1]>=0x30 && hexCh[2*i+1]<=0x39) {
            asc[i] = (asc[i] | (hexCh[2*i+1]-0x30));
        }else if(hexCh[2*i+1]>=0x41 && hexCh[2*i+1]<=0x46) {
            asc[i] = (asc[i] | (hexCh[2*i+1]-0x41+10));
        }else if(hexCh[2*i+1]>=0x61 && hexCh[2*i+1]<=0x66) {
            asc[i] = (asc[i] | (hexCh[2*i+1]-0x61+10));
        }else {
            return null;
        }
        
        
    }
    
    return asc;
}

Hex.utf8StrToHex = function(utf8Str){
  var ens = encodeURIComponent(utf8Str);
  var es = unescape(ens);
  
  
  var esLen = es.length;

    // Convert
    var words = [];
    for (var i = 0; i < esLen; i++) {
        words[i] = (es.charCodeAt(i).toString(16));
    }
    return words.join('');
}

Hex.utf8StrToBytes = function(utf8Str){
  var ens = encodeURIComponent(utf8Str);
  var es = unescape(ens);
  
  
  var esLen = es.length;

    // Convert
    var words = [];
    for (var i = 0; i < esLen; i++) {
        words[i] = es.charCodeAt(i);
    }
    return words;
}

Hex.hexToUtf8Str = function(utf8Str){
  
  var utf8Byte = Hex.decode(utf8Str);
    var latin1Chars = [];
    for (var i = 0; i < utf8Byte.length; i++) {
        latin1Chars.push(String.fromCharCode(utf8Byte[i]));
    }
    return decodeURIComponent(escape(latin1Chars.join('')));
}

Hex.bytesToUtf8Str = function(bytesArray){
  
  var utf8Byte = bytesArray;
    var latin1Chars = [];
    for (var i = 0; i < utf8Byte.length; i++) {
        latin1Chars.push(String.fromCharCode(utf8Byte[i]));
    }
    return decodeURIComponent(escape(latin1Chars.join('')));
}

Hex.toCharCodeArray = function(chs){
    var chArr = new Array(chs.length);
    for(var i = 0;i<chs.length;i++){
        chArr[i] = chs.charCodeAt(i);
    }
    return chArr;
}

 

byteUtil.JS

/*
 * 
 * 字节流转换工具js
 * 
 */

/*
 * 数组复制
 */
export function arrayCopy(src,pos1,dest,pos2,len){
  var realLen = len;
  if(pos1+len>src.length&&pos2+len<=dest.length){
   realLen = src.length-pos1;
  }else if(pos2+len>dest.length&&pos1+len<=src.length){
   realLen = dest.length-pos2;
  }else if(pos1+len<=src.length&&pos2+len<=dest.length){
   realLen = len;
  }else if(dest.length<src.length){
   realLen = dest.length-pos2;
  }else{
   realLen = src.length-pos2;
  }
  
  for(var i=0;i<realLen;i++){
   dest[i+pos2] = src[i+pos1];
  }
}

/*
 * 长整型转成字节,一个长整型为8字节
 * 返回:字节数组
 */
export function longToByte(num){
  //TODO 这里目前只转换了低四字节,因为js没有长整型,得要封装
  return new Array(
     0,
     0,
     0,
     0,
           (num >> 24)&0x000000FF,
           (num >> 16)&0x000000FF,
           (num >> 8)&0x000000FF,
           (num)&0x000000FF
        );
}

/*
 * int数转成byte数组
 * 事实上只不过转成byte大小的数,实际占用空间还是4字节
 * 返回:字节数组
 */
export function intToByte(num) {
    return new Array(
       (num >> 24)&0x000000FF,
       (num >> 16)&0x000000FF,
       (num >> 8)&0x000000FF,
       (num)&0x000000FF
    );
}

/*
 * int数组转成byte数组,一个int数值转成四个byte
 * 返回:byte数组
 */
export function intArrayToByteArray(nums) {
  var b = new Array(nums.length*4);
  
  for(var i = 0;i<nums.length;i++) {
   arrayCopy(intToByte(nums[i]), 0, b, i*4, 4);
  }
  
  return b;
}

/*
 * byte数组转成int数值
 * 返回:int数值
 */
export function byteToInt(b,pos) {
  if(pos+3<b.length) {
   return ((b[pos])<<24) | ((b[pos+1])<<16) | ((b[pos+2])<<8) | ((b[pos+3]));   
  }else if(pos+2<b.length) {
   return ((b[pos+1])<<16) | ((b[pos+2])<<8 )  | ((b[pos+3]));
  }else if(pos+1<b.length) {
   return ((b[pos])<<8) | ((b[pos+1]));
  }else {
   return ((b[pos]));
  }
}

/*
 * byte数组转成int数组,每四个字节转成一个int数值
 * 
 */
export function byteArrayToIntArray(b) {
  // var arrLen = b.length%4==0 ? b.length/4:b.length/4+1;
  var arrLen = Math.ceil(b.length/4);//向上取整
  var out = new Array(arrLen);
  for(var i = 0;i<b.length;i++){
   b[i] = b[i]&0xFF;//避免负数造成影响
  }
  for(var i = 0;i<out.length;i++) {
   out[i] = byteToInt(b,i*4);
  }
  return out;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值