keybase / keybase-issues

A single repo for managing publicly recognized issues with the keybase client, installer, and website.
902 stars 37 forks source link

Cannot decrypt private key with triplesec #1759

Closed westmark closed 9 years ago

westmark commented 9 years ago

Hi!

I am attempting to decrypt my private key as received during the login phase:

triplesec.decrypt({
    data: new triplesec.Buffer(response.me.private_keys.primary.bundle),
    key: new triplesec.Buffer(passphrase)
}, ...)

However I am getting the error

{ [Error: bad header; couldn't find a good version (got 1647465013)] istack: [ 'Decryptor::run' ] }

What am I missing? Do I need to prepare the key data before creating the Buffer? My private key was generated on the website.

maxtaco commented 9 years ago

need to base64 decode first

data : new triplesec.Buffer(response.me.private_keys.primary.bundle, "base64")
westmark commented 9 years ago

No change I'm afraid, other than the bad version changes a little.

I also checked that the passphrase is not lost/changed between login and decrypting.

maxtaco commented 9 years ago

it also need to unpacked via purepack. i don't have much time to support you on this, but it's all in the docs.

On Thu, Sep 3, 2015 at 12:05 PM, Fredrik Westmark notifications@github.com wrote:

No change I'm afraid, other than the bad version changes a little.

I also checked that the passphrase is not lost/changed between login and decrypting.

— Reply to this email directly or view it on GitHub https://github.com/keybase/keybase-issues/issues/1759#issuecomment-137496848 .

maxtaco commented 9 years ago

This doc shows the format. So you should (1) base64 decode; and (2) unpack via msgpack unpacker; and (3) access body.priv.data.

In JS, you can use the npm module purepack

westmark commented 9 years ago

Thanks a bunch, maxtaco. It works a lot better now. I completely missed that part of the docs.

Sadly though I stumble on the last step. The unpacked data decrypts without errors, but the resulting buffer does not turn into a readable plaintext key as needed by kbgpg.KeyManager.import_from_armored_pgp. Logging the buffer content only produces nonsense.

var decoded = new triplesec.Buffer(response.me.private_keys.primary.bundle, 'base64');
var unpacked = purepack.unpack(decoded, 'buffer');
triplesec.decrypt({
    data: unpacked.body.priv.data,
    key: new triplesec.Buffer(passphrase)
}, function (err, buffer) {
    if (err) {
      console.error(err);
      return;
    }
    console.log(buffer.toString()); // outputs nonsense
...
oconnor663 commented 9 years ago

Are those bytes the binary (as opposed to armored) representation of a PGP key? You can check by piping them to gpg --list-packets, which understands both the binary and armored formats. I think the kbpgp function to import a key from binary is called import_from_pgp_message, though I could be misreading that.

Have you taken a look at the function import_from_p3skb in kbpgp? I think it does all the stuff you're trying to do, so you might be able to cross reference with that too.

maxtaco commented 9 years ago

yeah, that is the binary PGP message, which can be opened by passing to import_from_armored_pgp { binary : foo }... but as @oconnor663 this is likely combining calls that are chained together already in the keymanager libary

westmark commented 9 years ago

I tried using "binary", but then I get "Error: need a Buffer!" instead. I looked though the code and found that SlicerBuffer (kbpgp/src/openpgp/buffer.iced) will emit this error if the argument supplied is not a Buffer. However I am definitely inputing a Buffer instance (see below). I am starting to feel like an imbecille here..

triplesec.decrypt({
    data: unpacked.body.priv.data,
    key: new triplesec.Buffer(passphrase)
}, function (err, buffer) {
    if (err) {
      console.error(err);
      return;
    }
    console.log(Buffer.isBuffer(buffer)); // outputs true
    KeyManager.import_from_armored_pgp({
        binary: buffer
    }, function(err, keyMgr) {
        ...
maxtaco commented 9 years ago

I think @oconnor663 is correct, it would be easier to go that route.

Here is the test file I use for this stuff in the kbpgp directory.

Here is a gist with a full working example in IcedCoffeeScript. You can easily rewrite in JS if you want.

Cheers

westmark commented 9 years ago

Thanks maxtaco, I got it to work using your gist.

0x4445565A commented 8 years ago

For posterity sake a pure ugly JS way(leveraging kbpgp and jquery) would look like the following..

Note: there is no error checking.. https://gist.github.com/tehbmar/7f3b69a6417ec2ef581d2e2443c4ef4e

I think import_from_p3skb and unlock_p3skb should be added to the documentation since they are pretty important for grabbing user's private keys and unlocking them.

It is also important to note that an unlocked key is NOT obviously reflected in the keyManager object and can/should be checked with kbpgp.KeyManager.prototype.is_p3skb_locked(). The KeyManager after being unlocked can be passed straight to kbpgp.box(). You don't actually need the private key in it's plaintext form, I know this because before I got kbpgp.KeyManager.import_from_p3skb working I rewrote it to unpack and decode the key before I could use it. Ah..APIs.. How I love you.