目录 前言 国密算法 SM1对称加密算法 SM1算法的基本原理 SM1算法的应用场景 SM1算法的优势 代码示例 SM2非对称加密算法 SM2算法的基本原理 SM2算法的应用场景 SM2算法的优势 代码示例 SM3杂凑算法 SM4分组密码算法 SM3、SM4工具类示例
前言
目前形式国内都在推行国产化,例如:国产化数据库,国产化服务器等。 我上家公司其中一条产品线是做电网项目的,其中加密的方式就要求使用国密加密算法,SM3和SM4,所以说国产化应该是一个趋势。 国密即国家密码局认定的国产密码算法。主要有SM1,SM2,SM3,SM4。密钥长度和分组长度均为128位。
国密算法
国密算法,全称为中国密码算法国家标准,是由中国国家密码管理局主导制定的一套密码算法标准。 国密算法包括以下四种: SM1对称加密算法 SM2非对称加密算法 SM3杂凑算法 SM4分组密码算法 国密算法在国家信息安全领域得到了广泛应用,被用于政务通信、金融支付、电子商务、云计算等领域。 其目的是为了保护国家信息安全和个人隐私,增强国内密码产品和系统的自主可控能力。
SM1对称加密算法
SM1对称加密算法是一种高效的分组密码算法,适用于对称加密和消息认证码,其安全性与国际上的AES算法相近。
SM1算法的基本原理
SM1算法是一种分组密码,采用对称密钥方式,将明文按照固定长度分组,然后对每个分组进行加密和解密。 该算法的关键在于密钥的生成和密钥的长度。 SM1算法的密钥长度为128位,密钥生成过程中采用了多种随机数生成器,保证了密钥的随机性和安全性。
SM1算法的应用场景
电子政务:SM1算法可以用于电子政务中的公文传输、公文存储和电子签章等场景,保证数据的机密性和完整性。 金融行业:SM1算法可以用于金融行业中的网上银行、移动支付和电子钱包等场景,保护用户的个人信息和资金安全。 医疗卫生:SM1算法可以用于医疗卫生中的电子病历、远程医疗和医疗数据存储等场景,确保医疗信息的机密性和完整性。 物联网:SM1算法可以用于物联网中的传感器网络、智能家居和智能交通等场景,保障物联网设备的通信安全和数据隐私。 云计算:SM1算法可以用于云计算中的数据加密、云存储和虚拟化等场景,保证云服务的安全性和可靠性。
SM1算法的优势
高安全性:SM1算法的密钥长度为128位,相比其他对称加密算法具有更高的安全性。此外,该算法的密钥生成过程中采用了多种随机数生成器,保证了密钥的随机性和安全性。 高效性:SM1算法的加解密速度较快,适用于大规模的数据加解密和安全通信同。时,该算法的软硬件实现成本较低,方便在各种设备上应用。 广泛适用性:SM1算法适用于各种不同的应用场景,包括电子政务、金融行业、医疗卫生、物联网和云计算等。该算法的应用范围广泛,可以满足不同领域的安全需求。 国家标准:SM1算法是中国的国家密码标准之一,被广泛应用于国家重要信息系统的数据加密和安全通信领域。该算法得到了国家的支持和认可,具有较高的可靠性和安全性。
代码示例
import javax. crypto. Cipher ;
import javax. crypto. spec. SecretKeySpec ;
import java. nio. charset. StandardCharsets ;
import java. util. Base64 ; public class AESUtil { private static final String ALGORITHM = "AES" ; private static final String TRANSFORMATION = "AES/ECB/PKCS5Padding" ; public static String encrypt ( String key, String value) throws Exception { SecretKeySpec secretKeySpec = new SecretKeySpec ( key. getBytes ( StandardCharsets . UTF_8 ) , ALGORITHM ) ; Cipher cipher = Cipher . getInstance ( TRANSFORMATION ) ; cipher. init ( Cipher . ENCRYPT_MODE , secretKeySpec) ; byte [ ] encrypted = cipher. doFinal ( value. getBytes ( StandardCharsets . UTF_8 ) ) ; return Base64 . getEncoder ( ) . encodeToString ( encrypted) ; } public static String decrypt ( String key, String encrypted) throws Exception { SecretKeySpec secretKeySpec = new SecretKeySpec ( key. getBytes ( StandardCharsets . UTF_8 ) , ALGORITHM ) ; Cipher cipher = Cipher . getInstance ( TRANSFORMATION ) ; cipher. init ( Cipher . DECRYPT_MODE , secretKeySpec) ; byte [ ] original = cipher. doFinal ( Base64 . getDecoder ( ) . decode ( encrypted) ) ; return new String ( original, StandardCharsets . UTF_8 ) ; } public static void main ( String [ ] args) throws Exception { String key = "your_16_byte_key_here_for_aes" ; String value = "Hello, World!" ; String encrypted = encrypt ( key, value) ; System . out. println ( "Encrypted: " + encrypted) ; String decrypted = decrypt ( key, encrypted) ; System . out. println ( "Decrypted: " + decrypted) ; }
}
SM2非对称加密算法
SM2非对称加密算法是基于椭圆曲线密码体制的数字签名算法和密钥交换协议,安全性较高。
SM2算法的基本原理
SM2使用非对称密钥加密体制,包括公钥和私钥。 公钥用于加密数据和验证数字签名,私钥用于解密数据和生成数字签名。
SM2算法的应用场景
数据加密: SM2算法可用于加密和解密数据,保障数据传输的安全性。它利用公钥进行加密,私钥进行解密,确保数据在传输过程中的机密性。 在网络安全领域,SM2算法常被用于保护敏感信息的传输,如电子邮件加密、文件传输加密等。 数字签名: SM2算法可用于生成数字签名,验证文档或数据的完整性和真实性。通过私钥对消息进行签名,利用公钥进行验证,确保数据在传输过程中未被篡改,并验证发送方的身份。 数字签名在电子认证、电子合同、电子票据等领域具有广泛应用,如网上银行交易、电子政务等。 身份认证: SM2算法可用于身份认证,验证用户的身份信息。通过公钥和私钥的配对使用,可以确保用户身份的真实性和可信度。 在网络安全领域,SM2算法常被用于用户登录、权限管理等场景,保障系统的安全性和可信度。 密钥交换: SM2算法支持密钥交换功能,通过公钥和私钥的配对使用,可以安全地协商出共享密钥,用于后续的对称加密通信。 密钥交换在网络安全通信中具有重要意义,可以确保通信双方之间密钥的安全传输和共享。 国家安全领域: 作为中国国家密码管理局颁布的国家标准,SM2算法在中国国内得到广泛应用,特别是在政府机构和企业的信息安全领域。 它符合国家密码管理政策,有利于保障国家信息安全,防止外部攻击和数据泄露。 国际认可: 虽然SM2是中国的国家标准,但它在一定程度上也获得了国际认可。部分国际组织和标准化机构也开始考虑将其作为一种可选的加密算法。
SM2算法的优势
安全性高: SM2算法基于椭圆曲线离散对数难题,这一数学问题的复杂性保证了算法的安全性。 与RSA算法相比,SM2算法在同等安全水平下,所需的密钥长度和签名长度更短,从而降低了被破解的风险。 SM2算法被认为在经典计算机和量子计算机的攻击下都是安全的。 效率高: SM2算法具有较高的运算效率,特别是在加密、解密和数字签名方面,性能优于RSA算法。 它适合高并发场景,满足大量数据加密、解密和数字签名的需求。 SM2算法的CPU占用少、内容使用少、网络消耗低,特别适用于移动设备和资源受限的环境。 灵活性好: SM2算法支持多种密钥长度,可以根据实际需求灵活选择密钥长度,适用于不同的应用场景。 自主创新: 它符合国家密码管理政策,有利于保障国家关键信息系统的信息安全。 技术特点: SM2算法基于椭圆曲线密码学,具备ECC算法的性能特点并实现优化改进。 它采用了一系列安全性增强措施,如密钥派生函数和随机数生成算法,以防止各种攻击。
代码示例
依赖
< dependency> < groupId> org.bouncycastle</ groupId> < artifactId> bcprov-jdk15on</ artifactId> < version> 最新版本</ version>
</ dependency>
代码
import org. bouncycastle. crypto. CipherParameters ;
import org. bouncycastle. crypto. engines. SM2Engine ;
import org. bouncycastle. crypto. params. ECPublicKeyParameters ;
import org. bouncycastle. crypto. params. ECPrivateKeyParameters ;
import org. bouncycastle. crypto. params. SM2PrivateKeyParameters ;
import org. bouncycastle. crypto. params. SM2PublicKeyParameters ;
import org. bouncycastle. jce. ECNamedCurveGenParameterSpec ;
import org. bouncycastle. jce. ECNamedCurveTable ;
import org. bouncycastle. jce. provider. BouncyCastleProvider ;
import org. bouncycastle. jce. spec. ECParameterSpec ; import java. security. KeyPair ;
import java. security. KeyPairGenerator ;
import java. security. PrivateKey ;
import java. security. PublicKey ;
import java. security. Security ; public class SM2Utils { static { Security . addProvider ( new BouncyCastleProvider ( ) ) ; } public static KeyPair generateKeyPair ( ) throws Exception { KeyPairGenerator keyGen = KeyPairGenerator . getInstance ( "EC" , "BC" ) ; ECParameterSpec ecSpec = ECNamedCurveTable . getParameterSpec ( "sm2p256v1" ) ; keyGen. initialize ( new ECNamedCurveGenParameterSpec ( "sm2p256v1" ) , new java. security. SecureRandom( ) ) ; return keyGen. generateKeyPair ( ) ; } public static byte [ ] encrypt ( PublicKey publicKey, byte [ ] data) throws Exception { return null ; } public static byte [ ] decrypt ( PrivateKey privateKey, byte [ ] cipherText) throws Exception { return null ; } public static byte [ ] sign ( PrivateKey privateKey, byte [ ] data) throws Exception { return null ; } public static boolean verify ( PublicKey publicKey, byte [ ] data, byte [ ] signature) throws Exception { return false ; }
}
SM3杂凑算法
SM3 消息摘要。可以用MD5作为对比理解。该算法已公开。校验结果为256位。 SM3杂凑算法是一种散列算法,用于将输入的数据转化为固定长度的摘要,具有抗碰撞、抗第二原像和抗预像等特性。 SM3杂凑算法是我国自主设计的密码杂凑算法,适用于商用密码应用中的数字签名和验证消息认证码的生成与验证以及随机数的生成,可满足多种密码应用的安全需求。 为了保证杂凑算法的安全性,其产生的杂凑值的长度不应太短,例如MD5输出128比特杂凑值,输出长度太短,影响其安全性SHA-1算法的输出长度为160比特,SM3算法的输出长度为256比特,因此SM3算法的安全性要高于MD5算法和SHA-1算法。
SM4分组密码算法
SM4 无线局域网标准的分组数据算法。对称加密,密钥长度和分组长度均为128位。 SM4分组密码算法是我国自主设计的分组对称密码算法,用于实现数据的加密/解密运算,以保证数据和信息的机密性。 要保证一个对称密码算法的安全性的基本条件是其具备足够的密钥长度,SM4算法与AES算法具有相同的密钥长度分组长度128比特,因此在安全性上高于3DES算法。
SM3、SM4工具类示例
依赖
< dependency> < groupId> org.bouncycastle</ groupId> < artifactId> bcprov-jdk15to18</ artifactId> < version> 1.77</ version>
</ dependency>
SM3工具类
package com. mkj. publicservice. utils. smalgorithm ; import org. bouncycastle. crypto. digests. SM3Digest ;
import org. bouncycastle. crypto. macs. HMac ;
import org. bouncycastle. crypto. params. KeyParameter ;
import org. bouncycastle. pqc. math. linearalgebra. ByteUtils ; import java. io. UnsupportedEncodingException ;
public class Sm3Util { public static String Sm3EncryptText ( String content) throws UnsupportedEncodingException { byte [ ] bytes = content. getBytes ( ) ; byte [ ] hash = hash ( bytes) ; String sm3 = ByteUtils . toHexString ( hash) ; System . out. println ( "[Sm3EncryptText]sm3 hex:" + sm3) ; return sm3; } public static byte [ ] hash ( byte [ ] srcData) { SM3Digest digest= new SM3Digest ( ) ; digest. update ( srcData, 0 , srcData. length) ; byte [ ] bytes = new byte [ digest. getDigestSize ( ) ] ; digest. doFinal ( bytes, 0 ) ; return bytes; } public static String encryptByKey ( String keyText, String plainText) { return ByteUtils . toHexString ( encryptByKey ( keyText. getBytes ( ) , plainText. getBytes ( ) ) ) ; } public static byte [ ] encryptByKey ( byte [ ] keyByte, byte [ ] plainByte) { KeyParameter keyParameter = new KeyParameter ( keyByte) ; SM3Digest sm3Digest = new SM3Digest ( ) ; HMac hMac = new HMac ( sm3Digest) ; hMac. init ( keyParameter) ; hMac. update ( plainByte, 0 , plainByte. length) ; byte [ ] result = new byte [ hMac. getMacSize ( ) ] ; hMac. doFinal ( result, 0 ) ; return result; } public static void main ( String [ ] args) throws UnsupportedEncodingException { Sm3EncryptText ( "ceshi001" ) ; System . out. println ( encryptByKey ( "key001" , "abc" ) ) ; } }
SM4工具类
SM4两种算法,基于ECB和CBC。示例中key都使用了16进制的字符串,有的项目没有需求可以自行去除。看实际情况。
CBC
package com. mkj. publicservice. utils. smalgorithm ; import org. bouncycastle. jce. provider. BouncyCastleProvider ;
import org. bouncycastle. pqc. math. linearalgebra. ByteUtils ;
import javax. crypto. Cipher ;
import javax. crypto. KeyGenerator ;
import javax. crypto. spec. IvParameterSpec ;
import javax. crypto. spec. SecretKeySpec ;
import java. security. AlgorithmParameters ;
import java. security. Key ;
import java. security. SecureRandom ;
import java. security. Security ;
import java. util. Arrays ;
public class Sm4CbcUtils { static { Security . addProvider ( new BouncyCastleProvider ( ) ) ; } private static final String ENCODING = "UTF-8" ; public static final String ALGORITHM_NAME = "SM4" ; public static final String ALGORITHM_NAME_CBC_PADDING = "SM4/CBC/PKCS5Padding" ; public static final int DEFAULT_KEY_SIZE = 128 ; public static byte [ ] generateKey ( ) throws Exception { return generateKey ( DEFAULT_KEY_SIZE ) ; } public static String generateKeyString ( ) throws Exception { return ByteUtils . toHexString ( generateKey ( ) ) ; } public static byte [ ] generateKey ( int keySize) throws Exception { KeyGenerator kg = KeyGenerator . getInstance ( ALGORITHM_NAME , BouncyCastleProvider . PROVIDER_NAME ) ; kg. init ( keySize, new SecureRandom ( ) ) ; return kg. generateKey ( ) . getEncoded ( ) ; } public static String encrypt ( String hexKey, String paramStr) throws Exception { String result = "" ; byte [ ] keyData = ByteUtils . fromHexString ( hexKey) ; byte [ ] srcData = paramStr. getBytes ( ENCODING ) ; byte [ ] cipherArray = encryptCbcPadding ( keyData, srcData) ; result = ByteUtils . toHexString ( cipherArray) ; return result; } public static byte [ ] encryptCbcPadding ( byte [ ] key, byte [ ] data) throws Exception { Cipher cipher = generateCbcCipher ( ALGORITHM_NAME_CBC_PADDING , Cipher . ENCRYPT_MODE , key) ; return cipher. doFinal ( data) ; } private static Cipher generateCbcCipher ( String algorithmName, int mode, byte [ ] key) throws Exception { Cipher cipher = Cipher . getInstance ( algorithmName, BouncyCastleProvider . PROVIDER_NAME ) ; Key sm4Key = new SecretKeySpec ( key, ALGORITHM_NAME ) ; cipher. init ( mode, sm4Key, generateIV ( ) ) ; return cipher; } public static AlgorithmParameters generateIV ( ) throws Exception { byte [ ] iv = new byte [ 16 ] ; Arrays . fill ( iv, ( byte ) 0x00 ) ; AlgorithmParameters params = AlgorithmParameters . getInstance ( ALGORITHM_NAME ) ; params. init ( new IvParameterSpec ( iv) ) ; return params; } public static String decrypt ( String hexKey, String text) throws Exception { String result = "" ; byte [ ] keyData = ByteUtils . fromHexString ( hexKey) ; byte [ ] resultData = ByteUtils . fromHexString ( text) ; byte [ ] srcData = decryptCbcPadding ( keyData, resultData) ; result = new String ( srcData, ENCODING ) ; return result; } public static byte [ ] decryptCbcPadding ( byte [ ] key, byte [ ] cipherText) throws Exception { Cipher cipher = generateCbcCipher ( ALGORITHM_NAME_CBC_PADDING , Cipher . DECRYPT_MODE , key) ; return cipher. doFinal ( cipherText) ; } public static void main ( String [ ] args) throws Exception { String str = "Hello, world" ; System . out. println ( "==========生成密钥==========" ) ; String generateKey = generateKeyString ( ) ; System . out. println ( generateKey) ; System . out. println ( "==========加密==========" ) ; String encrypt = encrypt ( generateKey, str) ; System . out. println ( encrypt) ; System . out. println ( "==========解密==========" ) ; String decrypt = decrypt ( generateKey, encrypt) ; System . out. println ( decrypt) ; }
}
ECB
package com. mkj. publicservice. utils. smalgorithm ; import cn. hutool. crypto. SmUtil ;
import cn. hutool. crypto. symmetric. SM4 ;
import org. bouncycastle. jce. provider. BouncyCastleProvider ;
import org. bouncycastle. pqc. math. linearalgebra. ByteUtils ;
import org. bouncycastle. util. encoders. Hex ; import javax. crypto. Cipher ;
import javax. crypto. KeyGenerator ;
import javax. crypto. spec. SecretKeySpec ;
import java. nio. charset. StandardCharsets ;
import java. security. Key ;
import java. security. SecureRandom ;
import java. security. Security ;
import java. util. Arrays ;
public class Sm4EcbUtils { static { Security . addProvider ( new BouncyCastleProvider ( ) ) ; } private static final String ENCODING = "UTF-8" ; public static final String ALGORITHM_NAME = "SM4" ; public static final String ALGORITHM_NAME_ECB_PADDING = "SM4/ECB/PKCS5Padding" ; public static final int DEFAULT_KEY_SIZE = 128 ; public static String generateKey ( ) throws Exception { return new String ( Hex . encode ( generateKey ( DEFAULT_KEY_SIZE ) ) ) ; } public static byte [ ] generateKey ( int keySize) throws Exception { KeyGenerator kg = KeyGenerator . getInstance ( ALGORITHM_NAME , BouncyCastleProvider . PROVIDER_NAME ) ; kg. init ( keySize, new SecureRandom ( ) ) ; return kg. generateKey ( ) . getEncoded ( ) ; } 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, ALGORITHM_NAME ) ; cipher. init ( mode, sm4Key) ; return cipher; } public static String encryptEcb ( String hexKey, String paramStr) { try { String cipherText = "" ; byte [ ] keyData = ByteUtils . fromHexString ( hexKey) ; byte [ ] srcData = paramStr. getBytes ( ENCODING ) ; byte [ ] cipherArray = encryptEcbPadding ( keyData, srcData) ; cipherText = ByteUtils . toHexString ( cipherArray) ; return cipherText; } catch ( Exception e) { return paramStr; } } public static byte [ ] encryptEcbPadding ( byte [ ] key, byte [ ] data) throws Exception { Cipher cipher = generateEcbCipher ( ALGORITHM_NAME_ECB_PADDING , Cipher . ENCRYPT_MODE , key) ; return cipher. doFinal ( data) ; } public static String decryptEcb ( String hexKey, String cipherText) { String decryptStr = "" ; byte [ ] keyData = ByteUtils . fromHexString ( hexKey) ; byte [ ] cipherData = ByteUtils . fromHexString ( cipherText) ; byte [ ] srcData = new byte [ 0 ] ; try { srcData = decryptEcbPadding ( keyData, cipherData) ; decryptStr = new String ( srcData, ENCODING ) ; } catch ( Exception e) { e. printStackTrace ( ) ; } return decryptStr; } public static byte [ ] decryptEcbPadding ( byte [ ] key, byte [ ] cipherText) throws Exception { Cipher cipher = generateEcbCipher ( ALGORITHM_NAME_ECB_PADDING , Cipher . DECRYPT_MODE , key) ; return cipher. doFinal ( cipherText) ; } 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 = decryptEcbPadding ( keyData, cipherData) ; byte [ ] srcData = paramStr. getBytes ( ENCODING ) ; flag = Arrays . equals ( decryptData, srcData) ; return flag; } public static void main ( String [ ] args) { try { String paramStr = "Hello, world" ; System . out. println ( "==========加密前源数据==========" ) ; System . out. println ( paramStr) ; String key = generateKey ( ) ; System . out. println ( "==========生成key==========" ) ; System . out. println ( key) ; String cipher = encryptEcb ( key, paramStr) ; System . out. println ( "==========加密串==========" ) ; System . out. println ( cipher) ; System . out. println ( "==========是否为同一数据==========" ) ; System . out. println ( verifyEcb ( key, cipher, paramStr) ) ; paramStr = decryptEcb ( key, cipher) ; System . out. println ( "==========解密后数据==========" ) ; System . out. println ( paramStr) ; } catch ( Exception e) { e. printStackTrace ( ) ; } }
}