Bouncy Castle :国密加密在.NET Core中的实践

一、简介

Bouncy Castle 是一个开源的密码学库, 提供了丰富的加密算法实现,包括常见的对称加密算法(如 AES)、非对称加密算法(如 RSA、ECC)、哈希算法(如 SHA-256)以及数字签名算法(如 ECDSA)

二、安装

第一步,老规矩, NuGet 包 安装。

Install-Package BouncyCastle.Cryptography

三、国密算法实现

Aes:加密解密

using BouncyCastleDemo;

string plaintext = "Hello, BouncyCastle!";

byte[] ciphertext = Util.EncryptAES(plaintext, aesKey, aesIV);
string decryptedText = Util.DecryptAES(ciphertext, aesKey, aesIV);

Console.WriteLine($"Plaintext: {plaintext}");
Console.WriteLine($"Ciphertext: {Convert.ToBase64String(ciphertext)}");
Console.WriteLine($"Decrypted Text: {decryptedText}");

using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Security;
using System.Text;

public static byte[] EncryptAES(string plaintext, byte[] key, byte[] iv)
{

    IBufferedCipher cipher = CipherUtilities.GetCipher("AES/CBC/PKCS7Padding");
    cipher.Init(true, new ParametersWithIV(new KeyParameter(key), iv));
    return cipher.DoFinal(Encoding.UTF8.GetBytes(plaintext));
}

public static string DecryptAES(byte[] ciphertext, byte[] key, byte[] iv)
{
    IBufferedCipher cipher = CipherUtilities.GetCipher("AES/CBC/PKCS7Padding");
    cipher.Init(false, new ParametersWithIV(new KeyParameter(key), iv));
    byte[] plaintext = cipher.DoFinal(ciphertext);
    return Encoding.UTF8.GetString(plaintext);
}

输出:
Plaintext: Hello, BouncyCastle!
Ciphertext: fNI2IszsUCTvMzU2kbLMZ4BVLNM4kkFrmMfMiJFkS44=
Decrypted Text: Hello, BouncyCastle!

SM2:非对称加密与签名

SM2 是一种基于椭圆曲线密码学的非对称加密算法,常用于数字签名和密钥交换。

using BouncyCastleDemo;
using Org.BouncyCastle.Asn1.GM;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;

var keyPair = Util.GenerateSm2KeyPair();
var privateKey = (ECPrivateKeyParameters)keyPair.Private;
var publicKey = (ECPublicKeyParameters)keyPair.Public;

Console.WriteLine($"Private Key: {privateKey.D}");
Console.WriteLine($"Public Key X: {publicKey.Q.XCoord}");
Console.WriteLine($"Public Key Y: {publicKey.Q.YCoord}");

public static AsymmetricCipherKeyPair GenerateSm2KeyPair()
{
    // 获取 SM2 椭圆曲线参数
    var ecParams = GMNamedCurves.GetByName("sm2p256v1");
    var domainParams = new ECDomainParameters(ecParams.Curve, ecParams.G, ecParams.N, ecParams.H);

    // 初始化密钥生成器
    var keyGen = new ECKeyPairGenerator("EC"); // 使用 "EC" 作为算法名称
    var keyGenParams = new ECKeyGenerationParameters(domainParams, new SecureRandom());
    keyGen.Init(keyGenParams);

    // 生成密钥对
    return keyGen.GenerateKeyPair();
}

输出:
Private Key: 52304744741195071390077799369490193481967288198229563887116583397880577348854
Public Key X: 7a981aa814b13b6494ccfa2b500188b8c3ce06de13e56abca21aae71c9b48b1e
Public Key Y: 24d19e15ba945cf31b8b26321ed5c1ecff88480103a43f447f98cf7efe596c36

SM3:哈希算法

SM3 是一种密码哈希算法,类似于 SHA-256,但具有更高的安全性。

using BouncyCastleDemo;
using Org.BouncyCastle.Crypto.Digests;

