kbpgp.js
Decrypting & verifying
Decrypting and verifying are slightly more complicated than encrypting or signing, because often, you don't know ahead of time which KeyManagers are required. For PGP messages that are signed and encrypted, you only know which verification key is needed after a successful decryption. Also, messages in PGP can be encrypted for multiple receivers, and any given receiver might only have access to one of many possible decryption keys.
In kbpgp, the unbox
function handles the nitty-gritty of decryption and
verification. You need to pass it a PGP message (encrypted, signed or both), and also a way
to fetch keys midstream --- a kbpgp.KeyFetcher
object. You can use one of ours
out-of-the-box or subclass your own (say, if you want to fetch keys from your server).
Out-of-the-Box: The KeyRing
The first example of a KeyFetcher we'll consider is a KeyRing --- a object that you can load ahead of time with a bunch of KeyManagers.
ring = new kbpgp.keyring.KeyRing
kms = [ alice, bob, charlie ]
for km in kms
ring.add_key_manager km
For convenience, the KeyManager
class also implements the KeyFetcher interface. If you
know ahead of time that you'll only need one KeyManager in a decryption/verification, then you can
use it as a KeyFetcher.
Decryption and Verification Example
Decrypt and verify via the unbox
function.
Pass the message, the KeyFetcher (like ring
above), an ASP if you intend
to cancel or monitor progress, and a callback to fire when done:
ring = new kbpgp.keyring.KeyRing
kms = [ alice, bob, charlie ]
pgp_msg = "---- BEGIN PGP MESSAGE ----- ...."
asp = # as in Encryption....
for km in kms
ring.add_key_manager km
kbpgp.unbox { keyfetch : ring, armored : pgp_msg, asp }, (err, literals) ->
if err?
console.log "Problem: #{err}"
else
console.log "decrypted message"
console.log literals[0].toString()
if (km = literals[0].get_data_signer()?.get_key_manager())?
console.log "Signed by PGP fingerprint"
console.log km.get_pgp_fingerprint().toString('hex')
unbox
calls back with two arguments: an Error if something went wrong, and an array
of Literals
if not. Literal
objects support the toString(enc)
and toBuffer()
methods. The former call takes an optional parameter which is an encoding;
if none is supplied, kbpgp will use the encoding specified in the PGP message; you can
specify 'utf8', 'ascii', 'binary', 'base64' or 'hex' if you want to override that encoding.
This example shows that unbox
handles both decryption and verification. To check
if parts of the message were signed, make a get_data_signer
call on each Literal
in the message. Note that the same KeyManager that you loaded into your KeyFetcher shows up here. So if you augment
that KeyManager with custom fields, they will be available here.
The KeyFetcher Interface
In a more general decryption/verification scenario, you might need to fetch the appropriate decryption and/or verification keys from secondary or remote storage. In this situation, you shouldn't use the KeyRing described above, but should instead provide a custom KeyFetcher.
All usable KeyFetchers must implement one method: fetch
. Given several
PGP key IDs, and a flag specifying which operation is requested, the fetch method should
call back with a KeyManager
, if it could find one.
fetch(ids,ops,cb)
is called with three arguments:
- ids --- An array of Buffers, each one containing a 64-bit ID of a PGP key. These keys might refer to subkeys, which are often employed in encrypting and signing messages.
-
ops --- Which crypto options are required of this key; a bitwise OR of
constants from
kbpgp.const.ops
, which are:- encrypt : 0x1
- decrypt : 0x2
- verify : 0x4
- sign : 0x8
-
cb --- A callback that when done, calls back with a triple:
(err,km,i)
- err is an Error explaining what went wrong, or
null
on success. - km is, in the case of success, a KeyManager that meets the given requirements
- i is, in the case of success, an integer indiciating which of the keys
was found in the lookup. If
0
is returned here, thenids[0]
is the 64-bit ID of a key insidekm
.
- err is an Error explaining what went wrong, or
We're just getting started with this tutorial and examples. Hit us up on github if anything is missing.