JavaのBouncy Castle Cryptography Libraryを使用してPGPデジタル署名を操作する

このガイドでは、Web開発での使用に重点を置いて、Bouncy Castle Cryptography Libraryを使用してJavaでOpenPGPを操作する方法を説明します。



画像



回路のソースへのリンク



PGP / OpenPGP



OpenPGPは RFC 4880に記載されており、デジタル署名およびメッセージ暗号化を扱うための公開鍵暗号化システムの最も一般的な標準です 。 無料およびオープンソースのものを含む多くのプログラムとライブラリでサポートされています。 特に、 GnuPGKleopatra 、Windows Gpg4win用のユーティリティセット(GnuPG、Kleopatraなどを含む)、Thunderbird Enigmailの拡張機能に注意する必要があります。

Windowsの場合、PGP Desktopとしても知られる商用のSymantec Endpoint Encryptionパッケージ( 試用版が利用可能になり、期間終了後も非商用目的で引き続き使用できます)およびSymantec Encryption Familyのその他の製品にも注意を払う必要があります。



詳細については、「 公開キー暗号化とPGPの概要」 、「 PGPエンジン 」を参照してください。



弾む城の暗号ライブラリ



Bouncy Castle Cryptography Libraryは現在、Androidで使用されているJavaで最も使用されている暗号化ライブラリです。

これはオープンソースプロジェクトです(GitHub: github.com/bcgit/bc-java )。 また、このトピックで興味深いのは、オープンソースプログラムPortable PGP vです。 Bouncy Castleを使用してJavaで記述された1.x: sourceforge.net/p/ppgp/code



OpenPGPを使用するために、Bouncy Castleには別のパッケージorg.bouncycastle.openpgpがあり 、これを使用します。



公開鍵を読む



解決すべきタスク:ASCII装甲公開PGPキーブロック(公開キー)を文字列として読み取り 、BCの公開キーを表すorg.bouncycastle.openpgp.PGPPublicKeyオブジェクトを作成します。



ASCII装甲形式は、テキスト形式のキーを表します。これは、サイトでの公開、電子メールによる送信などに使用すると便利です。

-----BEGIN PGP PUBLIC KEY BLOCK----- Version: GnuPG v2.0.22 (GNU/Linux) mQINBFZpf0wBEADo7NZ4Oymw2pVJMfrNEhGwYOT4CGMOTZHQo3rYFrN3yxCsd/xX r8kWLvkKvEFSD0XfQlq6slA9fnOtsRZl4JlmabKC33ZkB1zhV2c78AhhVMrfFi2a 114xHhOHkR4LOv8mAyyRKd5mpuyYpPKcF2670jXxANeqNQCoKKM/dPS1uxGapE9Z GG0GFKvIUqKWJUAv7JqOAxtXbAS7JFMwiH16jL/TeuvKy+0JKvlBM4qxB9S18hi4 GYg1SEATqmeu9E+6alz0L25REYYZZOMja1quF8HywsRY0fSZqCbD+9diP0keAg6z PSDSlgDF4WBUi+c8PoXcRRZq7+XYgky4l8wfGoGnOZKA4GH2SMlNAX8jCIrC7Cpf KPCu6NMY533X735Md6fnWOeuyxz4owPRb6OTt4rYiA3/9vCu/waZ1zZx/wATYORS 1wmOx8ZjogeAPOz6a2PW8hrK0tWbT3ILucC7dxjYfdKHZX2+v3eMGvXFRKss8J5i E5rlJiDnAMoERmIJunh/EJHz4te+RdMy2jWeDQWGzaFyZC92SUo9tAUJk7xez0KX 5sYzhXjFJX/17DwFBTXIOYpFjWUyPaQaP7ByWOjZzhCmQxYRBUJSoxOty1ngkZ+B 7zAZSTXh2mukHukRERG1//2FsiBZeapRhAaFWdWnPDN95bg7L7/qQ5szjQARAQAB tDdWaWt0b3IgQWdleWV2IDxhZ2V5ZXZAaW50ZXJuYXRpb25hbC1hcmJpdHJhdGlv bi5vcmcudWs+iQI/BBMBAgApBQJWaX9MAhsvBQkB4lLUBwsJCAcDAgEGFQgCCQoL BBYCAwECHgECF4AACgkQzjaf2edxc+UywQ/+MfYX5BRzl7iSndhr/vVOEycxZntu 9efMhwQYO87EXT/cNpRMX/u2Wzhx70brzFIenvaYTPpVkYKinKv3iEAauJ1wr5/a PrUxRcfVnBrV8ecWTO6SbNRDePqayst8bBq9rdqnKnpDEv911zk2hjJtCeFDlUkO eiTLgYCVOQ7n0fbN4pjrBGAqDGs2SFjJXAKYJpZqY77P0crHxXCMyukrdj2WxnB7 JyMdmBqViJSo/MCi7SFXqVQFTvJZVBhTQEUO5KNJA6oAYztYKXBE3AybE528m571 p+HhJ2mOnlNaRu5y12RRQJ7qmKvN9uzHz0+mt8rRk3oYWCYImTMwxDpc1mT39QKs 0WS/zp5NTIaa+Hvt7V8GH5hmq67YL+JcxEINZGZ+MZmiSKuvGVuqC8ZJpswumVw5 PHtMEL+0zBxZXN41YyfTudssXbvMrNiGIdlQA7CW/7yMviVR4nyQtFQJwYSL4mva uTQSnihm4Bj6FeYpgGpk1TyIzgtIyaQNSvnlDYFezmN/JsAs+25EP/oxyFLaK+ij WdjVmnsDGS4l5BWH/a8BYPbSnm7YrlYkYCXjTjK1/EeWA/tggApISFptc8YQw0Wp Qw0IwhJVPWDVW8nDrv/1IPhTJgYfIfdmxr32RLhNePEZGZ02zfCP9BrlNKut9/Hn x1yKWjVaWZO8VtU= =XyhJ -----END PGP PUBLIC KEY BLOCK-----
      
      





