Add documentation to pgp module.

This commit is contained in:
Spencer Ofwiti
2021-05-12 13:21:18 +03:00
parent 948a735baf
commit 948554563d
27 changed files with 3154 additions and 744 deletions

View File

@@ -1,3 +1,4 @@
// Application imports
import { MutablePgpKeyStore } from '@app/_pgp/pgp-key-store';
describe('PgpKeyStore', () => {

View File

@@ -1,88 +1,290 @@
// Third party imports
import { KeyStore } from 'cic-client-meta';
// TODO should we put this on the mutable key store object
import * as openpgp from 'openpgp';
/** An openpgp Keyring instance. */
const keyring = new openpgp.Keyring();
/**
* @extends
* Mutable Key store interface.
*
* @extends KeyStore
*/
interface MutableKeyStore extends KeyStore {
/**
* Instantiate the keyring in the keystore.
* @async
*/
loadKeyring(): void;
/**
* Add a key pair to keyring.
* @async
* @param publicKey - The public key to be added to the keyring.
* @param privateKey - The private key to be added to the keyring.
* @throws Error
*/
importKeyPair(publicKey: any, privateKey: any): Promise<void>;
importPublicKey(publicKey: any): void;
/**
* Add public key to keyring.
* @async
* @param publicKey - The public key to be added to the keyring.
* @throws Error
*/
importPublicKey(publicKey: any): Promise<void>;
/**
* Add private key to keyring.
* @async
* @param privateKey - The private key to be added to the keyring.
* @throws Error
*/
importPrivateKey(privateKey: any): Promise<void>;
/**
* Get all the public keys.
* @returns An array of public keys.
*/
getPublicKeys(): Array<any>;
/**
* Get all the trusted keys.
* @returns An array of trusted keys.
*/
getTrustedKeys(): Array<any>;
/**
* Get all the trusted active keys.
* @returns An array of trusted active keys.
*/
getTrustedActiveKeys(): Array<any>;
/**
* Get all the encryption keys.
* @returns An array of encryption keys.
* @remarks
* Current implementation doesn't include encryption keys.
* This is included to appease the implemented Keystore interface.
*/
getEncryptKeys(): Array<any>;
/**
* Get all private keys.
* @returns An array of all private keys.
*/
getPrivateKeys(): Array<any>;
/**
* Get the first private key.
* @returns The first private key.
*/
getPrivateKey(): any;
/**
* Test if the input is a valid key.
* @async
* @param key - The input to be validated.
* @returns true - If the input is a valid key.
*/
isValidKey(key: any): Promise<boolean>;
/**
* Verify that a private key is encrypted.
* @async
* @param privateKey - The private key to verify.
* @returns true - If private key is encrypted.
*/
isEncryptedPrivateKey(privateKey: any): Promise<boolean>;
/**
* Get the first private key's fingerprint.
* @returns The first private key's fingerprint.
*/
getFingerprint(): string;
/**
* Get a key's keyId.
* @param key - The key to fetch the keyId from.
* @returns The key's keyId.
*/
getKeyId(key: any): string;
/**
* Get the first private key's keyID.
* @returns The first private key's keyId.
*/
getPrivateKeyId(): string;
/**
* Get keys from the keyring using their keyId.
* @param keyId - The keyId of the keys to be fetched from the keyring.
* @returns An array of the keys with that keyId.
*/
getKeysForId(keyId: string): Array<any>;
/**
* Get a public key from the keyring using it's keyId.
* @param keyId - The keyId of the public key to be fetched from the keyring.
* @returns The public key with that keyId.
*/
getPublicKeyForId(keyId: string): any;
/**
* Get a private key from the keyring using it's keyId.
* @param keyId - The keyId of the private key to be fetched from the keyring.
* @returns The private key with that keyId.
*/
getPrivateKeyForId(keyId: string): any;
/**
* Get a public key from the keyring using it's subkeyId.
* @param subkeyId - The subkeyId of the public key to be fetched from the keyring.
* @returns The public key with that subkeyId.
*/
getPublicKeyForSubkeyId(subkeyId: string): any;
/**
* Get public keys from the keyring using their address.
* @param address - The address of the public keys to be fetched from the keyring.
* @returns An array of the public keys with that address.
*/
getPublicKeysForAddress(address: string): Array<any>;
/**
* Remove a public key from the keyring using it's keyId.
* @param keyId - The keyId of the keys to be removed from the keyring.
* @returns An array of the removed keys.
*/
removeKeysForId(keyId: string): Array<any>;
/**
* Remove a public key from the keyring using it's keyId.
* @param keyId - The keyId of the public key to be removed from the keyring.
* @returns The removed public key.
*/
removePublicKeyForId(keyId: string): any;
/**
* Remove a public key from the keyring.
* @param publicKey - The public key to be removed from the keyring.
* @returns The removed public key.
*/
removePublicKey(publicKey: any): any;
/** Remove all keys from the keyring. */
clearKeysInKeyring(): void;
/**
* Sign message using private key.
* @async
* @param plainText - The message to be signed.
* @returns The generated signature.
*/
sign(plainText: string): Promise<any>;
}
/** Provides a keyring for pgp keys. */
class MutablePgpKeyStore implements MutableKeyStore {
/**
* Instantiate the keyring in the keystore.
* @async
*/
async loadKeyring(): Promise<void> {
await keyring.load();
await keyring.store();
}
/**
* Add a key pair to keyring.
* @async
* @param publicKey - The public key to be added to the keyring.
* @param privateKey - The private key to be added to the keyring.
* @throws Error
*/
async importKeyPair(publicKey: any, privateKey: any): Promise<void> {
await keyring.publicKeys.importKey(publicKey);
await keyring.privateKeys.importKey(privateKey);
try {
await keyring.publicKeys.importKey(publicKey);
await keyring.privateKeys.importKey(privateKey);
} catch (error) {
throw error;
}
}
importPublicKey(publicKey: any): void {
keyring.publicKeys.importKey(publicKey);
/**
* Add public key to keyring.
* @async
* @param publicKey - The public key to be added to the keyring.
* @throws Error
*/
async importPublicKey(publicKey: any): Promise<void> {
try {
await keyring.publicKeys.importKey(publicKey);
} catch (error) {
throw error;
}
}
/**
* Add private key to keyring.
* @async
* @param privateKey - The private key to be added to the keyring.
* @throws Error
*/
async importPrivateKey(privateKey: any): Promise<void> {
await keyring.privateKeys.importKey(privateKey);
try {
await keyring.privateKeys.importKey(privateKey);
} catch (error) {
throw error;
}
}
/**
* Get all the public keys.
* @returns An array of public keys.
*/
getPublicKeys(): Array<any> {
return keyring.publicKeys.keys;
return keyring.publicKeys && keyring.publicKeys.keys;
}
/**
* Get all the trusted keys.
* @returns An array of trusted keys.
*/
getTrustedKeys(): Array<any> {
return keyring.publicKeys.keys;
return keyring.publicKeys && keyring.publicKeys.keys;
}
/**
* Get all the trusted active keys.
* @returns An array of trusted active keys.
*/
getTrustedActiveKeys(): Array<any> {
return keyring.publicKeys.keys;
return keyring.publicKeys && keyring.publicKeys.keys;
}
/**
* Get all the encryption keys.
* @returns An array of encryption keys.
* @remarks
* Current implementation doesn't include encryption keys.
* This is included to appease the implemented Keystore interface.
*/
getEncryptKeys(): Array<any> {
return [];
}
/**
* Get all private keys.
* @returns An array of all private keys.
*/
getPrivateKeys(): Array<any> {
return keyring.privateKeys.keys;
return keyring.privateKeys && keyring.privateKeys.keys;
}
/**
* Get the first private key.
* @returns The first private key.
*/
getPrivateKey(): any {
return keyring.privateKeys && keyring.privateKeys.keys[0];
}
/**
* Test if the input is a valid key.
* @async
* @param key - The input to be validated.
* @returns true - If the input is a valid key.
*/
async isValidKey(key): Promise<boolean> {
// There is supposed to be an openpgp.readKey() method but I can't find it?
const testKey = await openpgp.key.readArmored(key);
return !testKey.err;
}
/**
* Verify that a private key is encrypted.
* @async
* @param privateKey - The private key to verify.
* @returns true - If private key is encrypted.
*/
async isEncryptedPrivateKey(privateKey: any): Promise<boolean> {
const imported = await openpgp.key.readArmored(privateKey);
for (const key of imported.keys) {
@@ -93,6 +295,10 @@ class MutablePgpKeyStore implements MutableKeyStore {
return true;
}
/**
* Get the first private key's fingerprint.
* @returns The first private key's fingerprint.
*/
getFingerprint(): string {
// TODO Handle multiple keys
return (
@@ -103,10 +309,19 @@ class MutablePgpKeyStore implements MutableKeyStore {
);
}
/**
* Get a key's keyId.
* @param key - The key to fetch the keyId from.
* @returns The key's keyId.
*/
getKeyId(key: any): string {
return key.getKeyId().toHex();
}
/**
* Get the first private key's keyID.
* @returns The first private key's keyId.
*/
getPrivateKeyId(): string {
// TODO is there a library that comes with angular for doing this?
return (
@@ -116,43 +331,90 @@ class MutablePgpKeyStore implements MutableKeyStore {
);
}
/**
* Get keys from the keyring using their keyId.
* @param keyId - The keyId of the keys to be fetched from the keyring.
* @returns An array of the keys with that keyId.
*/
getKeysForId(keyId: string): Array<any> {
return keyring.getKeysForId(keyId);
}
/**
* Get a public key from the keyring using it's keyId.
* @param keyId - The keyId of the public key to be fetched from the keyring.
* @returns The public key with that keyId.
*/
getPublicKeyForId(keyId): any {
return keyring.publicKeys.getForId(keyId);
return keyring.publicKeys && keyring.publicKeys.getForId(keyId);
}
/**
* Get a private key from the keyring using it's keyId.
* @param keyId - The keyId of the private key to be fetched from the keyring.
* @returns The private key with that keyId.
*/
getPrivateKeyForId(keyId): any {
return keyring.privateKeys.getForId(keyId);
return keyring.privateKeys && keyring.privateKeys.getForId(keyId);
}
/**
* Get a public key from the keyring using it's subkeyId.
* @param subkeyId - The subkeyId of the public key to be fetched from the keyring.
* @returns The public key with that subkeyId.
*/
getPublicKeyForSubkeyId(subkeyId): any {
return keyring.publicKeys.getForId(subkeyId, true);
return keyring.publicKeys && keyring.publicKeys.getForId(subkeyId, true);
}
/**
* Get public keys from the keyring using their address.
* @param address - The address of the public keys to be fetched from the keyring.
* @returns An array of the public keys with that address.
*/
getPublicKeysForAddress(address): Array<any> {
return keyring.publicKeys.getForAddress(address);
return keyring.publicKeys && keyring.publicKeys.getForAddress(address);
}
/**
* Remove a public key from the keyring using it's keyId.
* @param keyId - The keyId of the keys to be removed from the keyring.
* @returns An array of the removed keys.
*/
removeKeysForId(keyId): Array<any> {
return keyring.removeKeysForId(keyId);
}
/**
* Remove a public key from the keyring using it's keyId.
* @param keyId - The keyId of the public key to be removed from the keyring.
* @returns The removed public key.
*/
removePublicKeyForId(keyId): any {
return keyring.publicKeys.removeForId(keyId);
return keyring.publicKeys && keyring.publicKeys.removeForId(keyId);
}
/**
* Remove a public key from the keyring.
* @param publicKey - The public key to be removed from the keyring.
* @returns The removed public key.
*/
removePublicKey(publicKey: any): any {
const keyId = publicKey.getKeyId().toHex();
return keyring.publicKeys.removeForId(keyId);
return keyring.publicKeys && keyring.publicKeys.removeForId(keyId);
}
/** Remove all keys from the keyring. */
clearKeysInKeyring(): void {
keyring.clear();
}
/**
* Sign message using private key.
* @async
* @param plainText - The message to be signed.
* @returns The generated signature.
*/
async sign(plainText): Promise<any> {
const privateKey = this.getPrivateKey();
if (!privateKey.isDecrypted()) {
@@ -169,4 +431,5 @@ class MutablePgpKeyStore implements MutableKeyStore {
}
}
/** @exports */
export { MutablePgpKeyStore, MutableKeyStore };

View File

@@ -1,5 +1,7 @@
import { PGPSigner } from '@app/_pgp/pgp-signer';
// Application imports
import { MutableKeyStore, MutablePgpKeyStore } from '@app/_pgp/pgp-key-store';
import { PGPSigner } from '@app/_pgp/pgp-signer';
const keystore: MutableKeyStore = new MutablePgpKeyStore();
describe('PgpSigner', () => {

View File

@@ -1,53 +1,111 @@
// Third party imports
import * as openpgp from 'openpgp';
// Application imports
import { MutableKeyStore } from '@app/_pgp/pgp-key-store';
import { LoggingService } from '@app/_services/logging.service';
const openpgp = require('openpgp');
/** Signable object interface */
interface Signable {
/** The message to be signed. */
digest(): string;
}
/** Signature object interface */
interface Signature {
/** Encryption engine used. */
engine: string;
/** Encryption algorithm used */
algo: string;
/** Data to be signed. */
data: string;
/** Message digest */
digest: string;
}
/** Signer interface */
interface Signer {
/** Event triggered on successful signing of message. */
onsign(signature: Signature): void;
/** Event triggered on successful verification of a signature. */
onverify(flag: boolean): void;
/**
* Get the private key fingerprint.
* @returns A private key fingerprint.
*/
fingerprint(): string;
/**
* Load the message digest.
* @param material - A signable object.
* @returns true - If digest has been loaded successfully.
*/
prepare(material: Signable): boolean;
/**
* Verify that signature is valid.
* @param digest - The message that was signed.
* @param signature - The generated signature.
*/
verify(digest: string, signature: Signature): void;
/**
* Signs a message using a private key.
* @async
* @param digest - The message to be signed.
*/
sign(digest: string): Promise<void>;
}
/** Provides functionality for signing and verifying signed messages. */
class PGPSigner implements Signer {
/** Encryption engine used. */
engine = 'pgp';
/** Encryption algorithm used */
algo = 'sha256';
/** Message digest */
dgst: string;
/** Generated signature */
signature: Signature;
/** A keystore holding pgp keys. */
keyStore: MutableKeyStore;
/** Event triggered on successful signing of message. */
onsign: (signature: Signature) => void;
/** Event triggered on successful verification of a signature. */
onverify: (flag: boolean) => void;
/** A service that provides logging capabilities. */
loggingService: LoggingService;
/**
* Initializing the Signer.
* @param keyStore - A keystore holding pgp keys.
*/
constructor(keyStore: MutableKeyStore) {
this.keyStore = keyStore;
this.onsign = (signature: Signature) => {};
this.onverify = (flag: boolean) => {};
}
/**
* Get the private key fingerprint.
* @returns A private key fingerprint.
*/
public fingerprint(): string {
return this.keyStore.getFingerprint();
}
/**
* Load the message digest.
* @param material - A signable object.
* @returns true - If digest has been loaded successfully.
*/
public prepare(material: Signable): boolean {
this.dgst = material.digest();
return true;
}
/**
* Verify that signature is valid.
* @param digest - The message that was signed.
* @param signature - The generated signature.
*/
public verify(digest: string, signature: Signature): void {
openpgp.signature
.readArmored(signature.data)
@@ -80,6 +138,11 @@ class PGPSigner implements Signer {
});
}
/**
* Signs a message using a private key.
* @async
* @param digest - The message to be signed.
*/
public async sign(digest: string): Promise<void> {
const m = openpgp.cleartext.fromText(digest);
const pk = this.keyStore.getPrivateKey();
@@ -111,4 +174,5 @@ class PGPSigner implements Signer {
}
}
/** @exports */
export { Signable, Signature, Signer, PGPSigner };