Table of Contents
- OPENPGP
- Functions
- openpgp.Key( keystr )
- openpgp.readKey( url )
- openpgp.key.toString()
- openpgp.KeyRing( [ key ] )
- openpg.KeyRing.addKey( key )
- openpg.KeyRing.addKeys( keys )
- openpg.KeyRing.resolve( id )
- openpgp.encrypt( string, keys, passwords, {hashAlgo="sha256", symmetricAlgo="cast5"} )
- openpgp.sign( msg, key, passwordProvider, {detachedSignature=true, onePass=false, hashAlgo="sha256"} )
- openpgp.composition.verify( signature, keymanager, message = false )
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.
- If only one subkey exists (the main-key) then this subkey is used.
- If two subkeys exist, and the non-main key is suitable for encryption, then the non-main key is used.
- If only one of many subkeys (including the main-key) is suitable for encryption, then this subkey is used.
- Else Hop raises an error.
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 :
a function that takes a substring identifier and returns a list of keys matching this id. Since a signature composition may contain several signatures this function may be invoked several times.
a key ring created with
new openpgg.KeyRing()
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)