このフォームでは、公開キーをWebフォームに送信できます。 サーバー上のキーからデータを抽出し、ユーザーに返し(公開キー認識サービス)、データベースに保存できるコードを記述します。 BCにPGPPublicKeyクラスがあり、タスクはString入力を使用してこのクラスの新しいオブジェクトを作成し、このクラスが提供するメソッドを使用してキーデータを取得することです。



org.bouncycastle.openpgp.examplesパッケージにはPGPExampleUtilクラスが含まれていますが、パブリックではないためインポートできませんが、そのコードを使用して同様のクラスを作成できます。 基礎として使用できるPGPExampleUtilのメソッド:

 /** * A simple routine that opens a key ring file and loads the first available key * suitable for encryption. * * @param input data stream containing the public key data * @return the first public key found. * @throws IOException * @throws PGPException */ static PGPPublicKey readPublicKey(InputStream input) throws IOException, PGPException { PGPPublicKeyRingCollection pgpPub = new PGPPublicKeyRingCollection( PGPUtil.getDecoderStream(input), new JcaKeyFingerprintCalculator()); // // we just loop through the collection till we find a key suitable for encryption, in the real // world you would probably want to be a bit smarter about this. // Iterator keyRingIter = pgpPub.getKeyRings(); while (keyRingIter.hasNext()) { PGPPublicKeyRing keyRing = (PGPPublicKeyRing)keyRingIter.next(); Iterator keyIter = keyRing.getPublicKeys(); while (keyIter.hasNext()) { PGPPublicKey key = (PGPPublicKey)keyIter.next(); if (key.isEncryptionKey()) { return key; } } } throw new IllegalArgumentException("Can't find encryption key in key ring."); }
      
      





portablepgp.core.KeyRingでは、同様の問題が次のように解決されます。

  public static PGPPublicKeyRing importPublicKey(InputStream iKeyStream) throws IOException { PGPPublicKeyRing newKey = new PGPPublicKeyRing(new ArmoredInputStream(iKeyStream)); pubring = PGPPublicKeyRingCollection.addPublicKeyRing(pubring, newKey); savePubring(); return newKey; }
      
      





PGPPublicKeyRingから(最初の)PGPPublicKeyを1つだけ削除する必要があるという仮定に基づいて、単に.getPublicKey()を使用し、イテレータを使用しません(String入力では、メソッドはorg.bouncycastle.openpgp.PGPPublicKeyを返します)。

  public static PGPPublicKey importPublicKey (String armoredPublicPGPkeyBlock) throws IOException { InputStream in = new ByteArrayInputStream(armoredPublicPGPkeyBlock.getBytes()); PGPPublicKeyRing pgpPublicKeyRing = new PGPPublicKeyRing(new ArmoredInputStream(in), new JcaKeyFingerprintCalculator()); in.close(); PGPPublicKey pgpPublicKey = pgpPublicKeyRing.getPublicKey(); return pgpPublicKey; }
      
      





または、org.bouncycastle.openpgp.examples.PGPExampleUtilからreadPublicKeyメソッドをクラスに完全にコピーし、次のメソッドでクラスを補足することができます。

  public static PGPPublicKey readPublicKeyFromString (String armoredPublicPGPkeyBlock) throws IOException, PGPException { InputStream in = new ByteArrayInputStream(armoredPublicPGPkeyBlock.getBytes()); PGPPublicKey pgpPublicKey = readPublicKey(in); in.close(); return pgpPublicKey; }
      
      





キーデータ表示



org.bouncycastle.openpgp.PGPPublicKeyオブジェクトに基づいて、人が読み取ったりデータベースに保存したりできるキーデータの表現を作成します。



読み取り可能な形式で公開キーデータを表す最も単純なバージョンの場合、 portablepgp.core.PrintablePGPPublicKeyクラスをtoString()メソッドとともに使用できます。

 package portablepgp.core; import java.util.Iterator; import org.bouncycastle.openpgp.PGPPublicKey; /** * * @author Primiano Tucci - http://www.primianotucci.com/ */ public class PrintablePGPPublicKey { PGPPublicKey base; public PrintablePGPPublicKey(PGPPublicKey iBase){ base = iBase; } public PGPPublicKey getPublicKey(){ return base; } @Override public String toString() { StringBuilder outStr = new StringBuilder(); Iterator iter = base.getUserIDs(); outStr.append("[0x"); outStr.append(Integer.toHexString((int)base.getKeyID()).toUpperCase()); outStr.append("] "); while(iter.hasNext()){ outStr.append(iter.next().toString()); outStr.append("; "); } return outStr.toString(); } }
      
      





キーに関するより完全な情報を保存するには、org.bouncycastle.openpgp.PGPPublicKeyからデータを抽出するコンストラクターでPGPPublicKeyDataクラスを作成します。

 import com.google.common.base.Splitter; import com.google.gson.Gson; import org.bouncycastle.openpgp.PGPPublicKey; import javax.xml.bind.DatatypeConverter; import java.util.Date; import java.util.Iterator; import java.util.List; public class PGPPublicKeyData { String keyID; String userID; String firstName; String lastName; String userEmail; Date created; Date exp; int bitStrength; String asciiArmored; String fingerprint; public PGPPublicKeyData(PGPPublicKey pgpPublicKey) { // keyID StringBuilder keyIDstrBuilder = new StringBuilder(); keyIDstrBuilder.append("[0x"); keyIDstrBuilder.append(Integer.toHexString((int) pgpPublicKey.getKeyID()).toUpperCase()); keyIDstrBuilder.append("] "); this.keyID = keyIDstrBuilder.toString(); // userID StringBuilder userIDstrBuilder = new StringBuilder(); Iterator userIDsIterator = pgpPublicKey.getUserIDs(); while (userIDsIterator.hasNext()) { userIDstrBuilder.append(userIDsIterator.next().toString()); userIDstrBuilder.append("; "); } this.userID = userIDstrBuilder.toString(); // user's first and last name and email List<String> userIdList = Splitter.on(' ').trimResults().omitEmptyStrings().splitToList(userID); this.firstName = userIdList.get(0); this.lastName = userIdList.get(1); String userEmailDirty = userIdList.get(userIdList.size() - 1); this.userEmail = userEmailDirty.substring( 1, userEmailDirty.length() - 2 ); // fingerprint // [0xE77173E5] this.fingerprint = DatatypeConverter.printHexBinary( pgpPublicKey.getFingerprint() ); // creation date this.created = pgpPublicKey.getCreationTime(); // exp date this.exp = org.apache.commons.lang3.time.DateUtils.addSeconds(created, (int) pgpPublicKey.getValidSeconds()); // Bit strength this.bitStrength = pgpPublicKey.getBitStrength(); } public String toJSON() { Gson gson = new Gson(); return gson.toJson(this); } // ---------- Getters and Setters: }
      
      







続く



All Articles