string input = "Hello, SM3!";
byte[] data = System.Text.Encoding.UTF8.GetBytes(input);
// 计算SM3哈希
byte[] hash = Util.CalculateSM3Hash(data);
Console.WriteLine("SM3 Hash: " + BitConverter.ToString(hash).Replace("-", "").ToLower());

public static byte[] CalculateSM3Hash(byte[] data)
{
    // 创建SM3摘要对象
    var sm3Digest = new SM3Digest();
    // 更新数据
    sm3Digest.BlockUpdate(data, 0, data.Length);
    // 获取摘要结果
    byte[] hash = newbyte[sm3Digest.GetDigestSize()];
    sm3Digest.DoFinal(hash, 0);

    return hash;
}

输出:LSM3 Hash: 21b937fed61e685b8ac08c67fe9a3300437f2ca44547dea06e0cfe30219fdc4c

SM4:对称加密

SM4 是中国国家密码管理局发布的对称分组加密算法,也称为 SMS4。它是一种分组密码算法,采用 128 位的分组长度和 128 位的密钥长度,通过 32 轮非线性迭代实现加密和解密。

SM4 工作模式 SM4 支持多种工作模式,适用于不同的应用场景:ECB(电子密码本模式):独立加密每个数据块,相同的明文块产生相同的密文块。适用于加密大量重复数据块,但安全性较低。CBC(密码块链接模式):使用前一个块的密文与当前块的明文进行 XOR 操作后再加密。适用于需要较高安全性的场合,如文件加密和网络通信。CFB(密码反馈模式):将加密算法当作流密码使用,适用于加密字节流或实时数据传输。OFB(输出反馈模式):生成密钥流与明文进行 XOR 操作,适用于加密大量数据。CTR(计数器模式):使用递增的计数器与密钥一起加密固定值,然后与明文进行 XOR 操作。适用于大数据量的加密,具有高安全性和高效率。

using BouncyCastleDemo;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Modes;
using Org.BouncyCastle.Crypto.Paddings;
using Org.BouncyCastle.Crypto.Parameters;
using System.Text;

string plainText = "Hello, SM4!";
byte[] key = Encoding.UTF8.GetBytes("0123456789abcdef"); // 16 字节密钥
byte[] iv = Encoding.UTF8.GetBytes("0123456789abcdef"); // 16 字节 IV
byte[] plainBytes = Encoding.UTF8.GetBytes(plainText);

// 加密
byte[] encrypted = SM4Example.SM4Encrypt(plainBytes, key, iv);
Console.WriteLine("加密结果(Base64): " + Convert.ToBase64String(encrypted));

// 解密
byte[] decrypted = SM4Example.SM4Decrypt(encrypted, key, iv);
Console.WriteLine("解密结果: " + Encoding.UTF8.GetString(decrypted));

publicclassSM4Example
{
public static byte[] SM4Encrypt(byte[] plainText, byte[] key, byte[] iv)
  {
      var cipher = new PaddedBufferedBlockCipher(new CbcBlockCipher(new SM4Engine()), new Pkcs7Padding());
      cipher.Init(true, new ParametersWithIV(new KeyParameter(key), iv));
      return cipher.DoFinal(plainText);
  }

public static byte[] SM4Decrypt(byte[] cipherText, byte[] key, byte[] iv)
  {
      var cipher = new PaddedBufferedBlockCipher(new CbcBlockCipher(new SM4Engine()), new Pkcs7Padding());
      cipher.Init(false, new ParametersWithIV(new KeyParameter(key), iv));
      return cipher.DoFinal(cipherText);
  }

}

输出:
加密结果(Base64): 0ftObaUj9/7kATP2BoEImQ==
解密结果: Hello, SM4!

链接

  • • https://www.cnblogs.com/syzcyyx/articles/18258031

  • • https://www.bouncycastle.org/documentation/documentation-c/

关注公众号“Net分享”,技术文章第一时间推送,随缘更新 , 分享一些你可能注意不到的细节。

