SM4算法大文件加密与字符串加密
生活随笔
收集整理的這篇文章主要介紹了
SM4算法大文件加密与字符串加密
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
引入包
<!-- 一個開源的加解密算法包 --><dependency><groupId>org.bouncycastle</groupId><artifactId>bcmail-jdk15on</artifactId><version>1.66</version></dependency><!-- 測試包 --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version></dependency>工具類
import org.bouncycastle.jce.provider.BouncyCastleProvider;import javax.crypto.Cipher; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.SecretKeySpec; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.charset.StandardCharsets; import java.security.Key; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.security.Security; import java.security.spec.InvalidKeySpecException; import java.security.spec.KeySpec; import java.util.Base64;/*** @author zkk*/ public class Sm4Helper3 {private static final String PADDING_MODE = "SM4/ECB/PKCS5Padding";private static final String FILE_MODE_READ = "r";private static final String FILE_MODE_READ_WRITE = "rw";private static final String PBK_SHA1 = "PBKDF2WithHmacSHA1";private static final String ALGORITHM_SM4 = "SM4";private static final int KEY_DEFAULT_SIZE = 128;private static final int ENCRYPT_BUFFER_SIZE = 1024;private static final int DECRYPT_BUFFER_SIZE = 1040;static{try{Security.addProvider(new BouncyCastleProvider());}catch(Exception e){e.printStackTrace();}}/*** 文件加密* @param sourceFilePath 源文件文件路徑* @param encryptFilePath 加密后文件路徑* @param seed 種子* @throws Exception 異常*/public static void encryptFile(String sourceFilePath, String encryptFilePath, String seed) throws Exception {sm4Cipher(Cipher.ENCRYPT_MODE, sourceFilePath, encryptFilePath, seed);}/*** 文件解密* @param encryptFilePath 加密文件路徑* @param targetFilePath 解密后文件路徑* @param seed 種子* @throws Exception 異常*/public static void decryptFile(String encryptFilePath, String targetFilePath, String seed) throws Exception {sm4Cipher(Cipher.DECRYPT_MODE, encryptFilePath, targetFilePath, seed);}/*** 文件加解密過程* @param cipherMode 加解密選項* @param sourceFilePath 源文件地址* @param targetFilePath 目標文件地址* @param seed 密鑰種子* @throws Exception 出現異常*/private static void sm4Cipher(int cipherMode, String sourceFilePath,String targetFilePath, String seed) throws Exception {FileChannel sourcefc = null;FileChannel targetfc = null;try {byte[] rawKey = getRawKey(seed);Cipher mCipher = generateEcbCipher(cipherMode, rawKey);File sourceFile = new File(sourceFilePath);File targetFile = new File(targetFilePath);sourcefc = new RandomAccessFile(sourceFile, FILE_MODE_READ).getChannel();targetfc = new RandomAccessFile(targetFile, FILE_MODE_READ_WRITE).getChannel();int bufferSize = Cipher.ENCRYPT_MODE == cipherMode ? ENCRYPT_BUFFER_SIZE : DECRYPT_BUFFER_SIZE;ByteBuffer byteData = ByteBuffer.allocate(bufferSize);while (sourcefc.read(byteData) != -1) {// 通過通道讀寫交叉進行。// 將緩沖區準備為數據傳出狀態byteData.flip();byte[] byteList = new byte[byteData.remaining()];byteData.get(byteList, 0, byteList.length);//此處,若不使用數組加密解密會失敗,因為當byteData達不到1024個時,加密方式不同對空白字節的處理也不相同,從而導致成功與失敗。byte[] bytes = mCipher.doFinal(byteList);targetfc.write(ByteBuffer.wrap(bytes));byteData.clear();}} finally {try {if (sourcefc != null) {sourcefc.close();}if (targetfc != null) {targetfc.close();}} catch (IOException e) {e.printStackTrace();}}}/*** 大字符串分段加密* @param content 需要加密的內容* @param seed 種子* @return 加密后內容* @throws Exception 異常*/public static String sm4EncryptLarge(String content, String seed) throws Exception {byte[] data = content.getBytes(StandardCharsets.UTF_8);byte[] rawKey = getRawKey(seed);Cipher mCipher = generateEcbCipher(Cipher.ENCRYPT_MODE, rawKey);int inputLen = data.length;ByteArrayOutputStream out = new ByteArrayOutputStream();int offSet = 0;byte[] cache;int i = 0;// 對數據分段解密while (inputLen - offSet > 0) {if (inputLen - offSet > ENCRYPT_BUFFER_SIZE) {cache = mCipher.doFinal(data, offSet, ENCRYPT_BUFFER_SIZE);} else {cache = mCipher.doFinal(data, offSet, inputLen - offSet);}out.write(cache, 0, cache.length);i++;offSet = i * ENCRYPT_BUFFER_SIZE;}byte[] decryptedData = out.toByteArray();out.close();return Base64.getEncoder().encodeToString(decryptedData);}/*** 大字符串分段解密* @param content 密文* @param seed 種子* @return 解密后內容* @throws Exception 異常*/public static String sm4DecryptLarge(String content, String seed) throws Exception {byte[] data = Base64.getDecoder().decode(content);byte[] rawKey = getRawKey(seed);Cipher mCipher = generateEcbCipher(Cipher.DECRYPT_MODE, rawKey);int inputLen = data.length;ByteArrayOutputStream out = new ByteArrayOutputStream();int offSet = 0;byte[] cache;int i = 0;// 對數據分段解密while (inputLen - offSet > 0) {if (inputLen - offSet > DECRYPT_BUFFER_SIZE) {cache = mCipher.doFinal(data, offSet, DECRYPT_BUFFER_SIZE);} else {cache = mCipher.doFinal(data, offSet, inputLen - offSet);}out.write(cache, 0, cache.length);i++;offSet = i * DECRYPT_BUFFER_SIZE;}byte[] decryptedData = out.toByteArray();out.close();return new String(decryptedData, StandardCharsets.UTF_8);}/*** 字符串加密* @param data 字符串* @param seed 種子* @return 加密后內容* @throws Exception 異常*/public static String sm4Encrypt(String data, String seed) throws Exception {byte[] rawKey = getRawKey(seed);Cipher mCipher = generateEcbCipher(Cipher.ENCRYPT_MODE, rawKey);byte[] bytes = mCipher.doFinal(data.getBytes(StandardCharsets.UTF_8));return Base64.getEncoder().encodeToString(bytes);}/*** 字符串解密* @param data 加密字符串* @param seed 種子* @return 解密后內容* @throws Exception 異常*/public static String sm4Decrypt(String data, String seed) throws Exception {byte[] rawKey = getRawKey(seed);Cipher mCipher = generateEcbCipher(Cipher.DECRYPT_MODE, rawKey);byte[] bytes = mCipher.doFinal(Base64.getDecoder().decode(data));return new String(bytes, StandardCharsets.UTF_8);}/*** 使用一個安全的隨機數來產生一個密匙,密匙加密使用的* @param seed 種子* @return 隨機數組* @throws NoSuchAlgorithmException 模式錯誤*/public static byte[] getRawKey(String seed) throws NoSuchAlgorithmException, InvalidKeySpecException {int count = 1000;int keyLen = KEY_DEFAULT_SIZE;int saltLen = keyLen / 8;SecureRandom random = new SecureRandom();byte[] salt = new byte[saltLen];random.setSeed(seed.getBytes());random.nextBytes(salt);KeySpec keySpec = new PBEKeySpec(seed.toCharArray(), salt, count, keyLen);SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(PBK_SHA1);return secretKeyFactory.generateSecret(keySpec).getEncoded();}/*** 生成ecb模式密碼工具* @param mode 模式* @param key 密鑰* @return 密碼工具* @throws Exception 異常*/private static Cipher generateEcbCipher(int mode, byte[] key) throws Exception{Cipher cipher = Cipher.getInstance(PADDING_MODE, BouncyCastleProvider.PROVIDER_NAME);Key sm4Key = new SecretKeySpec(key, ALGORITHM_SM4);cipher.init(mode, sm4Key);return cipher;} }測試類
import java.time.Clock;/*** @author zkk*/ public class Sm4Test3 {private static final String SEED = "afeawredafe";@org.junit.Testpublic void test1() throws Exception {long time1 = Clock.systemUTC().millis() / 1000;String sourceFile = "E:\\test\\djbx\\file.docx";String targetFile = "E:\\test\\djbx\\file.encrypt";Sm4Helper3.encryptFile(sourceFile, targetFile, SEED);long time2 = Clock.systemUTC().millis() / 1000;System.out.println("加密時間 = " + (time2 - time1));}@org.junit.Testpublic void test2() throws Exception {long time1 = Clock.systemUTC().millis() / 1000;String targetFile = "E:\\test\\djbx\\file.encrypt";String sourceFile2 = "E:\\test\\djbx\\fileDecrypt.docx";Sm4Helper3.decryptFile(targetFile, sourceFile2, SEED);long time2 = Clock.systemUTC().millis() / 1000;System.out.println("解密時間 = " + (time2 - time1));}@org.junit.Testpublic void test3() throws Exception {String content = getLargeContent(1024000);System.out.println("content 長度 = " + content.length());long time1 = Clock.systemUTC().millis() / 1000;String en = Sm4Helper3.sm4Encrypt(content, SEED); // System.out.println("en = " + en);long time2 = Clock.systemUTC().millis() / 1000;content = Sm4Helper3.sm4Decrypt(en, SEED); // System.out.println("content = " + content);long time3 = Clock.systemUTC().millis() / 1000;System.out.println("加密時間 = " + (time2 - time1));System.out.println("解密時間 = " + (time3 - time2));}@org.junit.Testpublic void test4() throws Exception {String content = getLargeContent(1024000);System.out.println("content 長度 = " + content.length());long time1 = Clock.systemUTC().millis() / 1000;String en = Sm4Helper3.sm4EncryptLarge(content, SEED); // System.out.println("en = " + en);long time2 = Clock.systemUTC().millis() / 1000;content = Sm4Helper3.sm4DecryptLarge(en, SEED); // System.out.println("content = " + content);long time3 = Clock.systemUTC().millis() / 1000;System.out.println("加密時間 = " + (time2 - time1));System.out.println("解密時間 = " + (time3 - time2));}private static String getLargeContent(int count){StringBuilder sb = new StringBuilder();for (int i = 0; i < count; i++) {sb.append(getContent(i));}return sb.toString();}private static String getContent(int number){return "這是一段測試數據,結尾行號為"+ number+ "。";} }?
總結
以上是生活随笔為你收集整理的SM4算法大文件加密与字符串加密的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 再玩五分钟手机就开始学习
- 下一篇: 开发APP、微信小程序、网页,都需要什么