001package top.cenze.utils.crypt.sm.sm4; 002 003/** 004 * Created by $(USER) on $(DATE) 005 */ 006 007import top.cenze.utils.ConvertUtil; 008 009import java.io.ByteArrayInputStream; 010import java.io.ByteArrayOutputStream; 011 012public class SM4 { 013 public static final int SM4_ENCRYPT = 1; 014 015 public static final int SM4_DECRYPT = 0; 016 017 private long GET_ULONG_BE(byte[] b, int i) { 018 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; 019 return n; 020 } 021 022 private void PUT_ULONG_BE(long n, byte[] b, int i) { 023 b[i] = (byte) (int) (0xFF & n >> 24); 024 b[i + 1] = (byte) (int) (0xFF & n >> 16); 025 b[i + 2] = (byte) (int) (0xFF & n >> 8); 026 b[i + 3] = (byte) (int) (0xFF & n); 027 } 028 029 private long SHL(long x, int n) { 030 return (x & 0xFFFFFFFF) << n; 031 } 032 033 private long ROTL(long x, int n) { 034 return SHL(x, n) | x >> (32 - n); 035 } 036 037 private void SWAP(long[] sk, int i) { 038 long t = sk[i]; 039 sk[i] = sk[(31 - i)]; 040 sk[(31 - i)] = t; 041 } 042 043 public static final byte[] SboxTable = {(byte) 0xd6, (byte) 0x90, (byte) 0xe9, (byte) 0xfe, 044 (byte) 0xcc, (byte) 0xe1, 0x3d, (byte) 0xb7, 0x16, (byte) 0xb6, 045 0x14, (byte) 0xc2, 0x28, (byte) 0xfb, 0x2c, 0x05, 0x2b, 0x67, 046 (byte) 0x9a, 0x76, 0x2a, (byte) 0xbe, 0x04, (byte) 0xc3, 047 (byte) 0xaa, 0x44, 0x13, 0x26, 0x49, (byte) 0x86, 0x06, 048 (byte) 0x99, (byte) 0x9c, 0x42, 0x50, (byte) 0xf4, (byte) 0x91, 049 (byte) 0xef, (byte) 0x98, 0x7a, 0x33, 0x54, 0x0b, 0x43, 050 (byte) 0xed, (byte) 0xcf, (byte) 0xac, 0x62, (byte) 0xe4, 051 (byte) 0xb3, 0x1c, (byte) 0xa9, (byte) 0xc9, 0x08, (byte) 0xe8, 052 (byte) 0x95, (byte) 0x80, (byte) 0xdf, (byte) 0x94, (byte) 0xfa, 053 0x75, (byte) 0x8f, 0x3f, (byte) 0xa6, 0x47, 0x07, (byte) 0xa7, 054 (byte) 0xfc, (byte) 0xf3, 0x73, 0x17, (byte) 0xba, (byte) 0x83, 055 0x59, 0x3c, 0x19, (byte) 0xe6, (byte) 0x85, 0x4f, (byte) 0xa8, 056 0x68, 0x6b, (byte) 0x81, (byte) 0xb2, 0x71, 0x64, (byte) 0xda, 057 (byte) 0x8b, (byte) 0xf8, (byte) 0xeb, 0x0f, 0x4b, 0x70, 0x56, 058 (byte) 0x9d, 0x35, 0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, (byte) 0xd1, 059 (byte) 0xa2, 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, (byte) 0x87, 060 (byte) 0xd4, 0x00, 0x46, 0x57, (byte) 0x9f, (byte) 0xd3, 0x27, 061 0x52, 0x4c, 0x36, 0x02, (byte) 0xe7, (byte) 0xa0, (byte) 0xc4, 062 (byte) 0xc8, (byte) 0x9e, (byte) 0xea, (byte) 0xbf, (byte) 0x8a, 063 (byte) 0xd2, 0x40, (byte) 0xc7, 0x38, (byte) 0xb5, (byte) 0xa3, 064 (byte) 0xf7, (byte) 0xf2, (byte) 0xce, (byte) 0xf9, 0x61, 0x15, 065 (byte) 0xa1, (byte) 0xe0, (byte) 0xae, 0x5d, (byte) 0xa4, 066 (byte) 0x9b, 0x34, 0x1a, 0x55, (byte) 0xad, (byte) 0x93, 0x32, 067 0x30, (byte) 0xf5, (byte) 0x8c, (byte) 0xb1, (byte) 0xe3, 0x1d, 068 (byte) 0xf6, (byte) 0xe2, 0x2e, (byte) 0x82, 0x66, (byte) 0xca, 069 0x60, (byte) 0xc0, 0x29, 0x23, (byte) 0xab, 0x0d, 0x53, 0x4e, 0x6f, 070 (byte) 0xd5, (byte) 0xdb, 0x37, 0x45, (byte) 0xde, (byte) 0xfd, 071 (byte) 0x8e, 0x2f, 0x03, (byte) 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 072 0x51, (byte) 0x8d, 0x1b, (byte) 0xaf, (byte) 0x92, (byte) 0xbb, 073 (byte) 0xdd, (byte) 0xbc, 0x7f, 0x11, (byte) 0xd9, 0x5c, 0x41, 074 0x1f, 0x10, 0x5a, (byte) 0xd8, 0x0a, (byte) 0xc1, 0x31, 075 (byte) 0x88, (byte) 0xa5, (byte) 0xcd, 0x7b, (byte) 0xbd, 0x2d, 076 0x74, (byte) 0xd0, 0x12, (byte) 0xb8, (byte) 0xe5, (byte) 0xb4, 077 (byte) 0xb0, (byte) 0x89, 0x69, (byte) 0x97, 0x4a, 0x0c, 078 (byte) 0x96, 0x77, 0x7e, 0x65, (byte) 0xb9, (byte) 0xf1, 0x09, 079 (byte) 0xc5, 0x6e, (byte) 0xc6, (byte) 0x84, 0x18, (byte) 0xf0, 080 0x7d, (byte) 0xec, 0x3a, (byte) 0xdc, 0x4d, 0x20, 0x79, 081 (byte) 0xee, 0x5f, 0x3e, (byte) 0xd7, (byte) 0xcb, 0x39, 0x48}; 082 083 public static final int[] FK = {0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc}; 084 085 public static final int[] CK = {0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269, 086 0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9, 087 0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249, 088 0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9, 089 0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229, 090 0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299, 091 0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209, 092 0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279}; 093 094 private byte sm4Sbox(byte inch) { 095 int i = inch & 0xFF; 096 byte retVal = SboxTable[i]; 097 return retVal; 098 } 099 100 private long sm4Lt(long ka) { 101 long bb = 0L; 102 long c = 0L; 103 byte[] a = new byte[4]; 104 byte[] b = new byte[4]; 105 PUT_ULONG_BE(ka, a, 0); 106 b[0] = sm4Sbox(a[0]); 107 b[1] = sm4Sbox(a[1]); 108 b[2] = sm4Sbox(a[2]); 109 b[3] = sm4Sbox(a[3]); 110 bb = GET_ULONG_BE(b, 0); 111 c = bb ^ ROTL(bb, 2) ^ ROTL(bb, 10) ^ ROTL(bb, 18) ^ ROTL(bb, 24); 112 return c; 113 } 114 115 private long sm4F(long x0, long x1, long x2, long x3, long rk) { 116 return x0 ^ sm4Lt(x1 ^ x2 ^ x3 ^ rk); 117 } 118 119 private long sm4CalciRK(long ka) { 120 long bb = 0L; 121 long rk = 0L; 122 byte[] a = new byte[4]; 123 byte[] b = new byte[4]; 124 PUT_ULONG_BE(ka, a, 0); 125 b[0] = sm4Sbox(a[0]); 126 b[1] = sm4Sbox(a[1]); 127 b[2] = sm4Sbox(a[2]); 128 b[3] = sm4Sbox(a[3]); 129 bb = GET_ULONG_BE(b, 0); 130 rk = bb ^ ROTL(bb, 13) ^ ROTL(bb, 23); 131 return rk; 132 } 133 134 private void sm4_setkey(long[] SK, byte[] key) { 135 long[] MK = new long[4]; 136 long[] k = new long[36]; 137 int i = 0; 138 MK[0] = GET_ULONG_BE(key, 0); 139 MK[1] = GET_ULONG_BE(key, 4); 140 MK[2] = GET_ULONG_BE(key, 8); 141 MK[3] = GET_ULONG_BE(key, 12); 142 k[0] = MK[0] ^ (long) FK[0]; 143 k[1] = MK[1] ^ (long) FK[1]; 144 k[2] = MK[2] ^ (long) FK[2]; 145 k[3] = MK[3] ^ (long) FK[3]; 146 for (; i < 32; i++) { 147 k[(i + 4)] = (k[i] ^ sm4CalciRK(k[(i + 1)] ^ k[(i + 2)] ^ k[(i + 3)] ^ (long) CK[i])); 148 SK[i] = k[(i + 4)]; 149 } 150 } 151 152 private void sm4_one_round(long[] sk, byte[] input, byte[] output) { 153 int i = 0; 154 long[] ulbuf = new long[36]; 155 ulbuf[0] = GET_ULONG_BE(input, 0); 156 ulbuf[1] = GET_ULONG_BE(input, 4); 157 ulbuf[2] = GET_ULONG_BE(input, 8); 158 ulbuf[3] = GET_ULONG_BE(input, 12); 159 while (i < 32) { 160 ulbuf[(i + 4)] = sm4F(ulbuf[i], ulbuf[(i + 1)], ulbuf[(i + 2)], ulbuf[(i + 3)], sk[i]); 161 i++; 162 } 163 PUT_ULONG_BE(ulbuf[35], output, 0); 164 PUT_ULONG_BE(ulbuf[34], output, 4); 165 PUT_ULONG_BE(ulbuf[33], output, 8); 166 PUT_ULONG_BE(ulbuf[32], output, 12); 167 } 168 //修改了填充模式,为模式 169 private byte[] padding(byte[] input, int mode) { 170 if (input == null) { 171 return null; 172 } 173 174 byte[] ret = (byte[]) null; 175 if (mode == SM4_ENCRYPT) { 176 //填充:hex必须是32的整数倍填充 ,填充的是80 00 00 00 177 int p = 16 - input.length % 16; 178 String inputHex = ConvertUtil.byteToHex(input)+ "80"; 179 StringBuffer stringBuffer =new StringBuffer(inputHex); 180 for (int i = 0; i <p-1 ; i++) { 181 stringBuffer.append("00"); 182 } 183 ret= ConvertUtil.hexToByte(stringBuffer.toString()); 184 //ret = new byte[input.length + p]; 185 /*System.arraycopy(input, 0, ret, 0, input.length); 186 for (int i = 0; i < p; i++) { 187 ret[input.length + i] = (byte) '�'; 188 }*/ 189 } else { 190 /*int p = input[input.length - 1]; 191 ret = new byte[input.length - p]; 192 System.arraycopy(input, 0, ret, 0, input.length - p);*/ 193 String inputHex =ConvertUtil.byteToHex(input); 194 int i = inputHex.lastIndexOf("80"); 195 String substring = inputHex.substring(0, i); 196 ret= ConvertUtil.hexToByte(substring); 197 } 198 return ret; 199 } 200 201 public void sm4_setkey_enc(SM4_Context ctx, byte[] key) throws Exception { 202 if (ctx == null) { 203 throw new Exception("ctx is null!"); 204 } 205 206 if (key == null || key.length != 16) { 207 throw new Exception("key error!"); 208 } 209 210 ctx.mode = SM4_ENCRYPT; 211 sm4_setkey(ctx.sk, key); 212 } 213 214 public void sm4_setkey_dec(SM4_Context ctx, byte[] key) throws Exception { 215 if (ctx == null) { 216 throw new Exception("ctx is null!"); 217 } 218 219 if (key == null || key.length != 16) { 220 throw new Exception("key error!"); 221 } 222 223 int i = 0; 224 ctx.mode = SM4_DECRYPT; 225 sm4_setkey(ctx.sk, key); 226 for (i = 0; i < 16; i++) { 227 SWAP(ctx.sk, i); 228 } 229 } 230 231 public byte[] sm4_crypt_ecb(SM4_Context ctx, byte[] input) throws Exception { 232 if (input == null) { 233 throw new Exception("input is null!"); 234 } 235 236 if ((ctx.isPadding) && (ctx.mode == SM4_ENCRYPT)) { 237 input = padding(input, SM4_ENCRYPT); 238 } 239 240 int length = input.length; 241 ByteArrayInputStream bins = new ByteArrayInputStream(input); 242 ByteArrayOutputStream bous = new ByteArrayOutputStream(); 243 for (; length > 0; length -= 16) { 244 byte[] in = new byte[16]; 245 byte[] out = new byte[16]; 246 bins.read(in); 247 sm4_one_round(ctx.sk, in, out); 248 bous.write(out); 249 } 250 251 byte[] output = bous.toByteArray(); 252 if (ctx.isPadding && ctx.mode == SM4_DECRYPT) { 253 output = padding(output, SM4_DECRYPT); 254 } 255 bins.close(); 256 bous.close(); 257 return output; 258 } 259 260 public byte[] sm4_crypt_cbc(SM4_Context ctx, byte[] iv, byte[] input) throws Exception { 261 if (iv == null || iv.length != 16) { 262 throw new Exception("iv error!"); 263 } 264 265 if (input == null) { 266 throw new Exception("input is null!"); 267 } 268 269 if (ctx.isPadding && ctx.mode == SM4_ENCRYPT) { 270 input = padding(input, SM4_ENCRYPT); 271 } 272 273 int i = 0; 274 int length = input.length; 275 ByteArrayInputStream bins = new ByteArrayInputStream(input); 276 ByteArrayOutputStream bous = new ByteArrayOutputStream(); 277 if (ctx.mode == SM4_ENCRYPT) { 278 for (; length > 0; length -= 16) { 279 byte[] in = new byte[16]; 280 byte[] out = new byte[16]; 281 byte[] out1 = new byte[16]; 282 283 bins.read(in); 284 for (i = 0; i < 16; i++) { 285 out[i] = ((byte) (in[i] ^ iv[i])); 286 } 287 sm4_one_round(ctx.sk, out, out1); 288 System.arraycopy(out1, 0, iv, 0, 16); 289 bous.write(out1); 290 } 291 } else { 292 byte[] temp = new byte[16]; 293 for (; length > 0; length -= 16) { 294 byte[] in = new byte[16]; 295 byte[] out = new byte[16]; 296 byte[] out1 = new byte[16]; 297 298 bins.read(in); 299 System.arraycopy(in, 0, temp, 0, 16); 300 sm4_one_round(ctx.sk, in, out); 301 for (i = 0; i < 16; i++) { 302 out1[i] = ((byte) (out[i] ^ iv[i])); 303 } 304 System.arraycopy(temp, 0, iv, 0, 16); 305 bous.write(out1); 306 } 307 } 308 309 byte[] output = bous.toByteArray(); 310 if (ctx.isPadding && ctx.mode == SM4_DECRYPT) { 311 output = padding(output, SM4_DECRYPT); 312 } 313 bins.close(); 314 bous.close(); 315 return output; 316 } 317}