• java使用bouncycastle加解密


    jdk默认带了一些常见的加解密方式,当我们常见的加解密不能满足时,就需要用到一些第三方的库了,bouncycastle就是其中一种。

    但是bouncycastle文档比较少。简单介绍一下写法

    1.导入依赖

    1. <dependency>
    2. <groupId>org.bouncycastle</groupId>
    3. <artifactId>bcprov-jdk15on</artifactId>
    4. <version>1.69</version>
    5. </dependency>

    2.写代码

    常见的有两种方式,一种使用BouncyCastleProvider,另一种使用BlockCipherEngine

    BouncyCastleProvider使用方式跟原生jdk类似,多数getInstance的地方指定一下provider就行

    BouncyCastleProvider方式DES加解密代码如下

    1. package com.vvvtimes.demo.util.endecrypt;
    2. import lombok.extern.slf4j.Slf4j;
    3. import org.bouncycastle.jce.provider.BouncyCastleProvider;
    4. import javax.crypto.Cipher;
    5. import javax.crypto.KeyGenerator;
    6. import javax.crypto.SecretKey;
    7. import javax.crypto.SecretKeyFactory;
    8. import javax.crypto.spec.DESKeySpec;
    9. import javax.crypto.spec.IvParameterSpec;
    10. import java.security.Key;
    11. import java.security.NoSuchAlgorithmException;
    12. @Slf4j
    13. public class BcDesUtil {
    14. private static final BouncyCastleProvider provider;
    15. //BouncyCastle与JDK加解密类区别
    16. //KeyFactory.getInstance("RSA"); +provider-->KeyFactory.getInstance("RSA", provider)
    17. //Cipher.getInstance("RSA"); +provider-->Cipher.getInstance("RSA", provider)
    18. //Signature.getInstance("SHA1withRSA"); +provider-->Signature.getInstance("SHA1withRSA", provider);
    19. //KeyGenerator.getInstance("DES") ; +provider-->KeyGenerator.getInstance("DES", provider); 或者KeyGenerator.getInstance("DES","BC")
    20. /**
    21. * 偏移变量,固定占8位字节
    22. */
    23. private final static String IV_PARAMETER = "12345678";
    24. /*
    25. * 生成key
    26. */
    27. public byte[] generateKey() {
    28. KeyGenerator keyGenerator = null;
    29. try {
    30. keyGenerator = KeyGenerator.getInstance("DES",provider);
    31. keyGenerator.init(56);
    32. SecretKey secretKey = keyGenerator.generateKey();
    33. byte[] encoded = secretKey.getEncoded();
    34. return encoded;
    35. } catch (NoSuchAlgorithmException e) {
    36. e.printStackTrace();
    37. }
    38. return null;
    39. }
    40. /**
    41. * 生成key
    42. *
    43. * @param password 密钥字符串
    44. * @return 密钥对象
    45. * @throws Exception
    46. */
    47. private static Key convertKey(byte[] password) throws Exception {
    48. DESKeySpec dks = new DESKeySpec(password);
    49. SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES",provider);
    50. return keyFactory.generateSecret(dks);
    51. }
    52. /**
    53. * DES加密
    54. */
    55. public static byte[] encrypt(byte[] data, byte[] password) {
    56. if (password == null || password.length < 8) {
    57. throw new RuntimeException("加密失败,key不能小于8位");
    58. }
    59. if (data == null)
    60. return null;
    61. try {
    62. Key secretKey = convertKey(password);
    63. Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding",provider);
    64. IvParameterSpec iv = new IvParameterSpec(IV_PARAMETER.getBytes("utf-8"));
    65. cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
    66. byte[] bytes = cipher.doFinal(data);
    67. return bytes;
    68. } catch (Exception e) {
    69. e.printStackTrace();
    70. return data;
    71. }
    72. }
    73. /**
    74. * DES解密解密字符串
    75. */
    76. public static byte[] decrypt(byte[] data, byte[] password) {
    77. if (password == null || password.length < 8) {
    78. throw new RuntimeException("加密失败,key不能小于8位");
    79. }
    80. if (data == null)
    81. return null;
    82. try {
    83. Key secretKey = convertKey(password);
    84. Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding",provider);
    85. IvParameterSpec iv = new IvParameterSpec(IV_PARAMETER.getBytes("utf-8"));
    86. cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
    87. byte[] bytes = cipher.doFinal(data);
    88. return bytes;
    89. } catch (Exception e) {
    90. e.printStackTrace();
    91. return data;
    92. }
    93. }
    94. /**
    95. * byte数组转十六进制
    96. *
    97. * @param bytes
    98. * @return
    99. */
    100. public static String byte2HexString(byte[] bytes) {
    101. StringBuilder hex = new StringBuilder();
    102. if (bytes != null) {
    103. for (Byte b : bytes) {
    104. hex.append(String.format("%02X", b.intValue() & 0xFF));
    105. }
    106. }
    107. return hex.toString();
    108. }
    109. //测试
    110. public static void main(String[] args) throws Exception {
    111. String source = "admin测试信息1234!@#$%^&*()_+";
    112. System.out.println("原 文: " + source);
    113. String password = "lw112190@2023";
    114. byte[] encryptDataBytes = encrypt(source.getBytes("utf-8"), password.getBytes("utf-8"));
    115. String encryptData = byte2HexString(encryptDataBytes);
    116. System.out.println("加密后: " + encryptData);
    117. byte[] decryptDataBytes = decrypt(encryptDataBytes, password.getBytes("utf-8"));
    118. String decryptData = new String(decryptDataBytes, "utf-8");
    119. ;
    120. System.out.println("解密后: " + decryptData);
    121. }
    122. static {
    123. provider = new BouncyCastleProvider();
    124. }
    125. }

    BlockCipherEngine方式的DES加解密代码如下

    1. package com.vvvtimes.demo.util.endecrypt;
    2. import org.bouncycastle.crypto.BlockCipher;
    3. import org.bouncycastle.crypto.BufferedBlockCipher;
    4. import org.bouncycastle.crypto.InvalidCipherTextException;
    5. import org.bouncycastle.crypto.engines.DESEngine;
    6. import org.bouncycastle.crypto.modes.CBCBlockCipher;
    7. import org.bouncycastle.crypto.paddings.PKCS7Padding;
    8. import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
    9. import org.bouncycastle.crypto.params.DESParameters;
    10. import org.bouncycastle.crypto.params.ParametersWithIV;
    11. import org.bouncycastle.jce.provider.BouncyCastleProvider;
    12. import javax.crypto.SecretKey;
    13. import javax.crypto.SecretKeyFactory;
    14. import javax.crypto.spec.DESKeySpec;
    15. import java.io.UnsupportedEncodingException;
    16. import java.security.InvalidKeyException;
    17. import java.security.NoSuchAlgorithmException;
    18. import java.security.spec.InvalidKeySpecException;
    19. public class BcDesEngineUtil {
    20. private final static BlockCipher engine;
    21. private static final BouncyCastleProvider provider;
    22. /**
    23. * 偏移变量,固定占8位字节
    24. */
    25. private final static String IV_PARAMETER = "12345678";
    26. /**
    27. * 生成key
    28. *
    29. * @param password 密钥字符串
    30. * @return 密钥对象
    31. * @throws Exception
    32. */
    33. private static byte[] convertKeyEncoded(byte[] password) {
    34. byte[] result = null;
    35. try {
    36. DESKeySpec dks = new DESKeySpec(password);
    37. SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES",provider);
    38. SecretKey secretKey = keyFactory.generateSecret(dks);
    39. return secretKey.getEncoded();
    40. } catch (InvalidKeyException e) {
    41. e.printStackTrace();
    42. } catch (NoSuchAlgorithmException e) {
    43. e.printStackTrace();
    44. } catch (InvalidKeySpecException e) {
    45. e.printStackTrace();
    46. }
    47. return result;
    48. }
    49. private static byte[] encrypt( byte[] ptBytes,byte[] key) throws InvalidCipherTextException, UnsupportedEncodingException {
    50. BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(engine), new PKCS7Padding());
    51. cipher.init(true, new ParametersWithIV(new DESParameters(key), IV_PARAMETER.getBytes("utf-8")));
    52. byte[] rv = new byte[cipher.getOutputSize(ptBytes.length)];
    53. int tam = cipher.processBytes(ptBytes, 0, ptBytes.length, rv, 0);
    54. cipher.doFinal(rv, tam);
    55. return rv;
    56. }
    57. private static byte[] decrypt( byte[] cipherText,byte[] key) throws InvalidCipherTextException, UnsupportedEncodingException {
    58. BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(engine), new PKCS7Padding());
    59. cipher.init(false, new ParametersWithIV(new DESParameters( key),IV_PARAMETER.getBytes("utf-8")));
    60. byte[] rv = new byte[cipher.getOutputSize(cipherText.length)];
    61. int tam = cipher.processBytes(cipherText, 0, cipherText.length, rv, 0);
    62. cipher.doFinal(rv, tam);
    63. return rv;
    64. }
    65. /**
    66. * byte数组转十六进制
    67. *
    68. * @param bytes
    69. * @return
    70. */
    71. public static String byte2HexString(byte[] bytes) {
    72. StringBuilder hex = new StringBuilder();
    73. if (bytes != null) {
    74. for (Byte b : bytes) {
    75. hex.append(String.format("%02X", b.intValue() & 0xFF));
    76. }
    77. }
    78. return hex.toString();
    79. }
    80. //测试
    81. public static void main(String[] args) throws Exception {
    82. String source = "admin测试信息1234!@#$%^&*()_+";
    83. System.out.println("原 文: " + source);
    84. String password = "lw112190@2023";
    85. //String password ="geffzhan";
    86. //String password ="lw112190";
    87. byte[] keyEncoded = convertKeyEncoded(password.getBytes("utf-8"));
    88. byte[] encryptDataBytes = encrypt(source.getBytes("utf-8"), keyEncoded);
    89. String encryptData = byte2HexString(encryptDataBytes);
    90. System.out.println("加密后: " + encryptData);
    91. byte[] decryptDataBytes = decrypt(encryptDataBytes, keyEncoded);
    92. String decryptData = new String(decryptDataBytes, "utf-8");
    93. ;
    94. System.out.println("解密后: " + decryptData);
    95. /*
    96. *原 文: admin测试信息1234!@#$%^&*()_+
    97. 加密后: 1D5C21B694A9085A69BE7EA37C197D1632239545298613B944C3AC272750A519F66FB43EFEC55C89
    98. 解密后: admin测试信息1234!@#$%^&*()_+
    99. */
    100. }
    101. static {
    102. engine = new DESEngine();
    103. provider = new BouncyCastleProvider();
    104. }
    105. }

    3.其他示例

    AES加解密

    1. package com.vvvtimes.demo.util.endecrypt;
    2. import lombok.extern.slf4j.Slf4j;
    3. import org.bouncycastle.jce.provider.BouncyCastleProvider;
    4. import javax.crypto.Cipher;
    5. import javax.crypto.KeyGenerator;
    6. import javax.crypto.SecretKey;
    7. import javax.crypto.SecretKeyFactory;
    8. import javax.crypto.spec.DESKeySpec;
    9. import javax.crypto.spec.IvParameterSpec;
    10. import javax.crypto.spec.SecretKeySpec;
    11. import java.security.AlgorithmParameters;
    12. import java.security.Key;
    13. import java.security.NoSuchAlgorithmException;
    14. import java.security.spec.InvalidParameterSpecException;
    15. @Slf4j
    16. public class BcAesUtil {
    17. private static final BouncyCastleProvider provider;
    18. /**
    19. * 偏移变量,固定占8位字节
    20. */
    21. private final static String IV_PARAMETER = "1234567890123456";
    22. /**
    23. * AES加密
    24. */
    25. public static byte[] encrypt(byte[] data, byte[] password, byte[] iv) {
    26. if (data == null)
    27. return null;
    28. try {
    29. Key secretKey = new SecretKeySpec(password,"AES");
    30. Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding",provider);
    31. AlgorithmParameters generateIV = generateIV(iv);
    32. cipher.init(Cipher.ENCRYPT_MODE, secretKey, generateIV);
    33. byte[] bytes = cipher.doFinal(data);
    34. return bytes;
    35. } catch (Exception e) {
    36. e.printStackTrace();
    37. return data;
    38. }
    39. }
    40. /**
    41. * AES解密解密字符串
    42. */
    43. public static byte[] decrypt(byte[] data, byte[] password, byte[] iv) {
    44. if (data == null)
    45. return null;
    46. try {
    47. Key secretKey = new SecretKeySpec(password,"AES");
    48. Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding",provider);
    49. AlgorithmParameters generateIV = generateIV(iv);
    50. cipher.init(Cipher.DECRYPT_MODE, secretKey, generateIV);
    51. byte[] bytes = cipher.doFinal(data);
    52. return bytes;
    53. } catch (Exception e) {
    54. e.printStackTrace();
    55. return data;
    56. }
    57. }
    58. public static AlgorithmParameters generateIV(byte[] iv){
    59. AlgorithmParameters params = null;
    60. try {
    61. params = AlgorithmParameters.getInstance("AES");
    62. params.init(new IvParameterSpec(iv));
    63. } catch (NoSuchAlgorithmException | InvalidParameterSpecException e) {
    64. e.printStackTrace();
    65. }
    66. return params;
    67. }
    68. /**
    69. * byte数组转十六进制
    70. *
    71. * @param bytes
    72. * @return
    73. */
    74. public static String byte2HexString(byte[] bytes) {
    75. StringBuilder hex = new StringBuilder();
    76. if (bytes != null) {
    77. for (Byte b : bytes) {
    78. hex.append(String.format("%02X", b.intValue() & 0xFF));
    79. }
    80. }
    81. return hex.toString();
    82. }
    83. //测试
    84. public static void main(String[] args) throws Exception {
    85. String source = "admin测试信息1234!@#$%^&*()_+";
    86. System.out.println("原 文: " + source);
    87. String password = "passwordpassword";
    88. byte[] encryptDataBytes = encrypt(source.getBytes("utf-8"), password.getBytes("utf-8"),IV_PARAMETER.getBytes("utf-8"));
    89. String encryptData = byte2HexString(encryptDataBytes);
    90. System.out.println("加密后: " + encryptData);
    91. byte[] decryptDataBytes = decrypt(encryptDataBytes, password.getBytes("utf-8"),IV_PARAMETER.getBytes("utf-8"));
    92. String decryptData = new String(decryptDataBytes, "utf-8");
    93. System.out.println("解密后: " + decryptData);
    94. }
    95. static {
    96. provider = new BouncyCastleProvider();
    97. }
    98. }

    RSA私钥解密 签名

    1. package com.vvvtimes.demo.util.endecrypt;
    2. import cn.hutool.core.codec.Base64;
    3. import org.bouncycastle.jce.provider.BouncyCastleProvider;
    4. import javax.crypto.BadPaddingException;
    5. import javax.crypto.Cipher;
    6. import javax.crypto.IllegalBlockSizeException;
    7. import javax.crypto.NoSuchPaddingException;
    8. import java.nio.charset.Charset;
    9. import java.security.*;
    10. import java.security.spec.PKCS8EncodedKeySpec;
    11. public class BcRsaUtil {
    12. private static final BouncyCastleProvider provider;
    13. private static PrivateKey getPrivateKey(String pkcs8Key) {
    14. byte[] pkcs8Keybytes = Base64.decode(pkcs8Key.getBytes(Charset.forName("UTF-8")));
    15. final PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(pkcs8Keybytes);
    16. try {
    17. return KeyFactory.getInstance("RSA", provider).generatePrivate(pkcs8EncodedKeySpec);
    18. } catch (Exception ex) {
    19. ex.printStackTrace();
    20. return null;
    21. }
    22. }
    23. /**
    24. * RSA私钥解密
    25. *
    26. * @param inputByte 待解密字节数组
    27. * @param pkcs8Key 私钥
    28. * @return 明文
    29. */
    30. public static byte[] decrypt(byte[] inputByte, String pkcs8Key) {
    31. byte[] outputeByte = null;
    32. try {
    33. PrivateKey privateKey = getPrivateKey(pkcs8Key);
    34. //RSA解密
    35. Cipher cipher = Cipher.getInstance("RSA", provider);
    36. cipher.init(Cipher.DECRYPT_MODE, privateKey);
    37. outputeByte = cipher.doFinal(inputByte);
    38. } catch (NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException | NoSuchAlgorithmException e) {
    39. e.printStackTrace();
    40. }
    41. return outputeByte;
    42. }
    43. public static byte[] sign(final byte[] array, String pkcs8Key) {
    44. try {
    45. PrivateKey privateKey = getPrivateKey(pkcs8Key);
    46. final Signature instance = Signature.getInstance("SHA1withRSA", provider);
    47. instance.initSign(privateKey);
    48. instance.update(array);
    49. return instance.sign();
    50. } catch (GeneralSecurityException ex) {
    51. throw new RuntimeException("License Server installation error 0000000F2", ex);
    52. }
    53. }
    54. static {
    55. provider = new BouncyCastleProvider();
    56. }
    57. }

    实际上bouncycastle还支持部分国密算法,这一部分不用自己写实现了。

  • 相关阅读:
    MetaObjectHandler的使用
    比较两个对象 取最大值 并返回对象
    网络安全等级保护基本要求解读- 安全计算环境-应用系统和数据安全
    AMD老电脑超频及性能提升方案及实施
    SpringBoot 整合 Dozer 映射框架
    Java EE -- Spring
    ardupilot的编译过程
    hi3559 C/C++混编 makefile(基于官方sample)
    博弈论
    熊猫在线影院系统笔记链接
  • 原文地址:https://blog.csdn.net/gsls200808/article/details/134256085