1

バイト配列の 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>

私はこの問題についてかなりの検索を行いましたが、運がなかったので、アシスタントをいただければ幸いです。

4

0 に答える 0