引自

1. Overview

BouncyCastle is a Java library that complements the default Java Cryptographic Extension (JCE).

In this introductory article, we’re going to show how to use BouncyCastle to perform cryptographic operations, such as encryption and signature.

2. Maven Configuration

Before we start working with the library, we need to add the required dependencies to our pom.xml file:

<dependency><groupId>org.bouncycastle</groupId><artifactId>bcpkix-jdk15on</artifactId><version>1.58</version>
</dependency>

Note that we can always look up the latest dependencies versions in the Maven Central Repository.

3. Setup Unlimited Strength Jurisdiction Policy Files

The standard Java installation is limited in terms of strength for cryptographic functions, this is due to policies prohibiting the use of a key with a size that exceeds certain values e.g. 128 for AES.

To overcome this limitation, we need to configure the unlimited strength jurisdiction policy files.

In order to do that, we first need to download the package by following this link. Afterwards, we need to extract the zipped file into a directory of our choice – which contains two jar files:

  • local_policy.jar
  • US_export_policy.jar

Finally, we need to look for the {JAVA_HOME}/lib/security folder and replace the existing policy files with the ones that we’ve extracted here.

Note that in Java 9, we no longer need to download the policy files package, setting the crypto.policy property to unlimited is enough:

Security.setProperty("crypto.policy", "unlimited");

Once done, we need to check that the configuration is working correctly:

int maxKeySize = javax.crypto.Cipher.getMaxAllowedKeyLength("AES");
System.out.println("Max Key Size for AES : " + maxKeySize);

As a result:

Max Key Size for AES : 2147483647

Based on the maximum key size returned by the getMaxAllowedKeyLength() method, we can safely say that the unlimited strength policy files have been installed correctly.

If the returned value is equal to 128, we need to make sure that we’ve installed the files into the JVM where we’re running the code.

4. Cryptographic Operations

4.1. Preparing Certificate And Private Key

Before we jump into the implementation of cryptographic functions, we first need to create a certificate and a private key.

For test purposes, we can use these resources:

  • Baeldung.cer
  • Baeldung.p12 (password = “password”)

Baeldung.cer is a digital certificate that uses the international X.509 public key infrastructure standard, while the Baeldung.p12 is a password-protected PKCS12 Keystore that contains a private key.

Let’s see how these can be loaded in Java:

Security.addProvider(new BouncyCastleProvider());
CertificateFactory certFactory= CertificateFactory.getInstance("X.509", "BC");X509Certificate certificate = (X509Certificate) certFactory.generateCertificate(new FileInputStream("Baeldung.cer"));char[] keystorePassword = "password".toCharArray();
char[] keyPassword = "password".toCharArray();KeyStore keystore = KeyStore.getInstance("PKCS12");
keystore.load(new FileInputStream("Baeldung.p12"), keystorePassword);
PrivateKey key = (PrivateKey) keystore.getKey("baeldung", keyPassword);

First, we’ve added the BouncyCastleProvider as a security provider dynamically using the addProvider() method.

This can also be done statically by editing the {JAVA_HOME}/jre/lib/security/java.security file, and adding this line:

security.provider.N = org.bouncycastle.jce.provider.BouncyCastleProvider

Once the provider is properly installed, we’ve created a CertificateFactory object using the getInstance() method.

The getInstance() method takes two arguments; the certificate type “X.509”, and the security provider “BC”.

The certFactory instance is subsequently used to generate an X509Certificate object, via the generateCertificate() method.

In the same way, we’ve created a PKCS12 Keystore object, on which the load() method is called.

The getKey() method returns the private key associated with a given alias.

Note that a PKCS12 Keystore contains a set of private keys, each private key can have a specific password, that’s why we need a global password to open the Keystore, and a specific one to retrieve the private key.

The Certificate and the private key pair are mainly used in asymmetric cryptographic operations:

  • Encryption
  • Decryption
  • Signature
  • Verification

4.2 CMS/PKCS7 Encryption And Decryption

In asymmetric encryption cryptography, each communication requires a public certificate and a private key.

The recipient is bound to a certificate, that is publicly shared between all senders.

Simply put, the sender needs the recipient’s certificate to encrypt a message, while the recipient needs the associated private key to be able to decrypt it.

Let’s have a look at how to implement an encryptData() function, using an encryption certificate:

public static byte[] encryptData(byte[] data,X509Certificate encryptionCertificate)throws CertificateEncodingException, CMSException, IOException {byte[] encryptedData = null;if (null != data && null != encryptionCertificate) {CMSEnvelopedDataGenerator cmsEnvelopedDataGenerator= new CMSEnvelopedDataGenerator();JceKeyTransRecipientInfoGenerator jceKey = new JceKeyTransRecipientInfoGenerator(encryptionCertificate);cmsEnvelopedDataGenerator.addRecipientInfoGenerator(transKeyGen);CMSTypedData msg = new CMSProcessableByteArray(data);OutputEncryptor encryptor= new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CBC).setProvider("BC").build();CMSEnvelopedData cmsEnvelopedData = cmsEnvelopedDataGenerator.generate(msg,encryptor);encryptedData = cmsEnvelopedData.getEncoded();}return encryptedData;
}

