日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術文章
文章詳情頁

java實現國產sm4加密算法

瀏覽:28日期:2022-08-19 08:52:22
前言

今天給大家帶來一個國產SM4加密解密算法的java后端解決方案,代碼完整,可以直接使用,希望給大家帶來幫助,尤其是做政府系統的開發人員,可以直接應用到項目中進行加密解密。畫重點!是SM4哦,不是SM。哈哈,各位要在知識里遨游,不要想歪。正文開始~

國產SM4加密解密算法概念介紹

SMS4算法是在國內廣泛使用的WAPI無線網絡標準中使用的加密算法,是一種32輪的迭代非平衡Feistel結構的分組加密算法,其密鑰長度和分組長度均為128。SMS4算法的加解密過程中使用的算法是完全相同的,唯一不同點在于該算法的解密密鑰是由它的加密密鑰進行逆序變換后得到的。SMS4分組加密算法是中國無線標準中使用的分組加密算法,在2012年已經被國家商用密碼管理局確定為國家密碼行業標準,標準編號GM/T 0002-2012并且改名為SM4算法,與SM2橢圓曲線公鑰密碼算法,SM3密碼雜湊算法共同作為國家密碼的行業標準,在我國密碼行業中有著極其重要的位置。SMS4算法的分組長度為128bit,密鑰長度也是128bit。加解密算法均采用32輪非平衡Feistel迭代結構,該結構最先出現在分組密碼LOKI的密鑰擴展算法中。SMS4通過32輪非線性迭代后加上一個反序變換,這樣只需要解密密鑰是加密密鑰的逆序,就能使得解密算法與加密算法保持一致。SMS4加解密算法的結構完全相同,只是在使用輪密鑰時解密密鑰是加密密鑰的逆序。S盒是一種利用非線性變換構造的分組密碼的一個組件,主要是為了實現分組密碼過程中的混淆的特性和設計的。SMS4算法中的S盒在設計之初完全按照歐美分組密碼的設計標準進行,它采用的方法是能夠很好抵抗差值攻擊的仿射函數逆映射復合法。

SM4加密算法應用場景

SM4常用于政府系統的數據傳輸加密,比如當我們前端向后臺傳參數的時候,可以使用此算法。對參數的數據進行加密,然后后臺對加密的數據進行解密再存儲到數據庫中,保證數據傳輸過程中,不受泄露。本次提供的方案不僅提供sm4的加密解密,還提供了md5算法的完整性防篡改校驗。

Java端解決方案

對于java端,我們使用的基于spring的aop切面和自定義注解來實現。整體思路為,當后臺開啟加密解密的時候,針對于打上注解的方法,尋找實體類中打上注解的字段進行加密和解密。再從前端傳遞請求的request中取出md5的header,進行md5的完整性,防篡改校驗。

首先我們必須說的是兩個工具類,一個是SM4Utils工具類,另一個則是md5工具類。下面先來說一下SM4Utils。這個工具類用于SM4算法的加密和解密及密碼校驗。我們先直接看代碼,然后后面對此進行解釋。

SM4Utils

