2017-08-17 20 views
1

BouncyCastleで暗号化したGnuPGを使用してメッセージを復号しようとすると、2つのgpg: [don't know]: invalid packet (ctb=xx)メッセージが表示され、復号化に失敗します。BouncyCastlePGPで暗号化されたメッセージをgpg-decryptできません

$ gpg --gen-key 
gpg (GnuPG) 2.0.30; Copyright (C) 2015 Free Software Foundation, Inc. 
This is free software: you are free to change and redistribute it. 
There is NO WARRANTY, to the extent permitted by law. 

Please select what kind of key you want: 
    (1) RSA and RSA (default) 
    (2) DSA and Elgamal 
    (3) DSA (sign only) 
    (4) RSA (sign only) 
Your selection? 1 
RSA keys may be between 1024 and 4096 bits long. 
What keysize do you want? (2048) 
Requested keysize is 2048 bits 
Please specify how long the key should be valid. 
     0 = key does not expire 
     <n> = key expires in n days 
     <n>w = key expires in n weeks 
     <n>m = key expires in n months 
     <n>y = key expires in n years 
Key is valid for? (0) 0 
Key does not expire at all 
Is this correct? (y/N) y 

GnuPG needs to construct a user ID to identify your key. 

Real name: Foo Bar 
Email address: [email protected] 
Comment: Test Key 
You selected this USER-ID: 
    "Foo Bar (Test Key) <[email protected]>" 

Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O 
You need a Passphrase to protect your secret key. 

We need to generate a lot of random bytes. It is a good idea to perform 
some other action (type on the keyboard, move the mouse, utilize the 
disks) during the prime generation; this gives the random number 
generator a better chance to gain enough entropy. 
We need to generate a lot of random bytes. It is a good idea to perform 
some other action (type on the keyboard, move the mouse, utilize the 
disks) during the prime generation; this gives the random number 
generator a better chance to gain enough entropy. 
public and secret key created and signed. 

pub 2048R/79CC322A 2017-08-17 
     Key fingerprint = 93B9 0D06 08D2 EB84 9F83 4CD3 A470 748E 79CC 322A 
uid  [ unknown] Foo Bar (Test Key) <[email protected]> 
sub 2048R/21B41E21 2017-08-17 
$ 

2) PGP公開鍵を:私は次のようにGPGを使用してPGPキーが生成された

1詳細BouncyCastle 1.54gpg (GnuPG) 2.0.30 on OSX

を使用しています

asc形式でエクスポートされます:

-----BEGIN PGP PUBLIC KEY BLOCK----- 
Version: GnuPG v2 

mQENBFmWE88BCADB+esy+D2Zobru86ztUTp7hWyDy5w9B2iHlyORLI6mQ0JH+ya6 
cbaO9nWT7WC68l1ocWaeak0t/9hx0CDWv6zdAXfEUPu8qB53M4m1NACDJp3UDeQS 
UytmpB/kutViUO+yiRhtezYsFP70PHOO7o9Tgze5H/qF/hgAVmk1/eN4oSTH4hqo 
VIvlsvTNZYLt+a2wYN0RPPryfXnvrKOSXdE5roQd/TMaMwwd2Mbhhh31IB1ROw2/ 
I+tvJfrM4zLseuo0ndYmWL7ZfjPslsFUezUQf5BDmFdIi9M3/UWHtHmSR6GGG1ko 
uo0XjABiIjwfj1mQSA3txI1yO+RLHYrI5UL1ABEBAAG0IEZvbyBCYXIgKFRlc3Qg 
S2V5KSA8Zm9vQGJhci5jb20+iQE5BBMBCAAjBQJZlhPPAhsDBwsJCAcDAgEGFQgC 
CQoLBBYCAwECHgECF4AACgkQpHB0jnnMMipk+Qf/cKLSdv+aYHKteS/rtAXQbRWG 
5nEGKk8vU5HseESr9tDbzkMpruYXtGG99GjPjZO2NqoYF+3NzD6suiQzP95dHyH0 
g3i2AHLoyd7W9VvZEieH7vGRrUjYYP2N/qifUepdiu3gKQLHDBE14tXRHEfTN5WV 
BxClZ4MwmMvHzsg6NB2RXJb7t5e9apgQ/+0O9l5LwGsSSkCQr53OmoMSUnQP0lrz 
gqMxzbC6sI/FYaVaoMGnAUMFQ+8l7nI/Tv6R/sCN5d4egcIC1AzVcDE+zGkwRrmX 
4lcKen0XvolJfpUNx9D2CIAQttz0nvygxjBAByXT4oFcbPw9GZCNmxKo/eUp4LkB 
DQRZlhPPAQgAz4tebylTFXZCj4xwzy7wyrw4J+vUkMrOh5tOVgISPMaEiDBzFyhf 
oqs0uAamImUyF2HGVGXEGappZncjrympdYFpDXG6jb0oYap03hheli1R6h+56PNq 
zNyVzlfq85BqgVa5Qed1VnDbEz29JMjLwSvCEY3V0SIOgVZxE5GfMjvAkUhPoE+o 
T5uVuRUlnfdKXMYgNRh5gbNEsvx+PMGihC3pSrWWYbBtU6otNXCVCYQryORaHWAf 
pvB99P6YzP0nc6Dbu2ZSiGsDAQwa3ZCow+E997upf22WMfowwkNFtarnrr1fVLkl 
exR28nJdeAbh0R3WpgQJqeCGmH9fYQEBjwARAQABiQEfBBgBCAAJBQJZlhPPAhsM 
AAoJEKRwdI55zDIqgAAH/39teAauUrB+xEVr/Q+McXa0PQSrErB2P4jaVIBuZH2/ 
6EeRycp6bIwc5R/gpkIVcPg8DmDYtobRbj2YDc5o+4tPVgSKJUgOB2l9CryP+aCm 
lx8R0nCN8q53vqtmm7LYc+W1K6tXQJZi8VbCC9sLGUxH0HuDP2ldcBnrialV2cLZ 
zsxRgoFF3f8u/We97z2qwzRQXshvw4GVL3wSs511mTcOZW8LnO1YMt3m5ABIsZN0 
P/avr7zEqsvr0iJOQ7WbJLbgHkxKu03SfcN0XfVDX4VzqykLvn9THHVtofU6h4LE 
LoIRKGg57DXFrsc93a1GWzN9z764sXQ7JgWqnW6a72g= 
=n8OZ 
-----END PGP PUBLIC KEY BLOCK----- 

