介绍
最近和联通的数据生成系统对接需要使用PGP工具,网上查了资料,调了一整天终于出来了,下面介绍下使用方法以及碰到的一些的小坑
使用方法
依赖jar包
1 2 3 4 5 6 7 8 9 10 11 12 13 | <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> |
bcprov-jdk15on.jar 常用的加解密jar包,相信大家都很熟悉了,我们通过它来实现PGP加解密及生成公私钥对
生成公私钥对的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | public class PgpUtil { /** * 私有方法,用于生成指定位宽的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 = PgpUtil.generateKeyPair(rsaWidth_); //生成RSA密钥对 PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder().build().get(HashAlgorithmTags.SHA1); //使用SHA1作为证书的散列算法 /** * 用证书等级生成的认证,将公私钥对和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错误 */ 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) ); } @SuppressWarnings("restriction") public static void main(String[] args) throws Exception { Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); String passPhrase_ = "123456789"; char[] passPhrase = passPhrase_.toCharArray(); //将passPharse转换成字符数组 PGPSecretKey secretKey = PgpUtil.getSecretKey("wathdata", passPhrase_, 2048); // 这里打印私钥-------------重要 String privateKeyString = new BASE64Encoder().encode(secretKey.getEncoded()); System.out.println(privateKeyString); PGPPublicKey publicKey = secretKey.getPublicKey(); //FileOutputStream fileOutputStream = new FileOutputStream("c://1.txt"); byte[] encoded = publicKey.getEncoded(); // 这里打印公钥----------------重要 String publicKeyString = new BASE64Encoder().encode(encoded); System.out.println(publicKeyString); } } |
执行结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | 私钥-------------------- lQO+BF6MRCABCADGKYKqSOtysDV4TX1ubaOVVxJbQ2gIlm9J/S0qQcvkip2nX/zfrDnFLH7eJFk5 gVcBX9Vc9uearmGI6xRzp8rqsyhVL/Nbp6zOkCTrRvglSnfrqPa2f7hzlKU976Za9NMwJHU4X0Mp xTV6/fut3oYFU7uW/INoNc2NB65ajL0qzMP3MKX9k2OLhdHAB/4jsw9tUmTjr+2H5s+hLdpsq4cp CscrfZf+Q2BZ+1b6BFMrMnf6aFBpiwL18zF5RME45mdrfb7VfGQR0mn5UmY8EXNNOjORLTZ4PTOb y/VGBvMtOyJ++ggaRncrW9CNB1590A2CVy48Q7gNdVLFRmzPMCFjABEBAAH+AwMClr2r0h2iECpg u+OVyOCH/GDpWN1NJ4F2kW34B0JSfQBHREJ56tbX4BD6k79pxfid9nift8YKUCc8fF/pkJOVKDGp wcM66oinAfyYj4ZyLEY5l29FksEMD94YCZMU+Kcaz/hvO8WBC2a1MhIHzVwaNwIbKC3l0ZuW7qKM u1nMnaIeTJHZcHpNluwaHY0NGZXf8TcCwIbncu4AVWo9JU3CAaCILMyezi2Rpc/lKRAK9a4zMb5M PkXThDSUEFuLIxZYiJVncpGK1n65oxnrZvPIU8+Ha+yo2e+413J1/yyfwBfj0MhyCFpil99iibam tQZnwx9XNvszSsXvbK68I9PD28PDJth/uDIHABfceQfZOiSnRL6ZT8bZPkqONENt2+Ia4U+PuK8l FqA0flsOhOFb3Qnv/h8yRD+lFwscVWxfzwe8zvcoerotr87tjc0HNKNXLXQefWO9DV4iAt7O0vKI QWqgvheMIK3zMiqR9i2510Y+1PQIqWBjyZtxjRAo5XDCu1BJcnQEUV58l0X1YCsRNMv+UxaQPIos UnuiqLetrE7HC+Fxkv7DWkIeVAe/E7VExfwNiVFRdhnU3Djjp0IUEr9B6/CAQ4Kr6P9gLlN4UKV6 x8Wqz+/s2zAJj3bHNN884G71NnBnffb6iLIdv256D3Abfuo4y4ZwiVFs2URUfdKJmFEf9BngP5+A ITs1z01OwkmlEsESjMGhSsUayLlOGo1obCubUIlXUfd5UxGRN2fQKGA8UNXUKWL53FczHYozuJER 9n7Q/guex6u/nfVJyhZW7DSuNp41FYPs/4ychVHo9sa5biGJ8X4MilvRnNfcdkKplJQs/h7KF+7a aF+OrBN0H6kZAxwpfNjN28Um386zLjfTOYen6/b3oXNRknJ8ka53U3udq+cO2gCplLQId2F0aGRh dGGJARwEEAECAAYFAl6MRCAACgkQxq3anzI2L9BCKAgAsF58+UyC8RK8Rasuluj5yNtYvzTI9AdZ n5r18XjZ5PitodN9G3uq9nDKMogFb9l4Tl1r70oUNKu1QJ42mlDzMZ4icppaKjYARN7wIxFm/Mik R5WtnQ76qJPsyAN0aE0jhRGaadQ9J4rw/M7wEoQ2r/O9AfNpCpcs30VNihWvhB5uqiDup8AIKf4f yWSlH7dAKVbsrVWIjjdLuvSBFiu/LFP7V/Vn61WAmcVLhRWioWCfU8HbS0d14VKCpalTSuEaEY7+ PgBs1ThqyM+/n4QdKQcjpd2wqeDqQUb7SAuQ3/j91XuKNLXT/+YsuLPxT0mB0K1e8uBzUd3CmK/D lCkPCg== 公钥------------------- mQENBF6MRCABCADGKYKqSOtysDV4TX1ubaOVVxJbQ2gIlm9J/S0qQcvkip2nX/zfrDnFLH7eJFk5 gVcBX9Vc9uearmGI6xRzp8rqsyhVL/Nbp6zOkCTrRvglSnfrqPa2f7hzlKU976Za9NMwJHU4X0Mp xTV6/fut3oYFU7uW/INoNc2NB65ajL0qzMP3MKX9k2OLhdHAB/4jsw9tUmTjr+2H5s+hLdpsq4cp CscrfZf+Q2BZ+1b6BFMrMnf6aFBpiwL18zF5RME45mdrfb7VfGQR0mn5UmY8EXNNOjORLTZ4PTOb y/VGBvMtOyJ++ggaRncrW9CNB1590A2CVy48Q7gNdVLFRmzPMCFjABEBAAG0CHdhdGhkYXRhiQEc BBABAgAGBQJejEQgAAoJEMat2p8yNi/QQigIALBefPlMgvESvEWrLpbo+cjbWL80yPQHWZ+a9fF4 2eT4raHTfRt7qvZwyjKIBW/ZeE5da+9KFDSrtUCeNppQ8zGeInKaWio2AETe8CMRZvzIpEeVrZ0O +qiT7MgDdGhNI4URmmnUPSeK8PzO8BKENq/zvQHzaQqXLN9FTYoVr4Qebqog7qfACCn+H8lkpR+3 QClW7K1ViI43S7r0gRYrvyxT+1f1Z+tVgJnFS4UVoqFgn1PB20tHdeFSgqWpU0rhGhGO/j4AbNU4 asjPv5+EHSkHI6XdsKng6kFG+0gLkN/4/dV7ijS10//mLLiz8U9JgdCtXvLgc1Hdwpivw5QpDwo= |
文件加解密
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 | /** * PGP加解密文件 * @author zhibin.wang * */ public class KeyBasedFileProcessorKey { /** * * @param inputFileName 要解密的文件名 * @param key 私钥 * @param passwd 私钥解密key * @param defaultFileName 输出解密的文件 * @throws IOException * @throws NoSuchProviderException */ public static void decryptFile( String inputFileName, String key, char[] passwd, String defaultFileName) throws IOException, NoSuchProviderException { InputStream in = new BufferedInputStream(new FileInputStream(inputFileName)); byte[] decode = Base64.getDecoder().decode(key); decryptFile(in, decode, passwd, defaultFileName); in.close(); } /** * * decrypt the passed in message stream * */ private static void decryptFile( InputStream in, byte[] keyIn, char[] passwd, String defaultFileName) throws IOException, NoSuchProviderException { in = PGPUtil.getDecoderStream(in); try { JcaPGPObjectFactory pgpF = new JcaPGPObjectFactory(in); PGPEncryptedDataList enc; Object o = pgpF.nextObject(); // // the first object might be a PGP marker packet. // if (o instanceof PGPEncryptedDataList) { enc = (PGPEncryptedDataList) o; } else { enc = (PGPEncryptedDataList) pgpF.nextObject(); } // // find the secret key // Iterator it = enc.getEncryptedDataObjects(); PGPPrivateKey sKey = null; PGPPublicKeyEncryptedData pbe = null; PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection( keyIn, new JcaKeyFingerprintCalculator()); while (sKey == null && it.hasNext()) { pbe = (PGPPublicKeyEncryptedData) it.next(); sKey = PGPExampleUtil.findSecretKey(pgpSec, pbe.getKeyID(), passwd); } if (sKey == null) { throw new IllegalArgumentException("secret key for message not found."); } InputStream clear = pbe .getDataStream(new JcePublicKeyDataDecryptorFactoryBuilder().setProvider("BC").build(sKey)); JcaPGPObjectFactory plainFact = new JcaPGPObjectFactory(clear); Object message = plainFact.nextObject(); if (message instanceof PGPCompressedData) { PGPCompressedData cData = (PGPCompressedData) message; JcaPGPObjectFactory pgpFact = new JcaPGPObjectFactory(cData.getDataStream()); message = pgpFact.nextObject(); } if (message instanceof PGPLiteralData) { PGPLiteralData ld = (PGPLiteralData) message; String outFileName = ld.getFileName(); if (outFileName.length() == 0) { outFileName = defaultFileName; } else { /** * * modify 20160520 * * set fileName * * 不同的系统可能源文件的包含的路径信息不同。 * */ String separator = ""; if (outFileName.contains("/")) { separator = "/"; } else if (outFileName.contains("\")) { separator = "\"; } String fileName = outFileName.substring(outFileName.lastIndexOf(File.separator) + 1); // String defseparator = ""; if (defaultFileName.contains("/")) { defseparator = "/"; } else if (defaultFileName.contains("\")) { defseparator = "\"; } defaultFileName = defaultFileName.substring(0, defaultFileName.lastIndexOf(defseparator)); outFileName = defaultFileName + File.separator + fileName; } InputStream unc = ld.getInputStream(); OutputStream fOut = new BufferedOutputStream(new FileOutputStream(outFileName)); Streams.pipeAll(unc, fOut); fOut.close(); } else if (message instanceof PGPOnePassSignatureList) { throw new PGPException("encrypted message contains a signed message - not literal data."); } else { throw new PGPException("message is not a simple encrypted file - type unknown."); } if (pbe.isIntegrityProtected()) { if (!pbe.verify()) { System.err.println("message failed integrity check"); } else { System.err.println("message integrity check passed"); } } else { System.err.println("no message integrity check"); } } catch (PGPException e) { System.err.println(e); if (e.getUnderlyingException() != null) { e.getUnderlyingException().printStackTrace(); } } } /** * * @param outputFileName 输出的加密文件名 2.pgp * @param inputFileName 输入的要加密的文件 * @param encryKey 公钥 * @param armor true * @param withIntegrityCheck true * @throws IOException * @throws NoSuchProviderException * @throws PGPException */ public static void encryptFile( String outputFileName, String inputFileName, String encryKey, boolean armor, boolean withIntegrityCheck) throws IOException, NoSuchProviderException, PGPException { OutputStream out = new BufferedOutputStream(new FileOutputStream(outputFileName)); Decoder decoder = Base64.getDecoder(); byte[] decode = decoder.decode(encryKey); PGPPublicKey encKey = PGPExampleUtil.readPublicKey(decode); encryptFile(out, inputFileName, encKey, armor, withIntegrityCheck); out.close(); } private static void encryptFile( OutputStream out, String fileName, PGPPublicKey encKey, boolean armor, boolean withIntegrityCheck) throws IOException, NoSuchProviderException { if (armor) { out = new ArmoredOutputStream(out); } try { byte[] bytes = PGPExampleUtil.compressFile(fileName, CompressionAlgorithmTags.ZIP); PGPEncryptedDataGenerator encGen = new PGPEncryptedDataGenerator( new JcePGPDataEncryptorBuilder(PGPEncryptedData.CAST5).setWithIntegrityPacket(withIntegrityCheck) .setSecureRandom(new SecureRandom()).setProvider("BC")); encGen.addMethod(new JcePublicKeyKeyEncryptionMethodGenerator(encKey).setProvider("BC")); OutputStream cOut = encGen.open(out, bytes.length); cOut.write(bytes); cOut.close(); if (armor) { out.close(); } } catch (PGPException e) { System.err.println(e); if (e.getUnderlyingException() != null) { e.getUnderlyingException().printStackTrace(); } } } public static void main( String[] args) throws Exception { String keyString = "mQENBF6MQAIBCACrMsize7pLL99P/r6SZc793tbQ6bwNlgPsMv4l+Yl0uD2AHaslg8/5BWNeIjzq" + "0xL0W4+8oWHCOw68Xw5a4ah8zFhkXM92iTeGb6zivTBrLOGGD+8wJRLALKke6/c9YZTqAxUFbIxf" + "0p9MuQLv2IQYDRr017N8q0bYN1tRz1sebEjvJ8noSkCEopkYIQ+vD6w2wOyN4bKHCa16qgM7S88D" + "/QjPviYWrXkVr1AdMmzo4NGMs4yqRFxeGMhHPAf3Z0vuWJJssdyC1wcB3qnj9vtM2vxBJlhAYTdx" + "C4WbB5eAXPZmBFWZ+Wb0CJaOxeCVpVHAJgTUjsRH7X3iZ0/a/EfbABEBAAG0CHdhdGhkYXRhiQEc" + "BBABAgAGBQJejEACAAoJEMKE0EVeprn3fG4H/0G4Fp3GZmAYfLNgcxqLxMFLFPxSdft+6NE8mOmK" + "DuKdsiHYcOpdBvm4YUeB9qyZGDeGHvRY3VzzDXU7QMD6/OXKZ3sDfcTcy0Cr2O1y7JNIJzC91cZ9" + "kroP4p0tmcwSRGlo+BI7G5oDXSM/pf05+8JE55nXh8uQ0MaYy/wxyfp2EDeLj2FMFjFuW112a00K" + "T1XzMqZ43Ubdsqe3sshiGFTA4tG3tQQh1sAjF6NLMnAo/pxzekcGB8RzkucW0M99IAmmhMksHPnH" + "wQ3wKl8NAkJJXyXTmQtQ6/jbJ+fsdIj/FJNgpc5+pEbS+vUxkOUHXs2wTQ5y0Fag7R52Ps1MO3M="; String privateKeyString = "lQO+BF6MQAIBCACrMsize7pLL99P/r6SZc793tbQ6bwNlgPsMv4l+Yl0uD2AHaslg8/5BWNeIjzq" + "0xL0W4+8oWHCOw68Xw5a4ah8zFhkXM92iTeGb6zivTBrLOGGD+8wJRLALKke6/c9YZTqAxUFbIxf" + "0p9MuQLv2IQYDRr017N8q0bYN1tRz1sebEjvJ8noSkCEopkYIQ+vD6w2wOyN4bKHCa16qgM7S88D" + "/QjPviYWrXkVr1AdMmzo4NGMs4yqRFxeGMhHPAf3Z0vuWJJssdyC1wcB3qnj9vtM2vxBJlhAYTdx" + "C4WbB5eAXPZmBFWZ+Wb0CJaOxeCVpVHAJgTUjsRH7X3iZ0/a/EfbABEBAAH+AwMCV9cV6pssqM1g" + "DSvDGApI59SQilmCijhWSJvEUwksqvMjyeiHjDvLmrxMpsnzWe7vSK1xABpph5A/HkVhQK3B+P8j" + "MkI4kTiiFFcJ6ZpbjiBN/A8xgnHYdimXXsPe2lsZVAzQOS2NvQ56nRwtW1EKa2++X66u6syu3DzO" + "9yqtfKzn7+oyWAsLu7xO5nYJQGZZJTIKZi3B9nR6Q8gpQ3qgFVEmQzF6x4MRypOH/TasspWnxV7Y" + "0zXl6CU7KXpIBfakfslOI1mPK1LycduWugxkLhkGngwFTH60HnB5hziAWyEmh1VJUHnoOERMBRtM" + "rFFyPR3ZKUBGDFm8dpBAgXEvow0dXhurTS3SEUkw5vEAa/0M1YB9TxQyGsIP9PMtI+TqBc9CS+xA" + "X+Ls6forCLWykjxPaEKDafH4F8dumrNvLYHWtBI/XAwwmTelhMSQcLCH5pF1PM4Svn9DoPchXp3A" + "BMVfcr66BStNuz35L5IW6UHNOYQHQMKjySU76yrXwn476ri0SYKp8+x1EQZuUK+T5zI2RvMLZa/8" + "EhWT79EoIXUjHQbo7vjTRsmoboLNq3lfd6OUcQf8tB+2+QQkMHWH4Ew0VTxpaUfc4NpjVvxoneig" + "qwnL8xFgtznEFAtiMqLWzbnTM+Fsy0EL3y0nQvYkl+4qJ+pwBdT2588zff8tCkAPqyd2KAD5e2pG" + "GfIaKtAjrcZ0OQOZy5GkwP7DJIptKcjCZBHmrV6wLdHCNqg8+29dxJHjSDMS+COMNEDjECoPIcWY" + "1K6VTzZqOqYxOuqJK79nVIIL7lkrYn1Sr4j7jLi4RqtGPEiVURPsfoCqHlZ0mQskztIvmF6dokOU" + "rlz46ad6kJ5B16zck1Ubk7MSrbsWoJN08WvNKn5nzgpyxecpmaX3Z4DcPTWl1fHdb7QId2F0aGRh" + "dGGJARwEEAECAAYFAl6MQAIACgkQwoTQRV6mufd8bgf/QbgWncZmYBh8s2BzGovEwUsU/FJ1+37o" + "0TyY6YoO4p2yIdhw6l0G+bhhR4H2rJkYN4Ye9FjdXPMNdTtAwPr85cpnewN9xNzLQKvY7XLsk0gn" + "ML3Vxn2Sug/inS2ZzBJEaWj4EjsbmgNdIz+l/Tn7wkTnmdeHy5DQxpjL/DHJ+nYQN4uPYUwWMW5b" + "XXZrTQpPVfMypnjdRt2yp7eyyGIYVMDi0be1BCHWwCMXo0sycCj+nHN6RwYHxHOS5xbQz30gCaaE" + "ySwc+cfBDfAqXw0CQklfJdOZC1Dr+Nsn5+x0iP8Uk2Clzn6kRtL69TGQ5QdezbBNDnLQVqDtHnY+" + "zUw7cw=="; Security.addProvider(new BouncyCastleProvider()); encryptFile("c://2.pgp", "c://2.txt", keyString, true, true); // 加密文件 decryptFile("c://2.pgp", privateKeyString, "123456789".toCharArray(), "c://3.txt");// 解密文件 } } |
大家可以直接拿来使用上面的代码,文件加解密和公私钥对生成都已经提供测试方法
并且上面的方法已经通过了PGP Desktop工具验证