We’ve created a JceKeyTransRecipientInfoGenerator object using the recipient’s certificate.

Then, we’ve created a new CMSEnvelopedDataGenerator object and added the recipient information generator into it.

After that, we’ve used the JceCMSContentEncryptorBuilder class to create an OutputEncrytor object, using the AES CBC algorithm.

The encryptor is used later to generate a CMSEnvelopedData object that encapsulates the encrypted message.

Finally, the encoded representation of the envelope is returned as a byte array.

Now, let’s see what the implementation of the decryptData() method looks like:

public static byte[] decryptData(byte[] encryptedData, PrivateKey decryptionKey) throws CMSException {byte[] decryptedData = null;if (null != encryptedData && null != decryptionKey) {CMSEnvelopedData envelopedData = new CMSEnvelopedData(encryptedData);Collection<RecipientInformation> recipients= envelopedData.getRecipientInfos().getRecipients();KeyTransRecipientInformation recipientInfo = (KeyTransRecipientInformation) recipients.iterator().next();JceKeyTransRecipient recipient= new JceKeyTransEnvelopedRecipient(decryptionKey);return recipientInfo.getContent(recipient);}return decryptedData;
}

First, we’ve initialized a CMSEnvelopedData object using the encrypted data byte array, and then we’ve retrieved all the intended recipients of the message using the getRecipients() method.

Once done, we’ve created a new JceKeyTransRecipient object associated with the recipient’s private key.

The recipientInfo instance contains the decrypted/encapsulated message, but we can’t retrieve it unless we have the corresponding recipient’s key.

Finally, given the recipient key as an argument, the getContent() method returns the raw byte array extracted from the EnvelopedData this recipient is associated with.

Let’s write a simple test to make sure everything works exactly as it should:

String secretMessage = "My password is 123456Seven";
System.out.println("Original Message : " + secretMessage);
byte[] stringToEncrypt = secretMessage.getBytes();
byte[] encryptedData = encryptData(stringToEncrypt, certificate);
System.out.println("Encrypted Message : " + new String(encryptedData));
byte[] rawData = decryptData(encryptedData, privateKey);
String decryptedMessage = new String(rawData);
System.out.println("Decrypted Message : " + decryptedMessage);

As a result:

Original Message : My password is 123456Seven
Encrypted Message : 0*�H��...
Decrypted Message : My password is 123456Seven

4.2 CMS/PKCS7 Signature And Verification

Signature and verification are cryptographic operations that validate the authenticity of data.

Let’s see how to sign a secret message using a digital certificate:

public static byte[] signData(byte[] data, X509Certificate signingCertificate,PrivateKey signingKey) throws Exception {byte[] signedMessage = null;List<X509Certificate> certList = new ArrayList<X509Certificate>();CMSTypedData cmsData= new CMSProcessableByteArray(data);certList.add(signingCertificate);Store certs = new JcaCertStore(certList);CMSSignedDataGenerator cmsGenerator = new CMSSignedDataGenerator();ContentSigner contentSigner = new JcaContentSignerBuilder("SHA256withRSA").build(signingKey);cmsGenerator.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider("BC").build()).build(contentSigner, signingCertificate));cmsGenerator.addCertificates(certs);CMSSignedData cms = cmsGenerator.generate(cmsData, true);signedMessage = cms.getEncoded();return signedMessage;
}

First, we’ve embedded the input into a CMSTypedData, then, we’ve created a new CMSSignedDataGenerator object.

We’ve used SHA256withRSA as a signature algorithm, and our signing key to create a new ContentSigner object.

The contentSigner instance is used afterward, along with the signing certificate to create a SigningInfoGenerator object.

After adding the SignerInfoGenerator and the signing certificate to the CMSSignedDataGenerator instance, we finally use the generate() method to create a CMS signed-data object, which also carries a CMS signature.

Now that we’ve seen how to sign data, let’s see how to verify signed data:·

public static boolean verifSignedData(byte[] signedData)throws Exception {X509Certificate signCert = null;ByteArrayInputStream inputStream= new ByteArrayInputStream(signedData);ASN1InputStream asnInputStream = new ASN1InputStream(inputStream);CMSSignedData cmsSignedData = new CMSSignedData(ContentInfo.getInstance(asnInputStream.readObject()));SignerInformationStore signers = cmsSignedData.getCertificates().getSignerInfos();SignerInformation signer = signers.getSigners().iterator().next();Collection<X509CertificateHolder> certCollection = certs.getMatches(signer.getSID());X509CertificateHolder certHolder = certCollection.iterator().next();return signer.verify(new JcaSimpleSignerInfoVerifierBuilder().build(certHolder));
}

Again, we’ve created a CMSSignedData object based on our signed data byte array, then, we’ve retrieved all signers associated with the signatures using the getSignerInfos() method.

In this example, we’ve verified only one signer, but for generic use, it is mandatory to iterate over the collection of signers returned by the getSigners() method and check each one separately.

