Here we have some generic Pretty Good Privacy (PGP) primitive functions presented as API calls running on a Node HTTPS: server.
These functions are not specific as might be used to say, implement an email messaging plugin, but are instead intended specifically for a user registration and logon authorization application that invokes the generic functions to support its larger process.The concepts and code shown here are easily adaptable and are shared at .
PGP is an implementation of a Public Key Cryptography (PKC) scheme usually based on the RSA encryption method.
PGP is generally employed to sign and encrypt email messages which are then verified and decrypted by the recipient. Another large use is to encrypt files and drives to protect their contents. Notice that the characteristics of PKC/PGP make the identity of the participants in such an exchange or transaction identifiable to one another. In fact, our use case is based on this aspect of the scheme.
Here is an article about PKC schemes that gives some good explanations of the concepts and methods involved: //gzht888.com/public-key-cryptography-simply-explained-e932e3093046.
PGP as a technique or method for encryption has been available for some time and it has been coded or programmed in a good number of different languages and platforms.
The fairly recent openPGPjs JavaScript implementation we use is written in Nodejs as an asynchronous API and it can be found in this repository: .
Server.js API Program Shell
We provide an interface to the openPGPjs' functions through an Express Nodejs API framework that uses POST form submissions from the caller.
Following is the heading code in our Nodejs server.js API program. This section of code shows the modules we require for inclusion.
Following this heading code, we have inserted a number of API entry points here for the various functions we provide. After these various API functions are listed, we have this final brief section of code that sets up and runs the HTTPS: server for the API functions.
Our API deals with a number of objects in the course of its activities, and some of those objects are stored in tables in a database and one is generated from the contents of another data table.
More about the data table use later, but meanwhile, this following block of code is for a Node module usersdb_conn.js that connects us to our users' mySQL database we have in general use within the API functions.
Server.js PGP Functions
Now that we have described our general API shell, we can look at the functions it presents to our users.
Key Generator Function
Virtually every PGP function employs one or more of three important objects in its determinations and operations. The first of these objects is the user object which, in our case, is generated from data about the user that we extract from a database with the user’s email address provided thru the POST message. The content of this user database was previously populated by another part of our registration process. Here, in the listing below, we can see the POST request used to invoke the key generator function as well as a function to get the key type and key bit length from a configuration file and the function we use to extract the specific user data values from the database table.
In this next listing section below, we see the invocation of the openPGP key generation function using the firstname, lastname, passphrase, and email data values we obtained just above. Once the keys are generated in this demo version, we also write each of them to an appropriate file.
The two functions next below check for the existence of the public and private key records in the public and private key data tables. We use this info to decide whether we are inserting a new key or replacing/updating an already present key as shown in the listing below this one.
The function here next below displays a salutary banner success message page to the browser of the user who sent the demo generate keys API POST.
This keygenWebpage success banner display page code we just examined above is the last function used in the key generator POST section of the API.In order to get these individual functions to accomplish the intended task of generating a user key pair, we need a method to enqueue these functions to execute in an order proper to the task with each function, in turn, providing its contribution to the task list. So the main code for the key generator API call we have been discussing runs as part of this “performAsyncFunctions” model function which is an asynchronous function controller that runs each function sequentially, awaiting each function to complete before going on to the next.
Key Generator Results
Once this key generator API call has been run we will have all of the three objects generally used to encrypt or decrypt and sign or verify text messages available to our use.
We have a simple HTML menu page named sendPost.html shown here next below setup to demonstrate or run the calls available from our API.
This is your basic HTML form which sends a POST request to our API server and the three entries to create a key pair are implemented with this code shown next.
Finally, for our demo, we display a banner page display flagging the completion of the key generation process. This completion results in three core objects for the PGP scheme’s use. One is that of the user object with its attributes of a firstname, lastname, passphrase, and email address.
Our key generator has created two additional new objects for our use, a public key object and a private key object.
The console log is used to display our results and progress for various functions, and this is an example console log from running the key generator demo.
Four Operations on Our Three Objects
There are four operations of interest that we use in our API implementation. These operations are to encrypt a message, to sign a message, to decrypt a message, and to verify a message.
It is possible to both encrypt-and-sign or both decrypt-and-verify a message, so this gives us a table of six general functions aside from the key generator.
Message encryption uses the sender’s public key while message decryption uses the recipient’s private key and passphrase so these complementary operations use complementary keys. Message signing uses the signer’s private key and passphrase while verification uses the public key in a similarly complementary fashion.Encrypting a message or decrypting a message are the two of the most common PGP functions. Let’s look at how they are implemented in our API.
Encrypt a Message
This code shown below is the beginning of our Encrypt API call. As can be seen, the first thing we do is to get the sender or encrypter’s email address from the POST message, followed by getting the plaintext message we wish to encrypt along with the encrypter’s public key, which in our demo, is extracted from a database table based upon the email we provided in our API call.
Once we have the plaintext message we want to encrypt along with the sender’s public key, we can continue to encrypt the message using an openPGP function as shown here next. For our demo, we end the API call by writing the encrypted file to disk.
All of these functions above and used in our Encrypt API call are run in order as directed by the closing “performEncryptAsyncFunctions” asynchronous function with its enqueued sequence of awaited functions listed above.The demo doesn’t present a completion message to our API user for this call, but it does present a log file to our server terminal as shown here below.
Decrypt a Message
Once we have an encrypted text message in our possession, we may wish to read its plaintext or unencrypted contents. This of course entails the process of decryption which is accomplished by the following code. We begin by parsing the POST message for our user email address followed by a function to read our encrypted message from a file.
Decryption in our use case requires both a private key and a passphrase, and we extract the passphrase from our user database as shown here.
Our PGP scheme provides an additional level of protection by a process known as “armoring“ the key which involves encrypting it with this passphrase.
Besides these two previous functions, we have an additional function to get the private key from its database.
With these objects, we can decrypt the message and save the plaintext to a file using the first two functions in the listing below.
Once again, as shown above, we use our “performAsyncFunctions” construct to sequentially perform each function in the await list. As was done with the Encrypt API call, the interaction provided by this Decrypt API call consists of text displayed on the console terminal as shown in this example log below.
Other API Calls
Besides the three primary functions of key generation, message encryption, and message decryption, the code also serves four other API functions which are sign and verify along with the encrypt-and-sign and decrypt-and-verify API calls.
The code and terminal log results for these APIs is included in the GitHub repository at Code to run this Node program as a service on Linux (Ubuntu20) is also included in the GitHub repository.
Conclusion
This code is written more as a demo and NodeJS API example than as any production-ready utility. Hopefully, it will serve that purpose well for you see I wrote it as my own demo example. It should be easily adaptable to your own ends. Comments or suggestions are welcome.
Also published