Table of Contents

OPENPGP

Hop.js implements a minimal subset of OpenPGP, just sufficient to encrypt/decrypt and sign/verify messages.

All the functions and methods are avaiable via the hop.openpgp module. In this document we assume two key files produced as follows:

$ gpg --quick-generate-key hop-use
$ gpg -a -o example.pkey --export 366BF6C651EDED25
$ gpg -a -o example.skey --export-secret-keys 366BF6C651EDED25

Functions

openpgp.Key( keystr )

Creates an OpenPGP key from an ascii representation.

openpgp.readKey( url )

Reads an ascii armored pgp key file and returns an array of keys.

openpgp.key.toString()

Returns a string representation of the key.

Example: reading and display public and secret keys

openpgp/readkeys.js

"use hopscript";

import { readKey } from hop.openpgp;

const [ pkey ] = readKey( "./example.pkey" );
const [ skey ] = readKey( "./example.skey" );

console.log( "pkey=", pkey.toString() );
console.log( "skey=", skey.toString() );

This outputs:

pkey= hop-user                                        
366bf6c651eded25 RSA (Encrypt or Sign)
3d919dbe52d5077e RSA (Encrypt or Sign)

skey= hop-user
366bf6c651eded25 RSA (Encrypt or Sign)
3d919dbe52d5077e RSA (Encrypt or Sign)

openpgp.KeyRing( [ key ] )

Creates a KeyRing that can be used as a key manager by all the functions that need one.

If provided, the optional key is added to the newly created keyring.

openpg.KeyRing.addKey( key )

Add key to the keyring.

openpg.KeyRing.addKeys( keys )

Add all the key of the array 'keys` to the keyring.

openpg.KeyRing.resolve( id )

Returns the list of subkeys of the keyring which match whose identifier match id.

openpgp.encrypt( string, keys, passwords, {hashAlgo="sha256", symmetricAlgo="cast5"} )

Encrypts the given string. The returned composition can be decrypted by the owners of the keys, or with one of the passwords.

In the following example Alice and Bob may use their private key to decrypt the secret message. Users knowing the one of the passwords (foo and bar) will also be able to decrypt the message.

openpgp.encrypt( "my secret message", [ aliceKey, bobKey ], [ "foo", "bar" ] );

The given keys should be subkeys of a PGP-key, but if a PGP-key is given Hop will do its best to pick the correct subkey for encryption.

Example: symmetric encryption

openpgp/encrypt.js

"use hopscript";

import { encrypt } from hop.openpgp;

// symmetric encryption with a passkey
const passkey = "secret passkey";
const secret = "JavaScript is a descendant of Scheme";
const composition = encrypt( secret, false, [ passkey ] );

console.log( composition.toString() );
console.log( composition.decrypt( { passkeyProvider: () => passkey } ) );

It outputs:

-----BEGIN PGP MESSAGE-----
Version: Bigloo 4.4b

ww0EAwMINUT7wTGt9R++0k0BPzYXXrPithK4hwy7rnYdVV8UvNl+22tVNjO1YaFcDxIafMiSDxGh
I8HlGpPoRaQ9cIy67NDN4hDcptGQFqG7l2ZUcAkqc22vYeiEew==
=Pi/N
-----END PGP MESSAGE-----

JavaScript is a descendant of Scheme

Example: asymmetric encryption

openpgp/encrypta.js

"use hopscript";

import { readKey, encrypt, KeyRing } from hop.openpgp;

// asymmetric encryption with a public/private pair
const [ skey ] = readKey( "./example.skey" );
const [ pkey ] = readKey( "./example.pkey" );

const secret = "JavaScript is a descendant of Scheme";
const composition = encrypt( secret, [ pkey ] );
const keyRing = new KeyRing( skey );

console.log( composition.toString() );
console.log( composition.decrypt( { passwordProvider: key => "foobargee", keyManager: keyRing } ) );

It outputs:

-----BEGIN PGP MESSAGE-----
Version: Bigloo 4.4b