Finally, we’ve created a SignerInformationVerifier object using the build() method and passed it to the verify() method.

The verify() method returns true if the given object can successfully verify the signature on the signer object.

Here’s a simple example:

byte[] signedData = signData(rawData, certificate, privateKey);
Boolean check = verifSignData(signedData);
System.out.println(check);

As a result:

true

5. Conclusion

In this article, we’ve discovered how to use the BouncyCastle library to perform basic cryptographic operations, such as encryption and signature.

Introduction to BouncyCastle with Java相关推荐

  1. Website for the introduction to Matlab and Java

    http://www.aquaphoenix.com/#Lectures 转载于:https://www.cnblogs.com/stoneresearch/archive/2011/09/21/43 ...

  2. [Introduction to programming in Java 笔记] 1.3.8 Gambler's ruin simulation 赌徒破产模拟

    赌徒赢得机会有多大? public class Gambler {public static void main(String[] args){ // Run T experiments that s ...

  3. 《Java: The Complete Reference》等书读书笔记

    春节期间读了下<Java: The Complete Reference>发现这本书写的深入浅出,我想一个问题,书中很多内容我们也知道,但是为什么我们就写不出这样一本书,这么全面,这么系统 ...

  4. 【Java小工匠聊密码学】-密码学--综述

    1.密码学的概述 1.1.密码学定义 密码学是研究编制密码和破译密码的技术科学.研究密码变化的客观规律,应用于编制密码以保守通信秘密的,称为编码学:应用于破译密码以获取通信情报的,称为破译学,总称密码 ...

  5. java 最小化 api_Java的API设计实践

    Introduction 了解在设计Java API时应该应用的一些API设计实践.通常,这些实践很有用,并确保API可以在模块化环境中正确使用,例如OSGi和Java平台模块系统(JPMS).有些做 ...

  6. Java开发者必须知道的内存泄漏问题

    点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 1. 简介 Java的核心优势之一是在内置垃圾收集器(简 ...

  7. 了解Java中的内存泄漏

    来源:SpringForAll社区 1. 简介 Java的核心优势之一是在内置垃圾收集器(简称GC)的帮助下实现自动内存管理.GC隐含地负责分配和释放内存,因此能够处理大多数内存泄漏问题. 虽然GC有 ...

  8. java数据结构读书笔记--引论

    1 递归简论 需求:求出f(x)=2f(x-1)+x²的值.满足f(0)=0 public class Recursion {// 需求: 求出f(x)=2f(x-1)+x²的值.满足f(0)=0pu ...

  9. Resolving Problems installing the Java JCE Unlimited Strength Jurisdiction Policy Files package--转

    原文地址:https://www.ca.com/us/services-support/ca-support/ca-support-online/knowledge-base-articles.tec ...

  10. java 内存泄漏_Java开发者必须知道的内存泄漏问题

    1. 简介 Java的核心优势之一是在内置垃圾收集器(简称GC)的帮助下实现自动内存管理.GC隐含地负责分配和释放内存,因此能够处理大多数内存泄漏问题. 虽然GC有效地处理了大部分内存,但它并不能成为 ...

最新文章

  1. k8s mysql operator_将 MySQL 通过 presslabs/mysql-operator 部署到 k8s 内部
  2. RvaToFileOffset 内存偏移转成文件偏移(滴水课后作业)
  3. Fortran 入门——函数调用
  4. 读写分离mysql数据库mariadb_MariaDB数据库读写分离实现(一):mysql-proxy的使用
  5. ML.NET Cookbook:(5)如何查看中间过程数据?
  6. SVN+AnkhSVN端配置
  7. 安装用户debian7安装oracle11g
  8. 【kafka】kafka 中 消息 record 格式
  9. leetcode 题库894-- 所有可能的满二叉树
  10. HttpUtils请求工具类
  11. C++沉思录(Ruminations on C++)中文第2版电子书pdf下载
  12. 4K图片(壁纸)免费下载网站【实用】
  13. 【虚幻引擎4(UE4)实用技巧】-关于高亮显示物体轮廓线
  14. UE4 3DUI Widget半透明渲染模糊和重影问题
  15. 做开发你遇到最无理的需求是什么?
  16. steam、DOTA2或者steam下的游戏双击没反应怎么解决
  17. win10声音显示红叉问题解决
  18. 计算机无法识别ipad2,iTunes无法识别iPad mini怎么办【解决方法】
  19. 请求消息详解(请求头、get、post、请求体)
  20. Delphi XE 10 跨平台三层数据库应用教程

热门文章

  1. android编译找不到系统so,Android找不到so库解决方法
  2. guided filter matlab,导向滤波器(Guided Filter)
  3. Android开发_ARN是什么
  4. 【Matlab代码】Sierpinsk地毯
  5. vue.js中created方法作用
  6. 浅谈微信小程序和微信公众平台
  7. [后缀数组][trie合并][启发式合并][并查集] LOJ #6198. 谢特
  8. android mac 探针,wifi探针获取手机mac地址
  9. shiny改写服务器文件,Shiny生产环境部署与共享
  10. Windows历史版本下载