3) PGP公開鍵は、その "PUBLIC KEY BLOCK" - 体に渡され、次のように解決される: (pgpKeyBytesは、キーの文字列表現のUTF-8バイトの符号化されています)

private byte[] encryptKeyBytes(byte[] keyBytes, byte[] pgpKey) throws GeneralSecurityException { 
    ByteArrayOutputStream encKeyBytes = new ByteArrayOutputStream(keyBytes.length); 

    try (Handle<SecureRandom> randomHandle = RngSupport.getRandom()) { 
    JcePGPDataEncryptorBuilder encryptorBuilder = 
     new JcePGPDataEncryptorBuilder(PGPEncryptedDataGenerator.AES_256); 
    encryptorBuilder.setWithIntegrityPacket(true); 
    encryptorBuilder.setSecureRandom(randomHandle.getObject()); 
    encryptorBuilder.setProvider("BC"); 

    PGPEncryptedDataGenerator encryptor = new PGPEncryptedDataGenerator(encryptorBuilder); 
    try { 
     JcePublicKeyKeyEncryptionMethodGenerator keyEncryptionMethodGenerator = 
      new JcePublicKeyKeyEncryptionMethodGenerator(resolvePgpPublicKey(pgpKey)); 
     keyEncryptionMethodGenerator.setProvider("BC"); 
     encryptor.addMethod(keyEncryptionMethodGenerator); 
     try (
      OutputStream ao = new ArmoredOutputStream(encKeyBytes); 
      OutputStream eo = encryptor.open(ao, keyBytes.length)) { 
     eo.write(BytesSupport.encodeHex(keyBytes).getBytes(StandardCharsets.UTF_8)); 
     } 
    } catch (ServiceRequestException e) { 
     throw e; 
    } catch (Exception e) { 
     throw new GeneralSecurityException("Cannot perform PGP encryption", e); 
    } 
    } 

    return encKeyBytes.toByteArray(); 
} 

private PGPPublicKey resolvePgpPublicKey(byte[] pgpKeyBytes) throws IOException, PGPException { 
    PGPPublicKeyRingCollection keyRingCollection; 
    try (InputStream in = PGPUtil.getDecoderStream(new ByteArrayInputStream(pgpKeyBytes))) { 
    keyRingCollection = new PGPPublicKeyRingCollection(
     PGPUtil.getDecoderStream(in), new JcaKeyFingerprintCalculator()); 
    } 

    Iterator<?> keyRingIterator = keyRingCollection.getKeyRings(); 
    while (keyRingIterator.hasNext()) { 
    PGPPublicKeyRing keyRing = (PGPPublicKeyRing) keyRingIterator.next(); 

    Iterator<?> keyIterator = keyRing.getPublicKeys(); 
    while (keyIterator.hasNext()) { 
     PGPPublicKey key = (PGPPublicKey) keyIterator.next(); 
     if (key.isMasterKey()) { 
     continue; 
     } 
     if (key.isEncryptionKey()) { 
     return key; 
     } 
    } 
    } 
    throw new ServiceRequestException("Cannot resolve PGPPublicKey"); 
} 

4)は何PGP暗号化なっていること keyBytesとして渡された16バイトの配列(の進文字列表現)は次のようです2 ":[分からない]:無効なパケットのgpg" 私はメッセージを解読しようとすると

-----BEGIN PGP MESSAGE----- 
Version: BCPG [email protected][email protected] 

