BouncyCastle使用

Bouncy Castle Crypto API由一个名为Bouncy Castle Inc的澳大利亚慈善组织维护。负责管理和维护Bouncy Castle API。希望为这项工作提供支持的朋友可以关注我们的捐赠页面或者通过Crypto工作组购买支持服务。非常欢迎为具体功能的改进开发或相关工作提供赞助。

Bouncy Castle Crypto的Java API包含下列内容:

  • 一个轻量级加密解密API。
  • Java加密解密扩展和框架Provider。
  • 一个JCE 1.2.1的净室实现(a clean-room implementation)。
  • 一个针对加密ASN.1对象的读写库。
  • TLS轻量级API((RFC 2246、RFC 4346)和 DTLS(RFC 4347)。
  • 提供3 X.509证书版本1和版本3 X生成器/处理器、CRL版本2和PKCS12文件。
  • 提供X.509证书版本2生成器/处理器。
  • 提供S/MIME和CMS(PKCS7/RFC 3852)生成器/处理器。
  • 提供OCSP(RFC 2560)生成器/处理器。
  • 提供TSP(RFC 3161 & RFC 5544)生成器/处理器。
  • 提供CMP和CRMF(RFC 4210 & RFC 4211)生成器/处理器。
  • 提供OpenPGP(RFC 4880)生成器/处理器。
  • 提供扩展访问控制(EAC)生成器/处理器。
  • 提供数据验证和认证服务器(DVCS)—RFC 3029生成器/处理器。
  • 提供基于DNS的命名实体认证((DANE)生成器/处理器。
  • 适用于JDK 1.4-1.8和Sun JCE的签名 jar 版本。

该轻量级API可以与从J2ME到JDK 1.8的任何版本一起工作。现在还提供了证书生成,提供针对各种JDK版本的 PKCS/CMS/CRMF/CMP/EAC/DANE/DVCS/TSP/TLS/DTLS 和 OpenPGP支持。

除非特殊声明,所有该站点提供的软件都遵循 下列协议 发布。

如果在列表中没有找到想要的资源,可以看看我们的资源页面。

1、为什么要使用BouncyCastle?

我们平常都使用jdk自带的加密包对数据进行加密,加密方式也都是使用的默认的,如果我们想选择别的加密方式,发现会报错,比如如下代码:

  1. Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding");
  2. cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA".getBytes("UTF-8"), "AES"));
  3. cipher.doFinal("QWEASDZS".getBytes("UTF-8"));

这时候我们就需要借助BouncyCastle了。

2、如何使用BouncyCastle?

2.1、方式一

(1)去BouncyCastle官网下载provider的包,然后放入$JAVA_HOME\jre\lib\ext目录下;

(2)修改配置文件$JAVA_HOME\jre\lib\security\java.security,加入一行配置:security.provider.按顺序填数字=org.bouncycastle.jce.provider.BouncyCastleProvider

(3)代码如下:

  1. Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding");
  2. cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA".getBytes("UTF-8"), "AES"));
  3. cipher.doFinal("QWEASDZS".getBytes("UTF-8"));
    这个方式不太合适, 因为有时候要替换 环境中的 jdk的, 因此在替换时若是处理不当, 后面就无法工作了。
    例如oralce的jdk已经陆续开始收费了, 我们公司已经全部都替换为openjdk了, 因此若是把库房到jdk下面, 就有麻烦了!

2.2、方式二

(1)在代码中通过maven引入BouncyCastle的包

<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.56</version>
</dependency>

(2)无需像方式一一样修改配置文件,直接在代码中手动添加provider:

  1. Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
  2. Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding");
  3. cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA".getBytes("UTF-8"), "AES"));
  4. cipher.doFinal("QWEASDZS".getBytes("UTF-8"));

下面一个段测试代码(包括MD5,Base64以及AES加密):

  1. public void test() {
  2.     String clearText = "Hello World!";
  3.     String password = "hi";
  4.     //md5
  5.     MD5Digest digest = new MD5Digest();
  6.     digest.update(password.getBytes(), 0, password.length());
  7.     int md5Num = digest.getByteLength();
  8.     byte[] md5Buf = new byte[md5Num];
  9.     digest.doFinal(md5Buf, 0);
  10.     //base64
  11.     byte[] base64Buf = Base64.encode(md5Buf);
  12.     byte[] key = new byte[16];//设置key长度为128位
  13.     System.arraycopy(base64Buf, 0, key, 016);
  14.     //AES加密
  15.     byte[] cipherBuf = null;
  16.     cipherBuf = AESEncode(clearText.getBytes(), key);
  17.     //AES解密
  18.     String decryptText = AESDecode(cipherBuf, key);
  19.     System.out.println("md5:" + new String(md5Buf));
  20.     System.out.println("base64:" + new String(base64Buf));
  21.     System.out.println("key:" + new String(key));
  22.     System.out.println("cipher:" + new String(cipherBuf));
  23.     System.out.println("clear:" + decryptText);
  24. }

Base64编码后的字符串是由a~z,A~Z,+,/这64个字符组合而成,末尾补齐用“=”号表示。
AES加密算法对key的长度有限制,它只支持128,192和256位的key。所以代码中接key设置成16个字节。

下面是AES加密的代码:

  1. public byte[] AESEncode(byte[] clearText, byte[] key) {
  2.     byte[] rv = null;
  3.     BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new AESEngine());
  4.     cipher.init(truenew KeyParameter(key));
  5.     rv = new byte[cipher.getOutputSize(clearText.length)];
  6.     int oLen = cipher.processBytes(clearText, 0, clearText.length, rv, 0);
  7.     try {
  8.         cipher.doFinal(rv, oLen);
  9.     } catch (DataLengthException e) {
  10.     } catch (IllegalStateException e) {
  11.     } catch (InvalidCipherTextException e) {
  12.     }
  13.     return rv;
  14. }

下面是AES解密的代码:

  1. public String AESDecode(byte[] cipherText, byte[] key) {
  2.     byte[] rv = null;
  3.     BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new AESEngine());
  4.     cipher.init(falsenew KeyParameter(key));
  5.     rv = new byte[cipher.getOutputSize(cipherText.length)];    //该大小会大于实际的大小
  6.     int oLen = cipher.processBytes(cipherText, 0, cipherText.length, rv, 0);
  7.     try
  8.     {
  9.         cipher.doFinal(rv, oLen);
  10.     } catch (DataLengthException e) {
  11.     } catch (IllegalStateException e) {
  12.     } catch (InvalidCipherTextException e) {
  13.     }
  14.     return new String(rv).trim();
  15. }

代码中rv的初始化长度会大于实际解密后数据的长度,所以生成的String要去掉空格。