java - Fail to gpg-decrypt BouncyCastlePGP-encrypted message -


when try decrypt message using gnupg encrypted bouncycastle 2 gpg: [don't know]: invalid packet (ctb=xx) messages , decryption fails.

i using bouncycastle 1.54 , gpg (gnupg) 2.0.30 on osx

details

1) pgp key generated using gpg follows:

$ gpg --gen-key gpg (gnupg) 2.0.30; copyright (c) 2015 free software foundation, inc. free software: free change , redistribute it. there no warranty, extent permitted law.  please select kind of key want:    (1) rsa , rsa (default)    (2) dsa , elgamal    (3) dsa (sign only)    (4) rsa (sign only) selection? 1 rsa keys may between 1024 , 4096 bits long. keysize want? (2048) requested keysize 2048 bits please specify how long key should valid.          0 = key 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 valid for? (0) 0 key not expire @ correct? (y/n) y  gnupg needs construct user id identify key.  real name: foo bar email address: foo@bar.com comment: test key selected user-id:     "foo bar (test key) <foo@bar.com>"  change (n)ame, (c)omment, (e)mail or (o)kay/(q)uit? o need passphrase protect secret key.  need generate lot of random bytes. idea perform other action (type on keyboard, move mouse, utilize disks) during prime generation; gives random number generator better chance gain enough entropy. need generate lot of random bytes. idea perform other action (type on keyboard, move mouse, utilize disks) during prime generation; gives random number generator better chance gain enough entropy. public , secret key created , 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) <foo@bar.com> sub   2048r/21b41e21 2017-08-17 $  

2) pgp public key exported in asc form looks like:

-----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 passed in in "public key block"-form , resolved follows: (the pgpkeybytes utf-8 byte encoding of string representation of key)

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) getting pgp encrypted hex-string representation of 16-byte array (passed in keybytes) follows:

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(); } 

5) example result of encryption looks like:

-----begin pgp message----- version: bcpg v@release_name@  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) when try decrypt message 2 "gpg: [don't know]: invalid packet"-messages , decryption fails:

$ gpg -vv --decrypt /tmp/ct.asc gpg: armor: begin pgp message version: bcpg v@release_name@ :pubkey enc packet: version 3, algo 1, keyid 46b51e4921b41e21     data: [2046 bits] gpg: armor header: gpg: public key 21b41e21 gpg: using subkey 21b41e21 instead of primary key 79cc322a  need passphrase unlock secret key user: "foo bar (test key) <foo@bar.com>" 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 1 gpg: public key encrypted data: dek :encrypted data packet:     length: 57     mdc_method: 2 gpg: encrypted 2048-bit rsa key, id 21b41e21, created 2017-08-17       "foo bar (test key) <foo@bar.com>" gpg: aes256 encrypted data gpg: [don't know]: invalid packet (ctb=39) gpg: decryption okay gpg: [don't know]: invalid packet (ctb=44) $ 

the problem encryptkeybytes implementation, encrypted pgp message gets built, writes plain-text message octets is, opposed literal data, hence protocol error during decryption attempt.

a correct implementation looks like:

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 content key", e);     }   }    return enckeybytes.tobytearray(); } 

notice use of pgpliteraldatagenerator, abstraction provides output stream on message bytes written to.


Comments

Popular posts from this blog

Is there a better way to structure post methods in Class Based Views -

performance - Why is XCHG reg, reg a 3 micro-op instruction on modern Intel architectures? -

jquery - Responsive Navbar with Sub Navbar -