hQEMA0a1HkkhtB4hAQf+MfDa3ILJJivDYO+V9GwLDXMq1Oi8YFe/oNfScT2KT6aG 
rKBIaCQvwTQPD95QS3lo9sRZYvD64C7+Y+PA2e4nSJYNiLmyEczqFVzSgoI8ibhD 
LDG+trkAgEd3UiSltju8oF/d5SUPaubVrfH413xZ2xg5lbx7z78U4KtAZ1IMk/XN 
DN2nCaOVIw/EbqzVt8YCdDpQRrnfh1ZB5lDmLYoRuJykQ08UCrxv9dyQN3wpOX/G 
K7Nq3w6Q6+vT8LiP9iA7NEEu3BObNHAQ371VQ4uJQaZOysxPAH/RFHDHRtDa6R/J 
F6ca8z28mliQdZxFpyrqKgPwjrsthZ4BApUnHZ6dm9I5ATnr4m4jPQefMeSgGLYD 
I3Mk82COdct8ZNk108bOQjSAl+CPlARb53pItOZm21PL1lVwzcq1IXvUjJYjEOSA 
6SccakqFhF8cgQ== 
=A56Z 
-----END PGP MESSAGE----- 

6)は私が手:

5)この暗号化の例の結果は次のようになります-messagesと 復号化に失敗した:

$ gpg -vv --decrypt /tmp/ct.asc 
gpg: armor: BEGIN PGP MESSAGE 
Version: BCPG [email protected][email protected] 
:pubkey enc packet: version 3, algo 1, keyid 46B51E4921B41E21 
    data: [2046 bits] 
gpg: armor header: 
gpg: public key is 21B41E21 
gpg: using subkey 21B41E21 instead of primary key 79CC322A 

You need a passphrase to unlock the secret key for 
user: "Foo Bar (Test Key) <[email protected]>" 
gpg: using subkey 21B41E21 instead of primary key 79CC322A 
2048-bit RSA key, ID 21B41E21, created 2017-08-17 (main key ID 79CC322A) 

gpg: no running gpg-agent - starting one 
gpg: public key encrypted data: good DEK 
:encrypted data packet: 
    length: 57 
    mdc_method: 2 
gpg: encrypted with 2048-bit RSA key, ID 21B41E21, created 2017-08-17 
     "Foo Bar (Test Key) <[email protected]>" 
gpg: AES256 encrypted data 
gpg: [don't know]: invalid packet (ctb=39) 
gpg: decryption okay 
gpg: [don't know]: invalid packet (ctb=44) 
$ 

答えて

1

暗号化されたPGPメッセージが構築されます場所ですencryptKeyBytes実装の問題は、あるとして01とは対照的に、それは、プレーンテキストメッセージのオクテットを書き込み、ということです、したがって解読の試行中のプロトコルエラーです。

private byte[] encryptKeyBytes(String keyName, byte[] keyBytes, byte[] pgpKey) 
    throws GeneralSecurityException { 
    ByteArrayOutputStream encKeyBytes = new ByteArrayOutputStream(keyBytes.length); 

    try (Handle<SecureRandom> randomHandle = RngSupport.getRandom()) { 
    JcePGPDataEncryptorBuilder encryptorBuilder = 
     new JcePGPDataEncryptorBuilder(PGPEncryptedDataGenerator.AES_256); 
    encryptorBuilder.setWithIntegrityPacket(true); 
    encryptorBuilder.setSecureRandom(randomHandle.getObject()); 
    encryptorBuilder.setProvider("BC"); 

    PGPEncryptedDataGenerator encryptor = new PGPEncryptedDataGenerator(encryptorBuilder); 
    try { 
     JcePublicKeyKeyEncryptionMethodGenerator keyEncryptionMethodGenerator = 
      new JcePublicKeyKeyEncryptionMethodGenerator(resolvePgpPublicKey(pgpKey)); 
     keyEncryptionMethodGenerator.setProvider("BC"); 
     encryptor.addMethod(keyEncryptionMethodGenerator); 

     PGPLiteralDataGenerator dataGenerator = new PGPLiteralDataGenerator(); 
     byte[] data = BytesSupport.encodeHex(keyBytes).getBytes(StandardCharsets.UTF_8); 
     try (
      OutputStream ao = new ArmoredOutputStream(encKeyBytes); 
      OutputStream eo = encryptor.open(ao, keyBytes.length); 
      OutputStream go = dataGenerator.open(
       eo, PGPLiteralData.UTF8, keyName, data.length, new Date())) { 
     go.write(data); 
     } 
    } catch (ServiceRequestException e) { 
     throw e; 
    } catch (Exception e) { 
     throw new GeneralSecurityException("Cannot perform PGP encryption on the content key", e); 
    } 
    } 

    return encKeyBytes.toByteArray(); 
} 

お知らせメッセージが書き込まれますどのバイトに出力ストリームを提供して抽象化されPGPLiteralDataGeneratorの使用、:

正しい実装は次のようになります。

関連する問題