基本介紹
- 中文名:SM 4.0
- 發布者:國家密碼管理局
- 發布時間:2012年3月21日
- 相關標準:GM/T0002-2012
- 學科:密碼學
- 原名:SMS4
介紹,相關概念,原始碼,C/C++,Python,Java,
介紹
SM4.0(原名SMS4.0)是中華人民共和國政府採用的一種分組密碼標準,由國家密碼管理局於2012年3月21日發布。相關標準為“GM/T 0002-2012《SM4分組密碼算法》(原SMS4分組密碼算法)”。
SM4.0中的指令長度被提升到大於64K(即64×1024)的水平,這是SM 3.0規格(渲染指令長度允許大於512)的128倍。
相關概念
在密碼學中,分組加密(英語:Block cipher),又稱分塊加密或塊密碼,是一種對稱密鑰算法。它將明文分成多個等長的模組(block),使用確定的算法和對稱密鑰對每組分別加密解密。分組加密是極其重要的加密協定組成,其中典型的如DES和AES作為美國政府核定的標準加密算法,套用領域從電子郵件加密到銀行交易轉帳,非常廣泛。
國密即國家密碼局認定的國產密碼算法。主要有SM1,SM2,SM3,SM4。密鑰長度和分組長度均為128位。
SM1為對稱加密。其加密強度與AES相當。該算法不公開,調用該算法時,需要通過加密晶片的接口進行調用。
SM2為非對稱加密,基於ECC。該算法已公開。由於該算法基於ECC,故其簽名速度與秘鑰生成速度都快於RSA。ECC 256位(SM2採用的就是ECC 256位的一種)安全強度比RSA 2048位高,但運算速度快於RSA。
SM3訊息摘要。可以用MD5作為對比理解。該算法已公開。校驗結果為256位。
SM4無線區域網路標準的分組數據算法。對稱加密,密鑰長度和分組長度均為128位。
原始碼
C/C++
#define HEADER_SM4_H#define HEADER_SM4_H#ifdef __cplusplusextern "C" {#endiftypedef unsigned char muint8;typedef unsigned long muint32;#define LITTLE_ENDIAN //定義小端位元組序//#define BIG_ENDIAN //定義大端位元組序#define SM4_ENCRYPT 1 //定義加密標誌#define SM4_DECRYPT 0 //定義解密標誌#define SM4_BLOCK_LEN 16#define SM4_KEY_LEN 16#define SM4_IV_LEN SM4_BLOCK_LEN// SM4的密鑰擴展算法// 參數說明:Key為加密密鑰,rk為子密鑰,CryptFlag為加解密標誌int SM4KeyExt(const muint8 *Key, muint32 *rk, muint32 CryptFlag);// SM4的加解密函式// 參數說明:Input為輸入信息分組,Output為輸出分組,rk為輪密鑰int SM4Crypt(const muint8 *Input, muint8 *Output, const muint32 *rk);//For EVPvoid sm4_set_key(muint32 *rk, const unsigned char *data, int enc);void sm4_ecb_encrypt(char *in, char *out, const muint32 *rk,int enc);void sm4_cbc_encrypt(const unsigned char *in, unsigned char *out, long length,const muint32 *rk, unsigned char *iv, int enc);void sm4_cfb64_encrypt(const unsigned char *in, unsigned char *out,long length, const muint32 *rk, unsigned char *ivec,int *num, int enc);void sm4_ofb64_encrypt(const unsigned char *in, unsigned char *out,long length, const muint32 *rk, unsigned char *ivec,int *num);#ifdef __cplusplus}#endif#endif#include "sm4.h"#include//muint32 rk[32];//作為加解密上下文const muint8 Sbox[256] = {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};const muint32 CK[32] = {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 };#define Rotl(_x, _y) (((_x) << (_y)) | ((_x) >> (32 - (_y))))#define ByteSub(_A) (Sbox[(_A) >> 24 & 0xFF] << 24 ^ \Sbox[(_A) >> 16 & 0xFF] << 16 ^ \Sbox[(_A) >> 8 & 0xFF] << 8 ^ \Sbox[(_A) & 0xFF])#define L1(_B) ((_B) ^ Rotl(_B, 2) ^ Rotl(_B, 10) ^ Rotl(_B, 18) ^ Rotl(_B, 24))#define L2(_B) ((_B) ^ Rotl(_B, 13) ^ Rotl(_B, 23))// SM4的加解密函式// 參數說明:Input為輸入信息分組,Output為輸出分組,rk為輪密鑰int SM4Crypt(const muint8 *Input, muint8 *Output, const muint32 *rk){muint32 r, mid, x0, x1, x2, x3, *p;p = (muint32 *)Input;x0 = p[0];x1 = p[1];x2 = p[2];x3 = p[3];#ifdef LITTLE_ENDIANx0 = Rotl(x0, 16); x0 = ((x0 & 0x00FF00FF) << 8) ^ ((x0 & 0xFF00FF00) >> 8);x1 = Rotl(x1, 16); x1 = ((x1 & 0x00FF00FF) << 8) ^ ((x1 & 0xFF00FF00) >> 8);x2 = Rotl(x2, 16); x2 = ((x2 & 0x00FF00FF) << 8) ^ ((x2 & 0xFF00FF00) >> 8);x3 = Rotl(x3, 16); x3 = ((x3 & 0x00FF00FF) << 8) ^ ((x3 & 0xFF00FF00) >> 8);#endiffor (r = 0; r < 32; r += 4){mid = x1 ^ x2 ^ x3 ^ rk[r + 0];mid = ByteSub(mid);x0 ^= L1(mid);mid = x2 ^ x3 ^ x0 ^ rk[r + 1];mid = ByteSub(mid);x1 ^= L1(mid);mid = x3 ^ x0 ^ x1 ^ rk[r + 2];mid = ByteSub(mid);x2 ^= L1(mid);mid = x0 ^ x1 ^ x2 ^ rk[r + 3];mid = ByteSub(mid);x3 ^= L1(mid);}#ifdef LITTLE_ENDIANx0 = Rotl(x0, 16); x0 = ((x0 & 0x00FF00FF) << 8) ^ ((x0 & 0xFF00FF00) >> 8);x1 = Rotl(x1, 16); x1 = ((x1 & 0x00FF00FF) << 8) ^ ((x1 & 0xFF00FF00) >> 8);x2 = Rotl(x2, 16); x2 = ((x2 & 0x00FF00FF) << 8) ^ ((x2 & 0xFF00FF00) >> 8);x3 = Rotl(x3, 16); x3 = ((x3 & 0x00FF00FF) << 8) ^ ((x3 & 0xFF00FF00) >> 8);#endifp = (muint32 *)Output;p[0] = x3;p[1] = x2;p[2] = x1;p[3] = x0;return 1;}
Python
SM4的Python實現
#!/usr/bin/env python# -*- coding: utf-8 -*-# @Author : 河北雪域網路科技有限公司 A.Star# @contact: [email protected]# @site: www.snowland.ltd# @file: SM4.py# @time: 2018/9/21 15:25# @Software: PyCharmimport copyimport timefrom functools import reduce# Expanded SM4 S-boxes Sbox table: 8bits input convert to 8 bits outputSboxTable = [ 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,]# System parameterFK = [0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc]# fixed parameterCK = [ 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]ENCRYPT = 0DECRYPT = 1def GET_UINT32_BE(key_data): return int((key_data[0] << 24) | (key_data[1] << 16) | (key_data[2] << 8) | (key_data[3]))def PUT_UINT32_BE(n): return [int((n >> 24) & 0xff), int((n >> 16) & 0xff), int((n >> 8) & 0xff), int((n) & 0xff)]# rotate shift left marco definitiondef SHL(x, n): return int(int(x << n) & 0xffffffff)def ROTL(x, n): return SHL(x, n) | int((x >> (32 - n)) & 0xffffffff)def XOR(a, b): return list(map(lambda x, y: x ^ y, a, b))# look up in SboxTable and get the related value.# args: [in] inch: 0x00~0xFF (8 bits unsigned value).def sm4Sbox(idx): return SboxTable[idx]# Calculating round encryption key.# args: [in] a: a is a 32 bits unsigned value;# return: sk[i]: i{0,1,2,3,...31}.def sm4CalciRK(ka): a = PUT_UINT32_BE(ka) b = [sm4Sbox(i) for i in a] bb = GET_UINT32_BE(b) rk = bb ^ (ROTL(bb, 13)) ^ (ROTL(bb, 23)) return rk# private F(Lt) function:# "T algorithm" == "L algorithm" + "t algorithm".# args: [in] a: a is a 32 bits unsigned value;# return: c: c is calculated with line algorithm "L" and nonline algorithm "t"def sm4Lt(ka): a = PUT_UINT32_BE(ka) b = [sm4Sbox(i) for i in a] bb = GET_UINT32_BE(b) return bb ^ (ROTL(bb, 2)) ^ (ROTL(bb, 10)) ^ (ROTL(bb, 18)) ^ (ROTL(bb, 24))# private F function:# Calculating and getting encryption/decryption contents.# args: [in] x0: original contents;# args: [in] x1: original contents;# args: [in] x2: original contents;# args: [in] x3: original contents;# args: [in] rk: encryption/decryption key;# return the contents of encryption/decryption contents.def sm4F(x0, x1, x2, x3, rk): return (x0 ^ sm4Lt(x1 ^ x2 ^ x3 ^ rk))class Sm4(object): def __init__(self): self.sk = [0] * 32 self.mode = ENCRYPT def sm4_set_key(self, key_data, mode): self.sm4_setkey(key_data, mode) def sm4_setkey(self, key, mode): MK = [0, 0, 0, 0] k = [0] * 36 MK[0] = GET_UINT32_BE(key[0:4]) MK[1] = GET_UINT32_BE(key[4:8]) MK[2] = GET_UINT32_BE(key[8:12]) MK[3] = GET_UINT32_BE(key[12:16]) k[0:4] = XOR(MK, FK) for i in range(32): k[i + 4] = k[i] ^ (sm4CalciRK(k[i + 1] ^ k[i + 2] ^ k[i + 3] ^ CK[i])) self.sk = k[4:] self.mode = mode if mode == DECRYPT: self.sk.reverse() def sm4_one_round(self, sk, in_put): item = [GET_UINT32_BE(in_put[0:4]), GET_UINT32_BE(in_put[4:8]), GET_UINT32_BE(in_put[8:12]), GET_UINT32_BE(in_put[12:16])] res = reduce(lambda x, y: [x[1], x[2], x[3], sm4F(x[0], x[1], x[2], x[3], y)], sk, item) res.reverse() rev = map(PUT_UINT32_BE, res) out_put = [] [out_put.extend(_) for _ in rev] return out_put def sm4_crypt_ecb(self, input_data): # SM4-ECB block encryption/decryption output_data = [] tmp = [input_data[i:i + 16] for i in range(0, len(input_data), 16)] [output_data.extend(each) for each in map(lambda x: self.sm4_one_round(self.sk, x), tmp)] return output_data def sm4_crypt_cbc(self, iv, input_data): # SM4-CBC buffer encryption/decryption length = len(input_data) i = 0 output_data = [] tmp_input = [0] * 16 if self.mode == ENCRYPT: while length > 0: tmp_input[0:16] = XOR(input_data[i:i + 16], iv[0:16]) output_data += self.sm4_one_round(self.sk, tmp_input[0:16]) iv = copy.deepcopy(output_data[i:i + 16]) i += 16 length -= 16 else: while length > 0: output_data += self.sm4_one_round(self.sk, input_data[i:i + 16]) output_data[i:i + 16] = XOR(output_data[i:i + 16], iv[0:16]) iv = copy.deepcopy(input_data[i:i + 16]) i += 16 length -= 16 return output_datadef sm4_crypt_ecb(mode, key, data): sm4_d = Sm4() sm4_d.sm4_set_key(key, mode) en_data = sm4_d.sm4_crypt_ecb(data) return en_datadef sm4_crypt_cbc(mode, key, iv, data): sm4_d = Sm4() sm4_d.sm4_set_key(key, mode) en_data = sm4_d.sm4_crypt_cbc(iv, data) return en_dataif __name__ == "__main__": # log_init() key_data = [0x5a] * 16 input_data = [0x6b] * 128 iv_data = [0] * 16 sm4_d = Sm4() sm4_d.sm4_set_key(key_data, ENCRYPT) en_data = sm4_d.sm4_crypt_ecb(input_data) print(en_data, "en_data:") sm4_d.sm4_set_key(key_data, DECRYPT) de_data = sm4_d.sm4_crypt_ecb(en_data) print(de_data, "de_data:") if de_data == input_data: print("ecb check pass") else: print("ecb check fail") raise BaseException("error") sm4_d.sm4_set_key(key_data, ENCRYPT) en_data = sm4_d.sm4_crypt_cbc(iv_data, input_data) print(en_data, "en_data:") sm4_d.sm4_set_key(key_data, DECRYPT) de_data = sm4_d.sm4_crypt_cbc(iv_data, en_data) print(de_data, "de_data:") if de_data == input_data: print("cbc check pass") else: print("cbc check fail") raise BaseException("error") # file test file_path = r"test2.txt" ecb_path_en = r"test2k_ecb_en.txt" ecb_path_de = r"test2k_ecb_de.txt" cbc_path_en = r"test2k_cbc_en.txt" cbc_path_de = r"test2k_cbc_de.txt" key_data = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08] iv_data = [0x5a] * 16 with open(file_path, 'rb') as f: file_data = f.read() # file_data_list = [ord(x) for x in file_data] file_data_list = list(file_data) # 1. ECB sm4_d = Sm4() sm4_d.sm4_set_key(key_data, ENCRYPT) en_data = sm4_d.sm4_crypt_ecb(file_data_list) with open(ecb_path_en, 'w+b') as f: f.write(bytes(en_data)) sm4_d.sm4_set_key(key_data, DECRYPT) de_data = sm4_d.sm4_crypt_ecb(en_data) with open(ecb_path_de, 'w+b') as f: f.write(bytes(de_data)) if de_data == file_data_list: print("file decode pass") else: print("file decode fail") raise BaseException('error') # 2. CBC sm4_d.sm4_set_key(key_data, ENCRYPT) en_data = sm4_d.sm4_crypt_cbc(iv_data, file_data_list) with open(cbc_path_en, 'w+b') as f: f.write(bytes(en_data)) sm4_d.sm4_set_key(key_data, DECRYPT) de_data = sm4_d.sm4_crypt_cbc(iv_data, en_data) with open(cbc_path_de, 'w+b') as f: f.write(bytes(de_data)) if de_data == file_data_list: print("file decode pass") else: print("file decode fail") raise BaseException("error") # log_end()
Java
SM4的Java實現
package ltd.snowland.security.utils;import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;public class SM4Base { public static final int SM4_ENCRYPT = 1; public static final int SM4_DECRYPT = 0; private long GET_ULONG_BE(byte[] b, int i) { long n = (long) (b[i] & 0xff) << 24 | (long) ((b[i + 1] & 0xff) << 16) | (long) ((b[i + 2] & 0xff) << 8) | (long) (b[i + 3] & 0xff) & 0xffffffffL; return n; } private void PUT_ULONG_BE(long n, byte[] b, int i) { b[i] = (byte) (int) (0xFF & n >> 24); b[i + 1] = (byte) (int) (0xFF & n >> 16); b[i + 2] = (byte) (int) (0xFF & n >> 8); b[i + 3] = (byte) (int) (0xFF & n); } private long SHL(long x, int n) { return (x & 0xFFFFFFFF) << n; } private long ROTL(long x, int n) { return SHL(x, n) | x >> (32 - n); } private void SWAP(long[] sk, int i) { long t = sk[i]; sk[i] = sk[(31 - i)]; sk[(31 - i)] = t; } public static final byte[] SboxTable = { (byte) 0xd6, (byte) 0x90, (byte) 0xe9, (byte) 0xfe, (byte) 0xcc, (byte) 0xe1, 0x3d, (byte) 0xb7, 0x16, (byte) 0xb6, 0x14, (byte) 0xc2, 0x28, (byte) 0xfb, 0x2c, 0x05, 0x2b, 0x67, (byte) 0x9a, 0x76, 0x2a, (byte) 0xbe, 0x04, (byte) 0xc3, (byte) 0xaa, 0x44, 0x13, 0x26, 0x49, (byte) 0x86, 0x06, (byte) 0x99, (byte) 0x9c, 0x42, 0x50, (byte) 0xf4, (byte) 0x91, (byte) 0xef, (byte) 0x98, 0x7a, 0x33, 0x54, 0x0b, 0x43, (byte) 0xed, (byte) 0xcf, (byte) 0xac, 0x62, (byte) 0xe4, (byte) 0xb3, 0x1c, (byte) 0xa9, (byte) 0xc9, 0x08, (byte) 0xe8, (byte) 0x95, (byte) 0x80, (byte) 0xdf, (byte) 0x94, (byte) 0xfa, 0x75, (byte) 0x8f, 0x3f, (byte) 0xa6, 0x47, 0x07, (byte) 0xa7, (byte) 0xfc, (byte) 0xf3, 0x73, 0x17, (byte) 0xba, (byte) 0x83, 0x59, 0x3c, 0x19, (byte) 0xe6, (byte) 0x85, 0x4f, (byte) 0xa8, 0x68, 0x6b, (byte) 0x81, (byte) 0xb2, 0x71, 0x64, (byte) 0xda, (byte) 0x8b, (byte) 0xf8, (byte) 0xeb, 0x0f, 0x4b, 0x70, 0x56, (byte) 0x9d, 0x35, 0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, (byte) 0xd1, (byte) 0xa2, 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, (byte) 0x87, (byte) 0xd4, 0x00, 0x46, 0x57, (byte) 0x9f, (byte) 0xd3, 0x27, 0x52, 0x4c, 0x36, 0x02, (byte) 0xe7, (byte) 0xa0, (byte) 0xc4, (byte) 0xc8, (byte) 0x9e, (byte) 0xea, (byte) 0xbf, (byte) 0x8a, (byte) 0xd2, 0x40, (byte) 0xc7, 0x38, (byte) 0xb5, (byte) 0xa3, (byte) 0xf7, (byte) 0xf2, (byte) 0xce, (byte) 0xf9, 0x61, 0x15, (byte) 0xa1, (byte) 0xe0, (byte) 0xae, 0x5d, (byte) 0xa4, (byte) 0x9b, 0x34, 0x1a, 0x55, (byte) 0xad, (byte) 0x93, 0x32, 0x30, (byte) 0xf5, (byte) 0x8c, (byte) 0xb1, (byte) 0xe3, 0x1d, (byte) 0xf6, (byte) 0xe2, 0x2e, (byte) 0x82, 0x66, (byte) 0xca, 0x60, (byte) 0xc0, 0x29, 0x23, (byte) 0xab, 0x0d, 0x53, 0x4e, 0x6f, (byte) 0xd5, (byte) 0xdb, 0x37, 0x45, (byte) 0xde, (byte) 0xfd, (byte) 0x8e, 0x2f, 0x03, (byte) 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51, (byte) 0x8d, 0x1b, (byte) 0xaf, (byte) 0x92, (byte) 0xbb, (byte) 0xdd, (byte) 0xbc, 0x7f, 0x11, (byte) 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, (byte) 0xd8, 0x0a, (byte) 0xc1, 0x31, (byte) 0x88, (byte) 0xa5, (byte) 0xcd, 0x7b, (byte) 0xbd, 0x2d, 0x74, (byte) 0xd0, 0x12, (byte) 0xb8, (byte) 0xe5, (byte) 0xb4, (byte) 0xb0, (byte) 0x89, 0x69, (byte) 0x97, 0x4a, 0x0c, (byte) 0x96, 0x77, 0x7e, 0x65, (byte) 0xb9, (byte) 0xf1, 0x09, (byte) 0xc5, 0x6e, (byte) 0xc6, (byte) 0x84, 0x18, (byte) 0xf0, 0x7d, (byte) 0xec, 0x3a, (byte) 0xdc, 0x4d, 0x20, 0x79, (byte) 0xee, 0x5f, 0x3e, (byte) 0xd7, (byte) 0xcb, 0x39, 0x48 }; public static final int[] FK = { 0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc }; public static final int[] 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 }; private byte sm4Sbox(byte inch) { int i = inch & 0xFF; byte retVal = SboxTable[i]; return retVal; } private long sm4Lt(long ka) { long bb = 0L; long c = 0L; byte[] a = new byte[4]; byte[] b = new byte[4]; PUT_ULONG_BE(ka, a, 0); b[0] = sm4Sbox(a[0]); b[1] = sm4Sbox(a[1]); b[2] = sm4Sbox(a[2]); b[3] = sm4Sbox(a[3]); bb = GET_ULONG_BE(b, 0); c = bb ^ ROTL(bb, 2) ^ ROTL(bb, 10) ^ ROTL(bb, 18) ^ ROTL(bb, 24); return c; } private long sm4F(long x0, long x1, long x2, long x3, long rk) { return x0 ^ sm4Lt(x1 ^ x2 ^ x3 ^ rk); } private long sm4CalciRK(long ka) { long bb = 0L; long rk = 0L; byte[] a = new byte[4]; byte[] b = new byte[4]; PUT_ULONG_BE(ka, a, 0); b[0] = sm4Sbox(a[0]); b[1] = sm4Sbox(a[1]); b[2] = sm4Sbox(a[2]); b[3] = sm4Sbox(a[3]); bb = GET_ULONG_BE(b, 0); rk = bb ^ ROTL(bb, 13) ^ ROTL(bb, 23); return rk; } private void sm4_setkey(long[] SK, byte[] key) { long[] MK = new long[4]; long[] k = new long[36]; int i = 0; MK[0] = GET_ULONG_BE(key, 0); MK[1] = GET_ULONG_BE(key, 4); MK[2] = GET_ULONG_BE(key, 8); MK[3] = GET_ULONG_BE(key, 12); k[0] = MK[0] ^ (long) FK[0]; k[1] = MK[1] ^ (long) FK[1]; k[2] = MK[2] ^ (long) FK[2]; k[3] = MK[3] ^ (long) FK[3]; for (; i < 32; i++) { k[(i + 4)] = (k[i] ^ sm4CalciRK(k[(i + 1)] ^ k[(i + 2)] ^ k[(i + 3)] ^ (long) CK[i])); SK[i] = k[(i + 4)]; } } private void sm4_one_round(long[] sk, byte[] input, byte[] output) { int i = 0; long[] ulbuf = new long[36]; ulbuf[0] = GET_ULONG_BE(input, 0); ulbuf[1] = GET_ULONG_BE(input, 4); ulbuf[2] = GET_ULONG_BE(input, 8); ulbuf[3] = GET_ULONG_BE(input, 12); while (i < 32) { ulbuf[(i + 4)] = sm4F(ulbuf[i], ulbuf[(i + 1)], ulbuf[(i + 2)], ulbuf[(i + 3)], 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); } private byte[] padding(byte[] input, int mode) { if (input == null) { return null; } byte[] ret = (byte[]) null; if (mode == SM4_ENCRYPT) { int p = 16 - input.length % 16; ret = new byte[input.length + p]; System.arraycopy(input, 0, ret, 0, input.length); for (int i = 0; i < p; i++) { ret[input.length + i] = (byte) p; } } else { int p = input[input.length - 1]; ret = new byte[input.length - p]; System.arraycopy(input, 0, ret, 0, input.length - p); } return ret; } public void sm4_setkey_enc(SM4_Context ctx, byte[] key) throws Exception { if (ctx == null) { throw new Exception("ctx is null!"); } if (key == null || key.length != 16) { throw new Exception("key error!"); } ctx.mode = SM4_ENCRYPT; sm4_setkey(ctx.sk, key); } public void sm4_setkey_dec(SM4_Context ctx, byte[] key) throws Exception { if (ctx == null) { throw new Exception("ctx is null!"); } if (key == null || key.length != 16) { throw new Exception("key error!"); } int i = 0; ctx.mode = SM4_DECRYPT; sm4_setkey(ctx.sk, key); for (i = 0; i < 16; i++) { SWAP(ctx.sk, i); } } public byte[] sm4_crypt_ecb(SM4_Context ctx, byte[] input) throws Exception { if (input == null) { throw new Exception("input is null!"); } if ((ctx.isPadding) && (ctx.mode == SM4_ENCRYPT)) { input = padding(input, SM4_ENCRYPT); } int length = input.length; ByteArrayInputStream bins = new ByteArrayInputStream(input); ByteArrayOutputStream bous = new ByteArrayOutputStream(); for (; length > 0; length -= 16) { byte[] in = new byte[16]; byte[] out = new byte[16]; bins.read(in); sm4_one_round(ctx.sk, in, out); bous.write(out); } byte[] output = bous.toByteArray(); if (ctx.isPadding && ctx.mode == SM4_DECRYPT) { output = padding(output, SM4_DECRYPT); } bins.close(); bous.close(); return output; } public byte[] sm4_crypt_cbc(SM4_Context ctx, byte[] iv, byte[] input) throws Exception { if (iv == null || iv.length != 16) { throw new Exception("iv error!"); } if (input == null) { throw new Exception("input is null!"); } if (ctx.isPadding && ctx.mode == SM4_ENCRYPT) { input = padding(input, SM4_ENCRYPT); } int i = 0; int length = input.length; ByteArrayInputStream bins = new ByteArrayInputStream(input); ByteArrayOutputStream bous = new ByteArrayOutputStream(); if (ctx.mode == SM4_ENCRYPT) { for (; length > 0; length -= 16) { byte[] in = new byte[16]; byte[] out = new byte[16]; byte[] out1 = new byte[16]; bins.read(in); for (i = 0; i < 16; i++) {out[i] = ((byte) (in[i] ^ iv[i])); } sm4_one_round(ctx.sk, out, out1); System.arraycopy(out1, 0, iv, 0, 16); bous.write(out1); } } else { byte[] temp = new byte[16]; for (; length > 0; length -= 16) { byte[] in = new byte[16]; byte[] out = new byte[16]; byte[] out1 = new byte[16]; bins.read(in); System.arraycopy(in, 0, temp, 0, 16); sm4_one_round(ctx.sk, in, out); for (i = 0; i < 16; i++) {out1[i] = ((byte) (out[i] ^ iv[i])); } System.arraycopy(temp, 0, iv, 0, 16); bous.write(out1); } } byte[] output = bous.toByteArray(); if (ctx.isPadding && ctx.mode == SM4_DECRYPT) { output = padding(output, SM4_DECRYPT); } bins.close(); bous.close(); return output; }}
package ltd.snowland.security.utils;public class SM4_Context{ public int mode; public long[] sk; public boolean isPadding; public SM4_Context() { this.mode = 1; this.isPadding = true; this.sk = new long[32]; }}