Bouncy CastleでOpenPGP鍵を操作する

Bouncy CastleのOpenPGP用ライブラリ(bcpg)を使ってOpenPGP鍵を操作する方法のメモです。以前の日記にsecring.gpgを読み込んで利用する方法がありますので、今回はそれ以外の操作が対象です。

PGPSecretKeyを生成する

public PGPSecretKey generateSecretKey() {
	// JCEでの一般的な鍵生成
	KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA", "BC");
	keyPairGenerator.initialize(2048);
	KeyPair keyPair = keyPairGenerator.generateKeyPair();

	// PGPSecretKeyの生成
	return new PGPSecretKey(
		PGPSignature.DEFAULT_CERTIFICATION,
		PublicKeyAlgorithmTags.RSA_SIGN,       // 鍵のアルゴリズムと用途
		keyPair.getPublic(),         // PublicKeyとPrivateKeyの
		keyPair.getPrivate(),        //   ペアを指定
		new Date(),                  // 鍵の生成日時
		"user@example.com",          // ユーザID
		SymmetricKeyAlgorithmTags.AES_256,    // 鍵を保護する際に使用する暗号
		"passphrase".toCharArray(),  // 鍵を保護する際に使用するパスフレーズ
		null,                        // 鍵に付与する属性
		null,                        // 鍵に付与する属性
		new SecureRandom(),
		"BC");

公開鍵への署名を作成する

/**
 * @param targetKey 署名対象の鍵
 * @param userId    署名対象のユーザID
 * @param signKey   署名する人の鍵
 */
public PGPSignature makeSignature(PGPPublicKey targetKey, String userID, PGPPrivateKey signKey) {
	PGPSignatureGenerator generator = new PGPSignatureGenerator(
		PublicKeyAlgorithmTags.RSA_SIGN, // 署名に利用する鍵(signKey)のアルゴリズム
		HashAlgorithmTags.SHA256,        // 署名に利用するハッシュアルゴリズム
		"BC");
	generator.initSign(PGPSignature.CASUAL_CERTIFICATION, signKey);
	return generator.generateCertification(userID, targetKey);
}

公開鍵に署名を追加する

先ほど作成した署名を公開鍵(PGPPublicKey)に追加する方法です。

// PGPPublicKey publicKey;
// PGPSignature signature;
//
publicKey = PGPPublicKey.addCertification(publicKey, signature);

bcpgでは、このように既存のオブジェクトにデータを追加した新しいオブジェクトを作成するstaticなメソッドが沢山あります。例えばPGPPublicKeyRingへのPGPPublicKeyの追加も同様の方法になります。

// PGPPublicKeyRing keyRing;
// PGPPublicKey publicKey;
//
keyRing = PGPPublicKeyRing.insertPublicKey(keyRing, publicKey);

保存と読込

バイナリ形式の場合

// PGPPublicKeyRing keyRing;
//
FileOutputStream fos = new FileOutputStream("pubring.gpg");
keyRing.encode(fos);
fos.close();

テキスト形式の場合(テキスト形式は BEGIN PGP でおなじみのやつです。)

// PGPPublicKeyRing keyRing;
//
FileOutputStream fos = new FileOutputStream("pubring.gpg");
ArmoredOutputStream os = new ArmoredOutputStream(fos);
keyRing.encode(os);
os.close();

こちらは読込方法です。以前とあまり変わりませんが、PGPUtil.getDecoderStream()を使うことで、テキスト形式とバイナリ形式の両方に対応しています。

FileInputStream fis = new FileInputStream("secring.gpg");
InputStream is = PGPUtil.getDecoderStream(fis); // ファイル形式を判断して適切なInputStreamを返す
PGPSecretKeyRing keyRing = new PGPSecretKeyRing(is);
is.close();

これ以外のクラスも基本的に、encodeで保存、コンストラクタでbyte[]もしくはInputStreamから読込という形式になります。