<think>好的,我现在要处理用户的问题:在Java Spring Boot拦截器中添加返回响应结果的SM4加密。首先,我需要确认用户的需求是什么。他们想在拦截器中处理响应数据,然后进行加密,特别是使用国密的SM4算法。 首先,我应该回忆一下Spring Boot拦截器的相关知识。拦截器主要用于预处理和后处理请求,可以在Controller执行前后进行操作。这里用户关注的是响应结果,所以应该是在afterCompletion方法,或者更可能是在preHandle或postHandle方法里处理响应数据?不对,postHandle是在Controller方法执行之后,视图渲染之前,可以修改ModelAndView。而afterCompletion是在请求完成之后,通常用于资源清理。因此,用户可能需要使用postHandle方法来修改响应内容,或者使用一个响应包装类来捕获响应数据。 但Spring的拦截器默认可能无法直接修改响应体,因为响应可能已经被提交。这时候可能需要使用Filter或者使用ContentCachingResponseWrapper来缓存响应数据,以便后续处理。不过用户提到的是拦截器,所以可能需要结合拦截器和ResponseBodyAdvice来实现。或者用户可能混淆了拦截器和过滤器的概念,需要明确两者的区别。 不过,用户明确说是拦截器,所以可能需要用HandlerInterceptor,但是要修改响应体的话,可能更合适的做法是使用ResponseBodyAdvice接口,它可以在控制器方法返回后,对响应体进行处理,比如加密。或者结合使用拦截器和ResponseBodyAdvice? 接下来,SM4加密的实现。需要确认用户是否已经有了SM4的工具类,或者需要引入相关的依赖。国密算法SM4的实现可能需要Bouncy Castle库或者其他国密算法的实现库。例如,Bouncy Castle提供了对SM4的支持,用户需要添加相应的依赖,或者使用国内的一些工具包,比如org.bouncycastle:bcprov-jdk15on。 然后,具体步骤可能是这样的: 1. 创建一个拦截器,实现HandlerInterceptor接口,或者使用ResponseBodyAdvice来对响应体进行处理。 2. 在拦截器的postHandle方法中,获取响应数据,进行加密处理。但是这里可能遇到问题,因为默认的响应流可能无法被重复读取,所以需要使用ContentCachingResponseWrapper来包装原始的HttpServletResponse,这样可以从缓存中读取响应内容。 3. 或者,使用ResponseBodyAdvice的beforeBodyWrite方法,在响应体写入之前进行加密处理。这种方式可能更直接,因为ResponseBodyAdvice专门用于处理响应体数据。 4. 实现SM4加密的逻辑,将原始响应内容加密后返回。 需要明确哪种方式更合适。例如,ResponseBodyAdvice允许在控制器返回结果后,对响应体进行处理,这样可以直接修改返回的数据,然后进行加密。而拦截器更适用于处理请求前后的通用逻辑,但修改响应体可能不太直接。 因此,可能更推荐使用ResponseBodyAdvice来实现。不过用户明确提到拦截器,可能需要解释两种方法,并给出相应的实现步骤。 接下来,具体实现步骤: 对于使用ResponseBodyAdvice: 1. 添加SM4加密所需的依赖,如Bouncy Castle。 2. 创建一个类实现ResponseBodyAdvice接口,并重写相关方法,支持对特定返回类型或路径的处理。 3. 在beforeBodyWrite方法中,获取原始的响应体,使用SM4加密,然后返回加密后的数据。 4. 配置这个Advice生效,可能需要使用@ControllerAdvice注解。 对于使用拦截器: 1. 创建一个拦截器类,实现HandlerInterceptor接口。 2. 在preHandle或postHandle方法中,将HttpServletResponse替换为ContentCachingResponseWrapper,以便后续读取响应内容。 3. 在afterCompletion方法中,获取缓存的响应内容,进行加密处理,并重新写入响应流。 4. 需要注意处理响应流的关闭和提交问题,避免重复写入。 不过,使用拦截器处理响应体可能较为复杂,因为拦截器的执行顺序和响应流的处理可能受限。而ResponseBodyAdvice更专注于响应体的处理,可能更简单。 另外,关于SM4加密的具体实现,用户可能需要生成密钥,选择合适的加密模式(如CBC或ECB),填充方式(如PKCS7Padding),以及处理IV(初始化向量)等。需要确保加密和解密的参数一致,比如密钥、模式、填充方式等。 因此,总结步骤: 1. 引入Bouncy Castle依赖或其他SM4实现库。 2. 创建ResponseBodyAdvice实现类,使用@ControllerAdvice注解。 3. 在beforeBodyWrite方法中,将原始响应数据转换为加密后的数据。 4. 编写SM4加密工具类,处理加密逻辑。 5. 测试验证加密是否正确,确保客户端能够解密。 可能还需要处理异常情况,比如加密失败,响应数据为空的情况。同时,要确保加密后的数据格式正确,比如Base64编码,以便传输。 最后,可能需要提供示例代码,说明如何实现ResponseBodyAdvice和SM4加密工具类,以及相关的配置步骤。同时提醒用户注意密钥管理,加密模式的选择,以及性能影响等注意事项。</think>在Spring Boot中,通过拦截器对响应结果进行SM4加密的实现可分为以下步骤: --- ### **1. 添加依赖** 首先引入SM4加密所需的库(如Bouncy Castle): ```xml <dependency> <groupId.org.bouncycastle</groupId> <artifactId>bcprov-jdk15on</artifactId> <version>1.70</version> </dependency> ``` --- ### **2. 创建SM4加密工具类** 编写SM4加密工具类,示例如下: ```java import org.bouncycastle.jce.provider.BouncyCastleProvider; import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; import java.security.Security; import java.util.Base64; public class SM4Util { static { Security.addProvider(new BouncyCastleProvider()); } // SM4加密(ECB模式,PKCS7填充) public static String encrypt(String data, String key) throws Exception { byte[] keyBytes = key.getBytes(); SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "SM4"); Cipher cipher = Cipher.getInstance("SM4/ECB/PKCS7Padding", "BC"); cipher.init(Cipher.ENCRYPT_MODE, keySpec); byte[] encrypted = cipher.doFinal(data.getBytes()); return Base64.getEncoder().encodeToString(encrypted); } } ``` --- ### **3. 实现响应体加密拦截器** 由于拦截器直接操作响应体较复杂,推荐使用`ResponseBodyAdvice`接口: ```java import org.springframework.core.MethodParameter; import org.springframework.http.MediaType; import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpResponse; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice; @ControllerAdvice public class EncryptResponseAdvice implements ResponseBodyAdvice<Object> { private static final String SM4_KEY = "your-16-byte-secret"; // 16字节密钥 @Override public boolean supports(MethodParameter returnType, Class converterType) { return true; // 对所有响应生效 } @Override public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) { try { String originalData = body.toString(); return SM4Util.encrypt(originalData, SM4_KEY); } catch (Exception e) { throw new RuntimeException("SM4加密失败", e); } } } ``` --- ### **4. 处理特殊情况** - **非字符串响应**:若响应为JSON对象,需先序列化为字符串再加密。 - **异常处理**:添加全局异常处理器,避免加密失败导致服务不可用。 --- ### **5. 配置密钥管理** - 密钥应从安全配置(如Vault、配置中心)动态获取,避免硬编码。 - 加密模式建议使用`CBC`(需处理IV)而非`ECB`以提高安全性。 --- ### **6. 验证结果** 发送请求后,响应应为加密后的Base64字符串: ```plaintext HTTP/1.1 200 OK Content-Type: text/plain qZ6N3mJ7T0KjRn8lPp2vXg== ``` --- ### **注意事项** 1. **性能影响**:加密操作可能增加响应时间,建议对敏感数据选择性加密。 2. **客户端解密**:确保客户端能正确解密(如使用相同SM4算法和密钥)。 3. **HTTPS推荐**:结合HTTPS传输,避免密钥泄露。 --- 通过以上步骤,即可在Spring Boot中实现对响应结果的SM4加密
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值