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自带的加密包对数据进行加密,加密方式也都是使用的默认的,如果我们想选择别的加密方式,发现会报错,比如如下代码:
-
Cipher cipher = Cipher.getInstance(“AES/ECB/PKCS7Padding”);
-
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(“AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA”.getBytes(“UTF-8″), “AES”));
-
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)代码如下:
-
Cipher cipher = Cipher.getInstance(“AES/ECB/PKCS7Padding”);
-
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(“AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA”.getBytes(“UTF-8″), “AES”));
-
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:
-
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
-
Cipher cipher = Cipher.getInstance(“AES/ECB/PKCS7Padding”);
-
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(“AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA”.getBytes(“UTF-8″), “AES”));
-
cipher.doFinal(“QWEASDZS”.getBytes(“UTF-8″));
下面一个段测试代码(包括MD5,Base64以及AES加密):
- public void test() {
- String clearText = “Hello World!”;
- String password = “hi”;
- //md5
- MD5Digest digest = new MD5Digest();
- digest.update(password.getBytes(), 0, password.length());
- int md5Num = digest.getByteLength();
- byte[] md5Buf = new byte[md5Num];
- digest.doFinal(md5Buf, 0);
- //base64
- byte[] base64Buf = Base64.encode(md5Buf);
- byte[] key = new byte[16];//设置key长度为128位
- System.arraycopy(base64Buf, 0, key, 0, 16);
- //AES加密
- byte[] cipherBuf = null;
- cipherBuf = AESEncode(clearText.getBytes(), key);
- //AES解密
- String decryptText = AESDecode(cipherBuf, key);
- System.out.println(“md5:” + new String(md5Buf));
- System.out.println(“base64:” + new String(base64Buf));
- System.out.println(“key:” + new String(key));
- System.out.println(“cipher:” + new String(cipherBuf));
- System.out.println(“clear:” + decryptText);
- }
Base64编码后的字符串是由a~z,A~Z,+,/这64个字符组合而成,末尾补齐用“=”号表示。
AES加密算法对key的长度有限制,它只支持128,192和256位的key。所以代码中接key设置成16个字节。
下面是AES加密的代码:
- public byte[] AESEncode(byte[] clearText, byte[] key) {
- byte[] rv = null;
- BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new AESEngine());
- cipher.init(true, new KeyParameter(key));
- rv = new byte[cipher.getOutputSize(clearText.length)];
- int oLen = cipher.processBytes(clearText, 0, clearText.length, rv, 0);
- try {
- cipher.doFinal(rv, oLen);
- } catch (DataLengthException e) {
- } catch (IllegalStateException e) {
- } catch (InvalidCipherTextException e) {
- }
- return rv;
- }
下面是AES解密的代码:
- public String AESDecode(byte[] cipherText, byte[] key) {
- byte[] rv = null;
- BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new AESEngine());
- cipher.init(false, new KeyParameter(key));
- rv = new byte[cipher.getOutputSize(cipherText.length)]; //该大小会大于实际的大小
- int oLen = cipher.processBytes(cipherText, 0, cipherText.length, rv, 0);
- try
- {
- cipher.doFinal(rv, oLen);
- } catch (DataLengthException e) {
- } catch (IllegalStateException e) {
- } catch (InvalidCipherTextException e) {
- }
- return new String(rv).trim();
- }
代码中rv的初始化长度会大于实际解密后数据的长度,所以生成的String要去掉空格。