public class Sm4Utils { private static final String ENCODING = 'UTF-8'; public static final String ALGORIGTHM_NAME = 'SM4'; public static final String ALGORITHM_NAME_ECB_PADDING = 'SM4/ECB/PKCS7Padding'; public static final int DEFAULT_KEY_SIZE = 128; public Sm4Utils() { } static { Security.addProvider(new BouncyCastleProvider()); } /** * @Description:生成ecb暗號 */ private static Cipher generateEcbCipher(String algorithmName, int mode, byte[] key) throws Exception { Cipher cipher = Cipher.getInstance(algorithmName,BouncyCastleProvider.PROVIDER_NAME); Key sm4Key = new SecretKeySpec(key, ALGORIGTHM_NAME); cipher.init(mode, sm4Key); return cipher; } /** * @Description:自動生成密鑰 */ public static byte[] generateKey() throws Exception { return generateKey(DEFAULT_KEY_SIZE); } public static byte[] generateKey(int keySize) throws Exception { KeyGenerator kg = KeyGenerator.getInstance(ALGORIGTHM_NAME, BouncyCastleProvider.PROVIDER_NAME); kg.init(keySize, new SecureRandom()); return kg.generateKey().getEncoded(); } /** * @Description:加密 */ public static String encryptEcb(String hexKey, String paramStr, String charset) throws Exception { String cipherText = ''; if (null != paramStr && !''.equals(paramStr)) { byte[] keyData = ByteUtils.fromHexString(hexKey); charset = charset.trim(); if (charset.length() <= 0) {charset = ENCODING; } byte[] srcData = paramStr.getBytes(charset); byte[] cipherArray = encrypt_Ecb_Padding(keyData, srcData); cipherText = ByteUtils.toHexString(cipherArray); } return cipherText; } /** * @Description:加密模式之ecb */ public static byte[] encrypt_Ecb_Padding(byte[] key, byte[] data) throws Exception { Cipher cipher = generateEcbCipher(ALGORITHM_NAME_ECB_PADDING, Cipher.ENCRYPT_MODE, key); byte[] bs = cipher.doFinal(data); return bs; } /** * @Description:sm4解密 */ public static String decryptEcb(String hexKey, String cipherText, String charset) throws Exception { String decryptStr = ''; byte[] keyData = ByteUtils.fromHexString(hexKey); byte[] cipherData = ByteUtils.fromHexString(cipherText); byte[] srcData = decrypt_Ecb_Padding(keyData, cipherData); charset = charset.trim(); if (charset.length() <= 0) { charset = ENCODING; } decryptStr = new String(srcData, charset); return decryptStr; } /** * @Description:解密 */ public static byte[] decrypt_Ecb_Padding(byte[] key, byte[] cipherText) throws Exception { Cipher cipher = generateEcbCipher(ALGORITHM_NAME_ECB_PADDING, Cipher.DECRYPT_MODE, key); return cipher.doFinal(cipherText); } /** * @Description:密碼校驗 */ public static boolean verifyEcb(String hexKey,String cipherText,String paramStr) throws Exception { boolean flag = false; byte[] keyData = ByteUtils.fromHexString(hexKey); byte[] cipherData = ByteUtils.fromHexString(cipherText); byte[] decryptData = decrypt_Ecb_Padding(keyData,cipherData); byte[] srcData = paramStr.getBytes(ENCODING); flag = Arrays.equals(decryptData,srcData); return flag; } /** * @Description:測試類 */ public static void main(String[] args) { try { String json = '{'name':'color','sex':'man'}'; // 自定義的32位16進制密鑰 String key = 'cc9368581322479ebf3e79348a2757d9'; String cipher = Sm4Utils.encryptEcb(key, json,ENCODING); System.out.println(cipher); System.out.println(Sm4Utils.verifyEcb(key, cipher, json)); json = Sm4Utils.decryptEcb(key, cipher,ENCODING); System.out.println(json); } catch (Exception e) { e.printStackTrace(); } }}

我們來仔細看一下上面的代碼,首先定義了個4個靜態不可修改都變量,用于下方方法的使用。包括編碼utf-8,密碼名稱sm4,密碼的分組方式SM4/ECB/PKCS7Padding和默認的key值長度128。整體的方法我們分為生成ecb暗號,自動生成密鑰,加密,解密,密碼校驗的算法。以上為sm4utils的核心代碼。

MD5Utils

/** * @Description:md5加密工具 */public class Md5Utils { /** * @Description:獲得md5加密串 */ public static String getMD5String(String str) { try { MessageDigest md = MessageDigest.getInstance('MD5'); md.update(str.getBytes()); return new BigInteger(1, md.digest()).toString(16); } catch (Exception e) { e.printStackTrace(); return null; } }}

MD5Utils主要用于對參數的完整性校驗,防止篡改。

此時我們已經實現了主要的加密解密工具,接下來實現spring的aop自定義注解,自定義注解我們要實現三個。第一個是加密注解,用于方法上的,表示該方法的參數需要被加密。第二個是解密注解,用于方法上的,表示該方法的參數需要被解密。第三個是字段加密解密注解,用于標識實體類的字段是否需要被加密和解密。

加密的自定義注解

@Documented@Target({ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)@Order(-2147483648)public @interface EncryptMethod {}

可以看到此時打了一個order注解,-2147483648用于標識優先級最高。

解密的自定義注解

@Target({ElementType.METHOD, ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Order(-2147483648)@Inheritedpublic @interface DecryptMethod {}加密解密字段的自定義注解

@Documented@Target({ElementType.FIELD})@Retention(RetentionPolicy.RUNTIME)@Order(-2147483648)public @interface EncryptField {}

注解的準備工作已經做完,接下來就是實現sm4的切面方法。不了解spring的aop的實現方法,可以去先補一下spring的相關知識,這里不做贅述。我們這里采用的切面都是環繞通知,切面的切點是加密解密的注解。

加密解密切面的實現

說一下切面的答題實現思路。我們可以看到@ConditionalOnProperty(prefix = 'sm4', value = 'enable', matchIfMissing = false),這個我們做成了根據配置文件的配置進行動態的開關。我們在appication.yml文件中進行如下的配置。這樣切面是否生效就取決于配置。然后我們捕捉加密的注解和解密的注解,然后對加了注解的方法中的邏輯進行加密和解密。下方代碼的切點方法為EncryptAOPCut和DecryptAOPCut。隨后通過around對切點進行捕捉。分別調用的核心的加密算法encryptMethodAop和解密算法decryptMethodAop。

sm4: enable: true

核心的加密解密算法都是使用環繞通知的ProceedingJoinPoint類,從他的對象中我們可以取到spring的各種參數,包括request請求,請求的參數和response對象。

/** * @Description:sm4加密解密切面 */@Order(-2147483648)@Aspect@Component@ConditionalOnProperty(prefix = 'sm4', value = 'enable', matchIfMissing = false)public class Sm4Aspect { private Logger log = LoggerFactory.getLogger(Sm4Aspect.class); private static final String DEFAULT_KEY = 'cc9368581322479ebf3e79348a2757d9'; public Sm4Aspect() { } @Pointcut('@annotation(com.jichi.aop.sm4.EncryptMethod)') public void EncryptAOPCut() { } @Pointcut('@annotation(com.jichi.aop.sm4.DecryptMethod)') public void DecryptAOPCut() { } @Around('EncryptAOPCut()') public Object encryptMethodAop(ProceedingJoinPoint joinPoint) { Object responseObj = null; try { responseObj = joinPoint.proceed(); this.handleEncrypt(responseObj); //md5加密 String md5Data = Md5Utils.getMD5String(new Gson().toJson(responseObj)); SpringContextUtil.getHttpServletResponse().setHeader('md5',md5Data); } catch (Throwable throwable) { throwable.printStackTrace(); this.log.error('encryptMethodAop處理出現異常{}', throwable); } return responseObj; } @Around('DecryptAOPCut()') public Object decryptMethodAop(ProceedingJoinPoint joinPoint) { Object responseObj = null; try { responseObj = joinPoint.getArgs()[0]; //throw new RuntimeException('md5校驗失敗'); this.handleDecrypt(responseObj); String md5 = ''; md5 = Md5Utils.getMD5String(new Gson().toJson(responseObj)); System.out.println(md5); String origianlMd5 = ''; origianlMd5 = SpringContextUtil.getHttpServletRequest().getHeader('md5'); if(origianlMd5.equals(md5)){responseObj = joinPoint.proceed(); }else{this.log.error('參數的md5校驗不同,可能存在篡改行為,請檢查!');throw new Exception('參數的md5校驗不同,可能存在篡改行為,請檢查!'); } } catch (Throwable throwable) { throwable.printStackTrace(); this.log.error('decryptMethodAop處理出現異常{}', throwable); } return responseObj; } private void handleEncrypt(Object requestObj) throws Exception { if (!Objects.isNull(requestObj)) { Field[] fields = requestObj.getClass().getDeclaredFields(); Field[] fieldsCopy = fields; int fieldLength = fields.length; for(int i = 0; i < fieldLength; ++i) {Field field = fieldsCopy[i];boolean hasSecureField = field.isAnnotationPresent(EncryptField.class);if (hasSecureField) { field.setAccessible(true); String plaintextValue = (String)field.get(requestObj); String encryptValue = Sm4Utils.encryptEcb(DEFAULT_KEY, plaintextValue, ''); field.set(requestObj, encryptValue);} } } } private Object handleDecrypt(Object responseObj) throws Exception { if (Objects.isNull(responseObj)) { return null; } else { Field[] fields = responseObj.getClass().getDeclaredFields(); Field[] fieldsCopy = fields; int fieldLength = fields.length; for(int i = 0; i < fieldLength; ++i) {Field field = fieldsCopy[i];boolean hasSecureField = field.isAnnotationPresent(EncryptField.class);if (hasSecureField) { field.setAccessible(true); String encryptValue = (String)field.get(responseObj); String plaintextValue = Sm4Utils.decryptEcb(DEFAULT_KEY, encryptValue, ''); field.set(responseObj, plaintextValue);} } return responseObj; } }}代碼實際應用

首先我們可以定義一個實體類,對實體類的字段進行加密或解密的標識。我們這里建立了一個Info實體類,對于其中的name屬性,我們加了注解加密解密字段,對于sex屬性我們不做任何處理。

@Datapublic class Info { @EncryptField private String name; private String sex;}

然后我們對于controller方法打上加密的方法或解密的方法。

@RestController@RequestMapping('/demo/test')public class TestController { @PostMapping('/saveInfo') @DecryptMethod public HashMap<String,String> saveInfo(@RequestBody Info info) { HashMap<String,String> result = new HashMap<String,String>(); String name = info.getName(); System.out.println(name); String sex= info.getSex(); System.out.println(sex); result.put('flag','1'); result.put('msg','操作成功'); return result; }}

注意到方法上的注解@DecryptMethod,以為這著我們的這個方法將會進行解密。如果是@EncryptMethod,則代表對方法進行加密。

總結

到此為止,涉及到java后端的代碼解決方案已經完畢。示例代碼已經給出,大家可以直接使用,本人親測有效。文中難免有不足,歡迎大家批評指正。

以上就是java實現國產sm4加密算法的詳細內容,更多關于Java 國產sm4加密算法的資料請關注好吧啦網其它相關文章!

標簽: Java
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
在线视频精品| 亚洲精品日本| 欧美精品不卡| 午夜久久av| 日韩专区在线视频| 免费国产亚洲视频| 亚洲一区二区小说| 综合日韩在线| 日韩精品中文字幕一区二区| 蜜桃av一区二区三区电影| 爽好多水快深点欧美视频| 蜜桃传媒麻豆第一区在线观看| 一区二区自拍| 亚洲开心激情| 国产精品亚洲产品| 久久精品国产精品亚洲毛片| 国精品产品一区| 岛国av在线网站| 中文在线中文资源| 激情丁香综合| 综合激情视频| 国产精品任我爽爆在线播放| 久久精品人人| 久久精品免费一区二区三区 | 91亚洲一区| 久久精品观看| 亚洲一区有码| 国产福利资源一区| 亚洲欧洲国产精品一区| 亚洲精品一区二区在线看| 久久福利毛片| 亚洲一区二区三区无吗| 久久爱www成人| а√天堂8资源中文在线| 久久网站免费观看| 玖玖玖国产精品| 久久国内精品自在自线400部| 麻豆久久久久久| 久久国产免费| 亚洲欧美网站在线观看| 国产精品最新| 99精品美女| 日韩精品一级| 97精品国产福利一区二区三区| 亚洲激情中文| 国产日韩欧美一区二区三区在线观看| 麻豆高清免费国产一区| 欧美在线观看视频一区| 日韩三级一区| 国产亚洲一区二区手机在线观看 | 美女精品在线观看| 久久99影视| 丝袜美腿亚洲一区| 国产高清一区二区| 欧美黄色一区| 日韩电影二区| 国产中文字幕一区二区三区| 成人久久一区| 欧美日韩va| 激情自拍一区| 国产精品99精品一区二区三区∴| 欧美亚洲激情| 欧美国产精品| 国产精品普通话对白| 久久国产精品免费一区二区三区| 日韩理论片av| 欧美日韩夜夜| 婷婷精品进入| 久久精品一区| 亚洲18在线| 亚洲少妇在线| 黄在线观看免费网站ktv| 中文无码日韩欧| 日本韩国欧美超级黄在线观看| 欧美精品影院| 午夜久久99| 国内一区二区三区| 综合一区二区三区| 激情欧美亚洲| 中文在线а√天堂| 国产欧美激情| 婷婷精品视频| 在线日韩成人| 亚洲精品123区| 国产一区久久| 欧美激情视频一区二区三区免费 | 国产精品99一区二区三区| 亚洲区欧美区| 不卡中文字幕| 美女一区网站| 精品日产乱码久久久久久仙踪林| 亚洲影院天堂中文av色| 久久久久免费av| 色综合五月天| 久久中文字幕一区二区| 91福利精品在线观看| 免费看日韩精品| 香蕉精品视频在线观看| 成人日韩在线| 精品理论电影在线| 国产精品久久久久久久久久白浆 | 欧美日韩一区二区国产| 亚洲伊人精品酒店| 成人亚洲精品| 久久国产精品久久久久久电车 | 91成人精品| 欧美aa一级| 精品网站999| 国产精品任我爽爆在线播放| 欧美久久精品| 97久久中文字幕| 日韩一区二区三免费高清在线观看 | 日本中文字幕一区二区| 水蜜桃久久夜色精品一区的特点| 99pao成人国产永久免费视频| 国产一区二区三区精品在线观看| 久久av资源| 国产精品一级| 国产伦一区二区三区| 欧美三区不卡| 国产精品欧美一区二区三区不卡 | 国产精品亚洲欧美日韩一区在线| 欧美日韩a区| 日韩av资源网| 日本成人手机在线| 欧美日韩精品一区二区三区在线观看| 日韩激情一区二区| 国产乱人伦精品一区| 日本午夜精品| 国产精品亚洲综合久久| 欧美国产极品| 六月天综合网| 欧美日韩亚洲一区三区| jiujiure精品视频播放| 日韩av影院| 日韩在线麻豆| 欧美偷窥清纯综合图区| 国产美女亚洲精品7777| 久久免费精品| 日韩国产专区| 亚洲一区欧美激情| 亚洲a成人v| 久久精品97| 久久久久亚洲精品中文字幕| 欧美精品97| 久久国产毛片| 免费久久久久久久久| 99视频精品| 日韩精品免费视频一区二区三区| 国产精品magnet| 偷拍精品精品一区二区三区| 欧美在线影院| 日韩二区在线观看| 国产一区调教| 国产毛片久久| 欧美日韩国产一区二区在线观看| 日韩av片子| 免费日韩av片| 一区在线免费| 色一区二区三区| 久久亚洲国产精品一区二区| 三级欧美在线一区| 久久激情av| 久久在线91| 91成人福利| 国产91在线精品| 欧美特黄一级| 国产情侣一区在线| 日韩精品一区二区三区免费观影| 亚洲一区二区三区高清| 久久激情五月激情| 久久久久蜜桃| 日韩二区三区四区| 国产精品99一区二区三区| 日韩国产激情| 国产在线日韩| 久久精品99久久久| 久久国产成人午夜av影院宅| 亚洲综合色婷婷在线观看| 久久精品九色| 免播放器亚洲| 日韩成人a**站| 三级在线观看一区二区| 久久精品国产999大香线蕉| 亚洲大全视频| 国产精品香蕉| 国产精品视区| 日韩av有码| 日韩激情av在线| 欧美www视频在线观看| 免费观看在线综合| 日韩高清成人| 日韩一区二区三区免费视频| 亚洲精品.com| 欧美一区网站| av亚洲在线观看| 精品中文字幕一区二区三区 | 亚洲免费成人| 欧美国产视频| 欧美成人久久|