国密算法的实现借助了Java库函数 Bouncy Castle,加密库安装使用教程请参考链接 SM4 简介 SM4,又称为商密算法,是一种分组密码算法,于2012年由中国密码技术研究中心(中国密码学会成员)发布,目前已成为我国国家密码算法,
国密算法的实现借助了Java库函数 Bouncy Castle,加密库安装使用教程请参考链接
SM4,又称为商密算法,是一种分组密码算法,于2012年由中国密码技术研究中心(中国密码学会成员)发布,目前已成为我国国家密码算法,并在多个领域得到了广泛的应用。SM4算法采用了32轮迭代结构,密钥长度为128位,分组长度为128位,支持ECB、CBC等多种分组模式,在安全性、效率和适用性上都得到了良好的平衡。SM4算法具有高速度、高安全性、硬件实现简单等特点,可以在多种安全场景中使用,比如对称加密、消息认证码等方面。同时,SM4算法已经经过了严格的国际标准测试,成为ISO/IEC 18033-4标准。
注意:代码加解密对象为文件,测试时请自行替换
import javax.crypto.Cipher;import javax.crypto.spec.IvParameterSpec;import javax.crypto.spec.SecreTKEySpec;import java.NIO.file.Files;import java.nio.file.Paths;import java.nio.charset.StandardCharsets;import java.security.Security;import org.bouncycastle.jce.provider.BouncyCastleProvider;public class SM4 { private static final String name="SM4"; //算法名字 private static final String transfORMation="SM4/CBC/PKCS5Padding"; //加密模式以及短快填充方式 private static final String Default_iv="0123456789abcdef"; //加密使用的初始向量private static void encodeFile(String inputFile, String outputFile, String key) throws Exception { // 读取输入文件中的所有字节 byte [] inputBytes = Files.readAllBytes(Paths.get(inputFile)); // 对输入字节数组进行加密 byte [] encodeByte = encode(inputBytes, key.getBytes(StandardCharsets.UTF_8)); // 将加密后的字节数组写入指定输出文件中 Files.write(Paths.get(outputFile),encodeByte); System.out.println("File encoded successfully.");} public static byte [] encode(byte [] inputByte, byte [] key) throws Exception { // 获取加密实例 Cipher c = Cipher.getInstance(transformation); // 根据密钥的字节数组创建 SecretKeySpec SecretKeySpec secretKeySpec = new SecretKeySpec(key, name); // 创建 IvParameterSpec 对象,使用默认向量和字符集 IvParameterSpec ivParameterSpec = new IvParameterSpec(Default_iv.getBytes(StandardCharsets.UTF_8)); // 初始化加密实例 c.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec); // 返回加密后的字节数组 return c.doFinal(inputByte); } public static void decodeFile(String inputFilePath, String outputFilePath, String key) throws Exception { byte[] inputBytes = Files.readAllBytes(Paths.get(inputFilePath)); byte[] decodeBytes = decode(inputBytes, key.getBytes(StandardCharsets.UTF_8)); Files.write(Paths.get(outputFilePath), decodeBytes); System.out.println("File decode successfully."); } private static byte[] decode(byte[] inputBytes, byte[] key) throws Exception { Cipher cipher = Cipher.getInstance(transformation); SecretKeySpec secretKeySpec = new SecretKeySpec(key, name); IvParameterSpec ivParameterSpec = new IvParameterSpec(Default_iv.getBytes(StandardCharsets.UTF_8)); cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec); return cipher.doFinal(inputBytes); } public static void main(String[] args) throws Exception { Security.addProvider(new BouncyCastleProvider()); String inputFile="Test.txt"; //需要加密的文件 String enFile="Encode.txt"; //加密后的文件 String deFile="Decode.txt"; //解密后的文件 String key="0123456789ABCDEF"; //加密密钥,注意必须是128bits,即16个字节 encodeFile(inputFile,enFile,key); decodeFile(enFile,deFile,key); }}
SM3是一种国家密码算法,也称为商用密码算法,是我国的一种哈希函数,用于信息安全领域。它基于Merkle–Damgård结构,采用了与SHA-256类似的位操作,并且设计了一个可调节的消息扰动函数。SM3保证了生日攻击下的安全强度,并提供了碰撞和预图攻击的防护。
import org.bouncycastle.crypto.digests.SM3Digest;import org.bouncycastle.util.encoders.Hex;import java.io.IOException;import java.nio.file.Files;import java.nio.file.Paths;public class SM3Test { private static byte[] calculateSM3Digest( byte [] inputBytes) { //创建 SM3Digest 对象 SM3Digest digest = new SM3Digest(); //将输入字符串转为字节数组,并使用该字节数组更新摘要对象的内部状态,以便进行计算 // byte[] inputBytes = input.getBytes(); digest.update(inputBytes, 0, inputBytes.length); //创建一个输出字节数组,调用 doFinal 方法完成哈希计算,并将结果存入输出数组 byte[] output = new byte[digest.getDigestSize()]; digest.doFinal(output, 0); //返回摘要字节数组 return output; } public static void main(String[] args) { String filePath = "src/Test.java"; try { byte [] inputBytes = Files.readAllBytes(Paths.get(filePath)); byte[] digest = calculateSM3Digest(inputBytes); String hexDigest = Hex.toHexString(digest); System.out.println("SM3 Digest: " + hexDigest); } catch (IOException e) { System.out.println("An error occurred while reading the file: " + e.getMessage()); } } }
SM2是一种我国的国家密码算法,采用基于椭圆曲线密码学的公钥密码体制,在数字签名、密钥协商、密钥交换和公钥加密场景中可广泛使用。其密钥长度为256位,安全等级高于普遍采用的RSA或DSA算法。在SM2算法中,密钥交换、数字签名和公钥加密均采用同一种椭圆曲线和同一种哈希算法,具有自主知识产权、高效率和安全性高等特点。并且SM2算法已经成为国际标准ISO/IEC 14888-3并得到了广泛应用。
public class SM2 { public SM2(){ } static { //加载BC驱动 if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) new BouncyCastleProvider(); } // 生成sm2密钥对 public KeyPair createECKeyPair() { //使用标准名称创建EC参数生成的参数规范 final ECGenParameterSpec sm2Spec = new ECGenParameterSpec("sm2p256v1"); // 获取一个椭圆曲线类型的密钥对生成器 final KeyPairGenerator kpg; try { kpg = KeyPairGenerator.getInstance("EC", new BouncyCastleProvider());// 使用SM2算法域参数集初始化密钥生成器(默认使用最高优先级安装的提供者的 SecureRandom 的实现作为随机源) // kpg.initialize(sm2Spec); // 使用SM2的算法域参数集和指定的随机源初始化密钥生成器 kpg.initialize(sm2Spec, new SecureRandom()); // 通过密钥生成器生成密钥对 return kpg.generateKeyPair(); } catch (Exception e) { e.printStackTrace(); return null; } } public byte[] encode(String publicKeyHex, byte[] inputBytes, int modeType){ //加密模式 // BCECPublicKey publicKey = getECPublicKeyByPublicKeyHex(publicKeyHex); SM2Engine.Mode mode; if (modeType == 1) {//采用新模式加密标准 mode = SM2Engine.Mode.C1C3C2; } else {//采用旧模式加密标准 mode = SM2Engine.Mode.C1C2C3; } //通过公钥对象获取公钥的基本域参数。 ECParameterSpec ecParameterSpec = publicKey.getParameters(); ECDomainParameters ecDomainParameters = new ECDomainParameters(ecParameterSpec.getCurve(), ecParameterSpec.getG(), ecParameterSpec.getN()); //通过公钥值和公钥基本参数创建公钥参数对象 ECPublicKeyParameters ecPublicKeyParameters = new ECPublicKeyParameters(publicKey.getQ(), ecDomainParameters); //根据加密模式实例化SM2公钥加密引擎 SM2Engine sm2Engine = new SM2Engine(mode); //初始化加密引擎 sm2Engine.init(true, new ParametersWithRandom(ecPublicKeyParameters, new SecureRandom())); byte[] arrayOfBytes = null; try { //通过加密引擎对字节数串行加密 arrayOfBytes = sm2Engine.processBlock(inputBytes, 0, inputBytes.length); } catch (Exception e) { System.out.println("SM2加密时出现异常:" + e.getMessage()); e.printStackTrace(); } return arrayOfBytes; } public static byte[] decode(String privateKeyHex, byte[] cipherBytes, int modeType) { //解密模式 SM2Engine.Mode mode; BCECPrivateKey privateKey = getBCECPrivateKeyByPrivateKeyHex(privateKeyHex); if (modeType == 1) { mode = SM2Engine.Mode.C1C3C2; } else { mode = SM2Engine.Mode.C1C2C3; } //通过私钥对象获取私钥的基本域参数。 ECParameterSpec ecParameterSpec = privateKey.getParameters(); ECDomainParameters ecDomainParameters = new ECDomainParameters(ecParameterSpec.getCurve(), ecParameterSpec.getG(), ecParameterSpec.getN()); //通过私钥值和私钥基本参数创建私钥参数对象 ECPrivateKeyParameters ecPrivateKeyParameters = new ECPrivateKeyParameters(privateKey.getD(), ecDomainParameters); //通过解密模式创建解密引擎并初始化 SM2Engine sm2Engine = new SM2Engine(SM2Engine.Mode.C1C3C2); sm2Engine.init(false, ecPrivateKeyParameters); byte[] arrayOfBytes = null; try { //通过解密引擎对密文字节串进行解密 arrayOfBytes = sm2Engine.processBlock(cipherBytes, 0, cipherBytes.length); } catch (Exception e) { System.out.println("SM2解密时出现异常" + e.getMessage()); } return arrayOfBytes; } //椭圆曲线ECParameters ASN.1 结构 private static X9ECParameters x9ECParameters = GMNamedCurves.getByName("sm2p256v1"); //椭圆曲线公钥或私钥的基本域参数。 private static ECParameterSpec ecDomainParameters = new ECParameterSpec(x9ECParameters.getCurve(), x9ECParameters.getG(), x9ECParameters.getN()); public static BCECPublicKey getECPublicKeyByPublicKeyHex(String pubKeyHex) { //截取64字节有效的SM2公钥(如果公钥首字节为0x04) if (pubKeyHex.length() > 128) { pubKeyHex = pubKeyHex.substring(pubKeyHex.length() - 128); } //将公钥拆分为x,y分量(各32字节) String stringX = pubKeyHex.substring(0, 64); String stringY = pubKeyHex.substring(stringX.length()); //将公钥x、y分量转换为BigInteger类型 BigInteger x = new BigInteger(stringX, 16); BigInteger y = new BigInteger(stringY, 16); //通过公钥x、y分量创建椭圆曲线公钥规范 ECPublicKeySpec ecPublicKeySpec = new ECPublicKeySpec(x9ECParameters.getCurve().createPoint(x, y), ecDomainParameters); //通过椭圆曲线公钥规范,创建出椭圆曲线公钥对象(可用于SM2加密及验签) return new BCECPublicKey("EC", ecPublicKeySpec, BouncyCastleProvider.CONFIGURATION); } public static BCECPrivateKey getBCECPrivateKeyByPrivateKeyHex(String privateKeyHex) { //将十六进制私钥字符串转换为BigInteger对象 BigInteger d = new BigInteger(privateKeyHex, 16); //通过私钥和私钥域参数集创建椭圆曲线私钥规范 ECPrivateKeySpec ecPrivateKeySpec = new ECPrivateKeySpec(d, ecDomainParameters); //通过椭圆曲线私钥规范,创建出椭圆曲线私钥对象(可用于SM2解密和签名) return new BCECPrivateKey("EC", ecPrivateKeySpec, BouncyCastleProvider.CONFIGURATION); } public static void main(String[] args) throws Exception { String Sm4Key="0123456789abcdef"; String sm2PublicKeyHex=null; String sm2PrivateKeyHex=null; SM2 sm2=new SM2(); // 生成SM2密钥 KeyPair keyPair = sm2.createECKeyPair(); PrivateKey privateKey = keyPair.getPrivate(); PublicKey publicKey = keyPair.getPublic(); if (publicKey instanceof BCECPublicKey){ //获取65字节非压缩的十六进制公钥串(0x04) byte[] publicKeyBytes = ((BCECPublicKey) publicKey).getQ().getEncoded(false); sm2PublicKeyHex = Hex.toHexString(publicKeyBytes); } if (privateKey instanceof BCECPrivateKey) { //获取32字节十六进制私钥串 sm2PrivateKeyHex = ((BCECPrivateKey) privateKey).getD().toString(16); } //Sm2加密密钥 byte [] keyBytes=Sm4Key.getBytes("utf-8"); byte[] encodeBytes = sm2.encode(sm2PublicKeyHex, keyBytes, 1); String encodeKey = Hex.toHexString(encodeBytes); //Sm2解密密钥 byte [] decodeBytes=sm2.decode(sm2PrivateKeyHex,encodeBytes,1); String deKey=new String(decodeBytes,"utf-8"); System.out.println("\ninitial key:"+Sm4Key+"\nencode key:"+encodeKey+"\ndecode key:"+deKey); System.out.println("complete!"); }}
--结束END--
本文标题: 使用 Java Bouncy Castle实现国密算法SM4、SM3以及SM2的加密
本文链接: https://lsjlt.com/news/374049.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
2024-04-01
2024-04-03
2024-04-03
2024-01-21
2024-01-21
2024-01-21
2024-01-21
2023-12-23
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0