wcDMAz2Rnb5S1Qd+AgwAvmPYXEu5YeadKwmW7EPVjKHdkSy6uESovZv69j5gAe0dBAZJEF8RkU/V
7USYjoitu4CfMXfsUoYeXCSDh/hE9NoErU9y1AKLIcHI9qgOy9fEJ661xOLqyZKQXuHcuY/xrnZ7
Mjlt9aq1AS4JrNAeg2sySIvTMjo3Inmauo6uJhjSEmGf3zxCCIyBpoW7YHYqlhuQAgD+76LEqYiE
UF8hng+mLY+W5H9t/3B99aUPe2lD0KPJyYuiPX4KYoylh8kygNeId3yO3vrO4bu1Rgmw1aCQ0Oq/
EFO11KN54z2p0Ykr1Wz8UAUzt11rcXaGBgsbMfqFfh3n41340K9Cox5s7Vk8JqQTOLDIYSW28EmW
EZM7diJYYDWNIn9WMmOVcp8jdK+e9McNZ244UcOiTfrAlhj7rSagU08tMQOylA2GbTgr6isB1IOr
gl+al5MXVzUrte4EXHE4FZvJN1LE4o3orwvD695Qt8PJWOVr+WcRTY9JIOyh8AtIMyMKv8nitmXK
0k0BOFGIk5tYABu+hr1G+MVlY06YrlJvgupHY0b4LTn1MIPwJqDoa8KoHB1Yi5NBQgmg+t1ZONIs
1a+qxEoGHdEl1WFc6+VwHQVoOolzPg==
=K39G
-----END PGP MESSAGE-----

JavaScript is a descendant of Scheme

openpgp.sign( msg, key, passwordProvider, {detachedSignature=true, onePass=false, hashAlgo="sha256"} )

Signs msg (a string) with the given key (an OpenPGP key). It returns an OpenPGP composition object.

Ideally the key should be a subkey, but if a complete OpenPGP key is given, Hop will use the main-key instead. If the main-key is not suitable for signing, then an error is raised.

If the private part of the key has not yet been decrypted then Hop will call the passwordProvider (a procedure) with the subkey to get a password (a string).

The function returns an OpenPGP composition.

If the optional detachedSignature parameter is set to false then the msg is not included in the returned composition.

The onePass and hashAlgo parameters are usually left at its default values sign a message.

Example: signing a message

openpgp/readkeys.js

"use hopscript";

import { readKey, sign } from hop.openpgp;

const [ skey ] = readKey( "./example.skey" );
const compo = sign( "JavaScript is not Scheme" , skey, key => "foobargee", {} );

console.log( compo.toString() );

This outputs:

-----BEGIN PGP SIGNATURE-----
Version: Bigloo 4.4b

wsDcBAABCAAGBQJgG8jJAAoJEDZr9sZR7e0lxDUL/jeGTrXl1bPfz9/4IHX2NO/0RQloF0GoezuU
2FIfH6oSnx7W6YxSeCfxGHt69p9GiWxBAohBqj3H1CX2UrhNOZSMSTG2ASirNm5d+Ztfvy+ArNyE
2bqJ+02skCZeCOXJDnMa56UlvoC6V5a1HP1BgSTS7iozuCwCwR8Wxt76U7JegaSPNk3/7W1jgm4u
5UN8pxEmIylSfBGwdfH51UA9CRGN0PbamlPJxcm80FrzqEQTXkddemrcyHE1MuaCsVu3ye0mAy9I
v4NbI+AOvWqNmOnAkVEYPl7fDq/Z8ganPK3jZNZdCON7DD0mDno7saCyjeqla7IpoNY2Dbo4jsJl
+8X3d+fjjhjm40UNsWuqGGbuqt5BEEFd6GlYT+V9b8mKO8Tvwo9iIzILrYNP5j9/bnO0ujBxnrQS
aQayCiK8Fikqy3J5Q0fIXTBuv8erXf04c3cu4QYoUz/D0jDzwaZCNrX0YZEZOaBK13nn0QwQ6Klz
o62keQApYnglrdXDldtMbw==
=wuk5
-----END PGP SIGNATURE-----

openpgp.composition.verify( signature, keymanager, message = false )

Verifies a signature.

The keymanager is either :

The result of the verification is a list of subkeys that signed the message. If the keymanager doesn't have any of the signature-keys then the result is the empty list.

A message (string) needs only be given if the signature is detached. Otherwise the original message is encoded in the signature-composition.

Example: signing and verifying a message

openpgp/verify.js

"use hopscript";

import { readKey, KeyRing, sign } from hop.openpgp;

// sign
const [ skey ] = readKey( "./example.skey" );
const sig = sign( "JavaScript is not Scheme" , 
   skey, key => "foobargee", { detachedSignature: false } );

// verify
const [ pkey ] = readKey( "./example.pkey" );

console.log( "signature message:", sig.signatureMessage() );

const keyRing = new KeyRing( skey );
const signers = sig.verify( keyRing );

signers.forEach( sk => console.log( sk.toString() ) );

This outputs:

signature message: JavaScript is not Scheme
signers= [ {} ]
hop-user 366bf6c651eded25 RSA (Encrypt or Sign)