バイト配列の OpenPGP 署名を実装しようとしています (文字列の場合もありますが、ソースが JSON であるため重要ではありません) が、Java BouncyCastle 実装から誤った出力が得られます。私は gnupg の --sign オプションを使用してテストしており、エミュレートしたいと考えています。使用例から変更したコードは次のとおりです。
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.SignatureException;
import java.util.Date;
import java.util.Iterator;
import org.bouncycastle.bcpg.BCPGOutputStream;
import org.bouncycastle.openpgp.PGPCompressedData;
import org.bouncycastle.openpgp.PGPCompressedDataGenerator;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPLiteralData;
import org.bouncycastle.openpgp.PGPLiteralDataGenerator;
import org.bouncycastle.openpgp.PGPPrivateKey;
import org.bouncycastle.openpgp.PGPSecretKey;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
import org.bouncycastle.openpgp.PGPSignature;
import org.bouncycastle.openpgp.PGPSignatureGenerator;
import org.bouncycastle.openpgp.PGPSignatureSubpacketGenerator;
import org.bouncycastle.openpgp.PGPUtil;
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder;
import org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
public class OpenPGP {
private static PGPSecretKey readSecretKey(final InputStream input)
throws IOException, PGPException {
final PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(
PGPUtil.getDecoderStream(input));
final Iterator keyRingIter = pgpSec.getKeyRings();
while (keyRingIter.hasNext()) {
final PGPSecretKeyRing keyRing = (PGPSecretKeyRing) keyRingIter
.next();
final Iterator keyIter = keyRing.getSecretKeys();
while (keyIter.hasNext()) {
final PGPSecretKey key = (PGPSecretKey) keyIter.next();
if (key.isSigningKey())
return key;
}
}
throw new IllegalArgumentException(
"Can't find signing key in key ring.");
}
public static byte[] sign(final byte[] data, final String key)
throws IOException, PGPException, SignatureException {
PGPSecretKey pgpSec;
pgpSec = readSecretKey(new ByteArrayInputStream(key.getBytes()));
PGPPrivateKey pgpPrivKey;
pgpPrivKey = pgpSec
.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder()
.setProvider("BC").build("".toCharArray()));
final PGPSignatureGenerator sGen = new PGPSignatureGenerator(
new JcaPGPContentSignerBuilder(pgpSec.getPublicKey()
.getAlgorithm(), PGPUtil.SHA1).setProvider("BC"));
sGen.init(PGPSignature.BINARY_DOCUMENT, pgpPrivKey);
@SuppressWarnings("rawtypes")
final Iterator it = pgpSec.getPublicKey().getUserIDs();
if (it.hasNext()) {
final PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
spGen.setSignerUserID(false, (String) it.next());
sGen.setHashedSubpackets(spGen.generate());
}
final PGPCompressedDataGenerator compressDataGenerator = new PGPCompressedDataGenerator(
PGPCompressedData.ZLIB);
final ByteArrayOutputStream out = new ByteArrayOutputStream();
final BCPGOutputStream bOut = new BCPGOutputStream(
compressDataGenerator.open(out));
sGen.generateOnePassVersion(false).encode(bOut);
final PGPLiteralDataGenerator lGen = new PGPLiteralDataGenerator();
OutputStream lOut;
lOut = lGen.open(bOut, PGPLiteralData.BINARY, "score.dat", new Date(),
data);
final InputStream fIn = new ByteArrayInputStream(data);
int ch;
while ((ch = fIn.read()) >= 0) {
lOut.write(ch);
sGen.update((byte) ch);
}
lGen.close();
sGen.generate().encode(bOut);
compressDataGenerator.close();
return out.toByteArray();
}
}
現在、sign 関数の結果は base64 でエンコードされ、URL に対して安全になり、適切な長さのように見えますが、メッセージをデコードすると無効になります。デコードされたものの例を次に示します。
0:
version: 3
signature_type: 0
hash_algorithm: 2
key_algorithm: 1
key_id: 4F65C291695F46BA
nested: 0
tag: 4
size: <NULL>
data: <NULL>
これは、古い php openpgp lib の私のポートから新しい標準へのきれいに印刷された PHP オブジェクトです。
\OpenPGP\Message::parse($message);
そこのkey_idは正しいですが、メッセージはgnupgが生成したメッセージとは大きく異なり、実際のデータが欠落しています:
0:
0:
version: 3
signature_type: 0
hash_algorithm: 2
key_algorithm: 1
key_id: 4F65C291695F46BA
nested: 1
tag: 4
size: <NULL>
data: <NULL>
1:
format: b
filename: data.txt
timestamp: 1400821038
tag: 11
size: 12
data: 1234567890
2:
version: 4
signature_type: 0
hash_algorithm: 2
key_algorithm: 1
hashed_subpackets:
0:
tag: 2
size: <NULL>
data: 1400821038
unhashed_subpackets:
0:
tag: 16
size: <NULL>
data: 4F65C291695F46BA
hash_head: 51977
trailer: S~�.�
tag: 2
size: <NULL>
data:
0: <long string of random characters>
私はこの問題についてかなりの検索を行いましたが、運がなかったので、アシスタントをいただければ幸いです。