From b0a1c42ff300b264d9559880b02c070901143104 Mon Sep 17 00:00:00 2001 From: zhoubin <2023106681@qq.com> Date: Tue, 19 Oct 2021 15:16:09 +0800 Subject: [PATCH] =?UTF-8?q?1=E3=80=81=E4=BC=98=E5=8C=96sm4=5Fcbc=E5=8A=A0?= =?UTF-8?q?=E8=A7=A3=E5=AF=86=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/sunyard/SYMEnDeLongData.java | 194 +++++++++++++++ src/main/java/com/sunyard/trans/Alg.java | 32 +++ src/main/java/com/sunyard/trans/FullMode.java | 27 +- .../java/com/sunyard/trans/RoundMode.java | 25 ++ src/main/java/com/sunyard/util/FileUtil.java | 6 +- .../java/racal/sunyard/main/SydApi4j.java | 235 +++++++++++++++++- .../sunyard/sydapi/test/TestAllMethods.java | 4 +- 7 files changed, 507 insertions(+), 16 deletions(-) create mode 100644 src/main/java/com/sunyard/SYMEnDeLongData.java create mode 100644 src/main/java/com/sunyard/trans/Alg.java create mode 100644 src/main/java/com/sunyard/trans/RoundMode.java diff --git a/src/main/java/com/sunyard/SYMEnDeLongData.java b/src/main/java/com/sunyard/SYMEnDeLongData.java new file mode 100644 index 0000000..dd106da --- /dev/null +++ b/src/main/java/com/sunyard/SYMEnDeLongData.java @@ -0,0 +1,194 @@ +package com.sunyard; + + +import com.sunyard.proto.Util; +import com.sunyard.trans.Alg; +import com.sunyard.trans.FullMode; +import com.sunyard.trans.RoundMode; +import racal.sunyard.main.SydApi4j; + +public class SYMEnDeLongData { + private SydApi4j api; + private String key = ""; + private String keyValue = ""; + private int keyType = 0; + private int inType = 0; + private int outType = 0; + private byte[] iv = new byte[0]; + private Alg alg = null; + private RoundMode roundMode=null; + private FullMode fullMode=null; + private byte[] data=null; + //private byte[] data=new byte[0]; + private boolean isFirst = true; + private boolean isFinal = false; + private boolean isEn = true; + + public RoundMode getRoundMode() { + return roundMode; + } + + public SYMEnDeLongData setRoundMode(RoundMode roundMode) { + this.roundMode = roundMode; + return this; + } + + public FullMode getFullMode() { + return fullMode; + } + + public SYMEnDeLongData setFullMode(FullMode fullMode) { + this.fullMode = fullMode; + return this; + } + + public byte[] getIv() { + return iv; + } + + public SYMEnDeLongData setIv(byte[] iv) { + this.iv = iv; + return this; + } + + public Alg getAlg() { + return alg; + } + + public void setAlg(Alg alg) { + this.alg = alg; + } + + public int getKeyType() { + return keyType; + } + + public SYMEnDeLongData setKeyType(int keyType) { + this.keyType = keyType; + return this; + } + + public int getInType() { + return inType; + } + + public SYMEnDeLongData setInType(int inType) { + this.inType = inType; + return this; + } + + public int getOutType() { + return outType; + } + + public SYMEnDeLongData setOutType(int outType) { + this.outType = outType; + return this; + } + + public SYMEnDeLongData(SydApi4j api, Alg alg, RoundMode roundMode, FullMode fullMode) { + this.api = api; + this.alg=alg; + this.roundMode=roundMode; + this.fullMode=fullMode; + } + + + public String getKey() { + return key; + } + + public SYMEnDeLongData setKey(String key) { + this.key = key; + return this; + } + + + public String getKeyValue() { + return keyValue; + } + + public SYMEnDeLongData setKeyValue(String keyValue) { + this.keyValue = keyValue; + return this; + } + + public SYMEnDeLongData en(){ + this.isEn = true; + return this; + } + + public SYMEnDeLongData de(){ + this.isEn = false; + return this; + } + + + public byte[] update(byte[] data){ + if ( isFinal ){ + throw new SydApiException("此时已经不能再更新",370000); + } + + if ( this.isEn ){ + // this.data = this.api.SYMEncryptData(this.key,this.keyValue,this.alg,this.roundMode,this.fullMode,this.isFirst ? 1 : 2 , data); + System.out.println("块号block:"+(this.isFirst ? 1 : 2)); + RetWrap en = this.api.SM4EncryptDataCBC(this.isEn, this.keyType, this.keyValue, this.inType, this.outType, data, this.iv, this.isFirst ? 1 : 2); + this.data = (byte[]) en.get("msg_all"); + this.iv = (byte[]) en.get("iv"); + System.out.println("下一IV长度:"+this.iv.length); + System.out.println("iv---"+ Util.bytes2HexString(this.iv)); + } else { + RetWrap de = this.api.SM4EncryptDataCBC(this.isEn, this.keyType, this.keyValue, this.inType, this.outType, data, this.iv, this.isFirst ? 1 : 2); + this.data = (byte[]) de.get("msg_all"); + this.iv = (byte[]) de.get("iv"); + } + + this.isFirst = false; + return this.data; + } + + + public byte[] calc(byte[] lastData ){ + return calc( lastData, lastData.length ); + } + public byte[] calc(byte[] lastData, int len ) { + if ( isFinal ){ + throw new SydApiException("此时已经不能再计算",370000); + } + + byte[] last = null; + + if( len < 0 ){ + len = 0; + } + + if ( 0 == lastData.length ){ + last = new byte[0]; + } else if ( lastData.length == len ){ + last = lastData; + } else { + last = new byte[len]; + System.arraycopy( lastData, 0, last, 0, len ); + } + + this.isFinal = true; + + int block = 3; + if ( null == this.data ){ + block = 0; + } + + if (last.length>0){ + + if ( this.isEn ){ + System.out.println("block:"+block); + this.data = (byte[]) this.api.SM4EncryptDataCBC(this.isEn, this.keyType, this.keyValue, this.inType, this.outType, last, this.iv, block).get("msg_all"); + } else { + System.out.println("block:"+block); + this.data = (byte[]) this.api.SM4EncryptDataCBC(this.isEn, this.keyType, this.keyValue, this.inType, this.outType, last, this.iv, block).get("msg_all"); + } + } + + return this.data; + } +} diff --git a/src/main/java/com/sunyard/trans/Alg.java b/src/main/java/com/sunyard/trans/Alg.java new file mode 100644 index 0000000..a492f0a --- /dev/null +++ b/src/main/java/com/sunyard/trans/Alg.java @@ -0,0 +1,32 @@ +package com.sunyard.trans; + +public enum Alg { + + DES("DES", 0), + DES3("DES3", 1), + AES( "AES", 2), + AES256( "AES256", 3), + SSF33( "SSF33", 4), + SM1( "SM1", 5), + SM2( "SM2", 6), + SM3( "SM3", 7), + SM4( "SM4", 8), + RSA( "RSA", 9); + + + private String name; + private int value; + // 构造方法 + private Alg(String name, int value) { + this.name = name; + this.value = value; + } + + public String getName() { + return name; + } + + public int getValue() { + return value; + } +} diff --git a/src/main/java/com/sunyard/trans/FullMode.java b/src/main/java/com/sunyard/trans/FullMode.java index 15f2760..d3e3b85 100644 --- a/src/main/java/com/sunyard/trans/FullMode.java +++ b/src/main/java/com/sunyard/trans/FullMode.java @@ -4,13 +4,34 @@ package com.sunyard.trans; */ public enum FullMode { + PKCS("PKCS", 1), //PKCS5/PKCS7 + NOFILL( "NOFILL", 2), + WEAKFILL( "WEAKFILL", 3), + STRONGFILL( "STRONGFILL", 4); + + private String name; + private int value; + // 构造方法 + private FullMode(String name, int value) { + this.name = name; + this.value = value; + } + + public String getName() { + return name; + } + + public int getValue() { + return value; + } + /** * 如果数据块长度为 8/16 的整数倍,不需要填 充;如果长度不为 8/16 的整数倍,填充至长度满 8/16 的整数倍(填充方式按 Pad character 域中 描述的规则进行,由加密机内部自动完成) */ - FULL_8_16, +// FULL_8_16, /** * 如果数据块长度为 8/16 的整数倍,填充一个 整 8/16 字节的数据(填充方式按 Pad character @@ -19,5 +40,7 @@ public enum FullMode { 的整数倍(填充方式按 Pad character 域中描述 的规则进行,由加密机内部自动完成) */ - FULL_MORE_8_16 +// FULL_MORE_8_16 + + } diff --git a/src/main/java/com/sunyard/trans/RoundMode.java b/src/main/java/com/sunyard/trans/RoundMode.java new file mode 100644 index 0000000..e2d67e5 --- /dev/null +++ b/src/main/java/com/sunyard/trans/RoundMode.java @@ -0,0 +1,25 @@ +package com.sunyard.trans; + +public enum RoundMode { + + ECB("ECB", 1), + CBC( "CBC", 2), + CFB( "CFB", 3), + OFB( "OFB", 4); + + private String name; + private int value; + // 构造方法 + private RoundMode(String name, int value) { + this.name = name; + this.value = value; + } + + public String getName() { + return name; + } + + public int getValue() { + return value; + } +} diff --git a/src/main/java/com/sunyard/util/FileUtil.java b/src/main/java/com/sunyard/util/FileUtil.java index 4811a87..7cc8ad4 100644 --- a/src/main/java/com/sunyard/util/FileUtil.java +++ b/src/main/java/com/sunyard/util/FileUtil.java @@ -64,10 +64,10 @@ public class FileUtil { * @param path 文件路径 * @param data 数据 */ - public static void printDataToFile(String path, String data) { - BufferedWriter osw = null; + public static void printDataToFile(String path, byte[] data) { + BufferedOutputStream osw = null; try { - osw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(path), "UTF-8")); + osw = new BufferedOutputStream(new FileOutputStream(path)); osw.write(data); diff --git a/src/main/java/racal/sunyard/main/SydApi4j.java b/src/main/java/racal/sunyard/main/SydApi4j.java index 2f5ba6a..0cc94e5 100644 --- a/src/main/java/racal/sunyard/main/SydApi4j.java +++ b/src/main/java/racal/sunyard/main/SydApi4j.java @@ -1,6 +1,7 @@ package racal.sunyard.main; import com.sunyard.RetWrap; +import com.sunyard.SYMEnDeLongData; import com.sunyard.SydApi; import com.sunyard.SydApiException; import com.sunyard.cert.X509; @@ -10,7 +11,10 @@ import com.sunyard.proto.PacketSection; import com.sunyard.proto.Util; import com.sunyard.proto.section.SectionValue; import com.sunyard.proto.value.Str; +import com.sunyard.trans.Alg; +import com.sunyard.trans.FullMode; import com.sunyard.trans.PacketSN; +import com.sunyard.trans.RoundMode; import com.sunyard.util.CoderUtil; import com.sunyard.util.FileUtil; import com.sunyard.util.MyUtil; @@ -1499,10 +1503,7 @@ public class SydApi4j implements SydApi { if (1 == loop) { // 唯一包 // [如果大包是中间包 2,则全部是中间包] - packNo = 0; - if (2 == block) { - packNo = 2; - } + packNo = block; data.put("packSn$option", packNo); data.put("msg", msgAll); @@ -4248,7 +4249,7 @@ public class SydApi4j implements SydApi { * @return 加密是否成功。false为失败,true为成功 */ // 测试通过 - @Override +// @Override public boolean SM4EncryptFileDataCBC(int keyType, String key, int inType, int outType, String inFilePath, String outFilePath) { byte[] msg = FileUtil.getDataFromFile(inFilePath); @@ -4261,11 +4262,142 @@ public class SydApi4j implements SydApi { byte[] result = SM4EncryptDataCBC(keyType, key, inType, outType, msg); String str = Util.bytes2HexString(result); - FileUtil.printDataToFile(outFilePath, str); + FileUtil.printDataToFile(outFilePath, str.getBytes()); return true; } +// @Override + public boolean _SM4EncryptFileDataCBC(int keyType, String key, int inType, int outType, String inFilePath, String outFilePath) { + + byte[] iv = new byte[32]; + Arrays.fill(iv, (byte) 0x30); + SYMEnDeLongData sym = SYMEnDeLongData_CBC_PKCS() + .en().setKeyValue(key).setIv(iv).setKeyType(keyType) + .setInType(inType).setOutType(outType); + + File in = new File(inFilePath); + + if ( !in.exists() ){ + System.out.println("要加密的文件不存在"); + } + + long length = in.length(); + int l = new Long(length).intValue(); + int n = l / ( 2 * 1024); + System.out.println("n 个 2k:"+n); + + if (l % ( 2 * 1024) != 0) { + n++; + } + + File out = new File(outFilePath); + if ( out.exists() ){ + out.delete(); + } + try { + out.createNewFile(); + } catch (IOException e) { + e.printStackTrace(); + } + FileInputStream fis =null; + FileOutputStream fos=null; + + try { + fis = new FileInputStream(in); + fos = new FileOutputStream(out); + byte[] buff = new byte[2 * 1024]; + + for (int i = 0; i < n-1; i++) { + int len = fis.read( buff ); + //先判断是否是最后一块/唯一块,是->calc, + //首块和中间块才->update + if ( len == buff.length){ + println("len长度_update:"+len); + byte[] en = sym.update( buff ); + println("en长度:"+en.length); +// String str = Util.bytes2HexString(en); + fos.write( en ); + } + } + + int len = fis.read( buff ); + //先判断是否是最后一块/唯一块,是->calc, + //首块和中间块才->update + if ( len <= buff.length && len>-1) { + println("len长度_calc:" + len); + byte[] en = sym.calc(buff, len); + println("en长度:" + en.length); +// String str = Util.bytes2HexString(en); + fos.write( en ); + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + if (fis != null) { + try { + fis.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + if (fos != null) { + try { + fos.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + return true; + } + + public SYMEnDeLongData SYMEnDeLongData_CBC_PKCS() { + return new SYMEnDeLongData(this, Alg.SM4, RoundMode.CBC, FullMode.PKCS); + } + +// @Override + public RetWrap SM4EncryptDataCBC(Boolean isEn, int keyType, String key, int inType, int outType, byte[] msg, byte[] iv, int block) { + + // 填充数据 + HashMap packet = new HashMap(); + HashMap data = new HashMap(); + + // 确认算法 + if (isEn) { + data.put("alg$option", 0x8); + + } else { + data.put("alg$option", 0x9); + + } + + // 确认 roundmod + data.put("roundModel$option", 1); + + // 确认 iv + data.put("iv", iv); + data.put("block", block); + + + data.put("keyType$option", keyType); + data.put("key", key.getBytes()); + data.put("inType$option", inType); + data.put("outType$option", outType); + data.put("fullMode$option", 1); + data.put("fullChar$option", 0); + data.put("fullType$option", 2); + data.put("msg", msg); + + packet.put("data", data); + + RetWrap retWrap = repackEncrypt(packet, !isEn); + + return retWrap; + } + /** * 使用SM4算法进行加密,其中加密模式为CBC, * Ⅳ使用缺省值0X 00000000000000000000000000000000, @@ -4317,7 +4449,7 @@ public class SydApi4j implements SydApi { * @return 解密是否成功。false为失败,true为成功 */ // 测试通过 - @Override +// @Override public boolean SM4DecryptFileDataCBC(int keyType, String key, int inType, int outType, String inFilePath, String outFilePath) throws UnsupportedEncodingException { byte[] msg = FileUtil.getDataFromFile(inFilePath); @@ -4329,9 +4461,94 @@ public class SydApi4j implements SydApi { // 调用加密接口将数据加密 byte[] result = SM4DecryptDataCBC(keyType, key, inType, outType, Util.hexString2Bytes(new String(msg))); - String str = new String(result, "utf-8"); + FileUtil.printDataToFile(outFilePath, result); - FileUtil.printDataToFile(outFilePath, str); + return true; + } + +// @Override + public boolean _SM4DecryptFileDataCBC(int keyType, String key, int inType, int outType, String inFilePath, String outFilePath) { + + println("解密============================"); + byte[] iv = new byte[32]; + Arrays.fill(iv, (byte) 0x30); + SYMEnDeLongData sym = SYMEnDeLongData_CBC_PKCS() + .de().setKeyValue(key).setIv(iv).setKeyType(keyType) + .setInType(inType).setOutType(outType); + + File in = new File(inFilePath); + + if ( !in.exists() ){ + System.out.println("要解密的文件不存在"); + } + + long length = in.length(); + int l = new Long(length).intValue(); + int n = l / ( 2 * 1024); + System.out.println("n 个 2k:"+n); + + if (l % ( 2 * 1024) != 0) { + n++; + } + + File out = new File(outFilePath); + if ( out.exists() ){ + out.delete(); + } + try { + out.createNewFile(); + } catch (IOException e) { + e.printStackTrace(); + } + FileInputStream fis =null; + FileOutputStream fos=null; + + try { + fis = new FileInputStream(in); + fos = new FileOutputStream(out); + byte[] buff = new byte[2 * 1024]; + byte[] buff1 = new byte[2 * 1024 + 16]; + + for (int i = 0; i < n-1; i++) { + int len = fis.read( buff ); + //先判断是否是最后一块/唯一块,是->calc, + //首块和中间块才->update + if ( len == buff.length){ + println("len长度_update:"+len); + byte[] en = sym.update( buff ); + println("en长度:"+en.length); + fos.write( en ); + } + } + + int len = fis.read( buff1 ); + //先判断是否是最后一块/唯一块,是->calc, + //首块和中间块才->update + if ( len <= buff1.length && len>-1) { + println("len长度_calc:" + len); + byte[] en = sym.calc(buff1, len); + println("en长度:" + en.length); + fos.write(en); + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + if (fis != null) { + try { + fis.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + if (fos != null) { + try { + fos.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } return true; } diff --git a/src/test/java/com/sunyard/sydapi/test/TestAllMethods.java b/src/test/java/com/sunyard/sydapi/test/TestAllMethods.java index 56d08c1..3076080 100644 --- a/src/test/java/com/sunyard/sydapi/test/TestAllMethods.java +++ b/src/test/java/com/sunyard/sydapi/test/TestAllMethods.java @@ -678,9 +678,9 @@ public class TestAllMethods { String outFilePath = "C:\\Users\\edgar\\Desktop\\fsdownload\\test\\in2.txt"; String outFilePath2 = "C:\\Users\\edgar\\Desktop\\fsdownload\\test\\out1.txt"; - boolean b = api.SM4EncryptFileDataCBC(0, key, 0, 0, inFilePath, outFilePath); + boolean b = api._SM4EncryptFileDataCBC(0, key, 0, 0, inFilePath, outFilePath); System.out.println(b); - boolean c = api.SM4DecryptFileDataCBC(0, key, 0, 0, outFilePath, outFilePath2); + boolean c = api._SM4DecryptFileDataCBC(0, key, 0, 0, outFilePath, outFilePath2); System.out.println(c); }