使用Bouncy Castle创建PGP密钥对
最后一个寒假了,由于正在走向Java猴子的路上,所以要适应一大批Java的轮子,那就从最基本的加密开始做笔记吧。
PGP是常用的非对称加密手段,也是我所喜欢加在项目里的轮子,Bouncy Castle中的PGP包可以满足所有PGP需求。
Bouncy Castle介绍
Bouncy Castle(以下简称为BC)是一个开源的Java包,其中几乎包含了程序猿们所听说过的所有加密方式,十分简洁易用。Bouncy Castle的优势不仅仅体现在其轻便性,更重要的是他横跨了所有的Java平台,即使是J2ME都在他的魔爪之下。
当然,Bouncy Castle还有对应的C#类库,并且中文资料挺多~
Bouncy Castle PGP包
PGP包的包名为org.bouncycastle.bcpg
,使用Maven的话需要添加以下依赖:
<!-- Provider依赖 --> <!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on --> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk15on</artifactId> <version>1.56</version> </dependency> <!-- OpenPGP包依赖 --> <!-- https://mvnrepository.com/artifact/org.bouncycastle/bcpg-jdk15on --> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpg-jdk15on</artifactId> <version>1.56</version> </dependency>
BC中PGP密钥对的构成
这里不讨论PGP的原理(毕竟几年没学数论了23333)。我们知道在信息的非对称加密中,需要有公钥和私钥两把钥匙。
公钥(PublicKey)负责加密内容,私钥(PrivateKey)负责解密内容。在PGP的规则里,私钥是由密钥对的所有者保管的,他是用对称加密方法(CAST-128)被加密在密钥中(也就是SecretKey),这样确保只有知道密钥口令的人才能掌握私钥。
BC将PublicKey和加密后的PrivateKey存放在的SecretKey对象中。
BC所处理的PGP的加解密流程也不在本文的讨论范围中,后续会跟上。
Java使用BC生成密钥对
先上代码:
/** * 私有方法,用于生成指定位宽的PGP RSA密钥对 * * @param rsaWidth_ RSA密钥位宽 * @return 未经私钥加密的PGP密钥对 * @throws Exception IO错误,数值错误等 */ private static PGPKeyPair generateKeyPair(int rsaWidth_) throws Exception { KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", "BC");//获取密钥对生成器实例 kpg.initialize(rsaWidth_);//设定RSA位宽 KeyPair kp = kpg.generateKeyPair();//生成RSA密钥对 return new JcaPGPKeyPair(PGPPublicKey.RSA_GENERAL, kp, new Date());//返回根据日期,密钥对生成的PGP密钥对 } /** * 获取PGP密钥<br> * 密钥是将密钥对的私钥部分用对称的加密方法CAST-128算法加密,再加上公钥部分 * * @param identity_ 密钥ID也就是key值,可以用来标记密钥属于谁 * @param passPhrase_ 密钥的密码,用来解出私钥 * @param rsaWidth_ RSA位宽 * @return PGP密钥 * @throws Exception IO错误和数值错误等 */ public static PGPSecretKey getSecretKey(String identity_, String passPhrase_, int rsaWidth_) throws Exception { char[] passPhrase = passPhrase_.toCharArray(); //将passPharse转换成字符数组 PGPKeyPair keyPair = KeyPairGeneratorRSA.generateKeyPair(rsaWidth_); //生成RSA密钥对 PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder().build().get(HashAlgorithmTags.SHA1); //使用SHA1作为证书的散列算法 return new PGPSecretKey( PGPSignature.DEFAULT_CERTIFICATION, keyPair, identity_, sha1Calc, null, null, new JcaPGPContentSignerBuilder(keyPair.getPublicKey().getAlgorithm(), HashAlgorithmTags.SHA1), //密钥的加密方式 new JcePBESecretKeyEncryptorBuilder(PGPEncryptedData.CAST5, sha1Calc).setProvider("BC").build(passPhrase) ); }
以上就是BC根据用户标识和私钥密码生成PGPSecretKey的过程,其实最关键的是PGPSecretKey的构造方法,以下是这个构造方法JavaDoc的翻译:
/** * 用证书等级生成的认证,将公私钥对和PGP ID密码绑定构造PGP密钥(SecretKey) * * @param certificationLevel PGP密钥的证书等级 * @param keyPair 需要绑定的公私钥对 * @param id 需要绑定的ID * @param checksumCalculator 散列值计算器,用于计算私钥密码散列 * @param hashedPcks the hashed packets to be added to the certification.(先不管) * @param unhashedPcks the unhashed packets to be added to the certification.(也先不管) * @param certificationSignerBuilder PGP证书的生成器 * @param keyEncryptor 如果需要加密私钥,需要在这里传入私钥加密器 * @throws PGPException 一些PGP错误 */ public PGPSecretKey( int certificationLevel, PGPKeyPair keyPair, String id, PGPDigestCalculator checksumCalculator, PGPSignatureSubpacketVector hashedPcks, PGPSignatureSubpacketVector unhashedPcks, PGPContentSignerBuilder certificationSignerBuilder, PBESecretKeyEncryptor keyEncryptor)
生成完整的PGP密钥证书只需要PGPSecretKey这个的构造方法。后续获得publicKey只需要使用getPublicKey()
方法即可。
怎么从密钥对象中得到私钥呢?需要用extractPrivateKey()
方法,这个方法有一个参数,根据PGP的逻辑,这个参数一定是用来通过密文也就是代码中的passParse来解密PrivateKey内容的。方法如下:
//我们已经有了secretKey对象 PGPPrivateKey privateKey = secretKey.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder().setProvider("BC").build(passParse));
写完了,睡觉去~
One thought on “使用Bouncy Castle创建PGP密钥对”
谢谢,您的提供,万分感谢