Bifroest Mr. Tines MacCTC CTCjava Manual Pages
Bifroest Mr. Tines CTC Home CTClib MacCTC CTCjava Manual


Key Hash-Table Module

This module is used to manage PKE keys. These are managed in key-rings pairs. A key-ring is a file containing PKE keys. A public key-ring contains Public-Keys. A secret key-ring contains secret keys. A key-ring pair consists of one of each. Most applications will only use a single key-ring pair at a time. However this module is capable of manipulating any number of key-ring pairs, limited only by available memory.

This module maintains an in-memory look-up structure of all public keys, associated usernames and signatures. However the bulk of the data for all of these remains on disc. The public key-ring file remains open and the module maintains pointers into it so this data can be read rapidly. [Note this adds some complications if rewriting the file. See writePubKey().] The secret key-ring is read in its entirety and file closed. (It is assumed that number of secret keys will be comparitively small.) Note this means that there may be zero or many secret key-rings used with any given public key-ring.

The structure of this module is suitable for the vast majority of end-user applications. However there is no pretense that this module is suitable for manipulating major public key-rings. That is a task for a Database Management System.

This module does maintain trust bytes, indeed, it ignores them. Trust bytes are held unencrypted in the key-rings, hence are wide open to manipulation on a machine that is not 100% secure. Accordingly it seems unwise to trust Trust bytes.

Data Types

Handles

The following datatypes are visible only as pointers. Calling application should not attempt to read or manipulate the contents. Any program attempting to is likely to fail to work with future releases of CTC.
pubkey
A PKE public key
seckey
A PKE secret key
username
A username associated with a public key.
signature
A signature typically confirming a public-key/username association, however this structure can represent a variety of types of PKE signature.
hashtable
A PKE public key

Enumeration Types

key_man_conds
They are a set of errors to be used conditions in callbacks. The following values are valid:-
KEY_NO_NUMBS
Key data (key itself) not available
KEY_DEADBEEF
Two keys have been encountered with the same Key Id. but different key values. This is very unlikely to occur by chance. This
KEY_BAD_STATUS
corrupt secret key status value
KEY_RING_FAILURE
failure to read from public key-ring
KEY_READ_PUBKEY
Just read a complete public key, add to ring?
KEY_READ_SECKEY
Just read a complete secret key, add to ring?
KEY_PUBKEY_FOUND
Public key block (not in a key-ring)
KEY_SECKEY_FOUND
Secret key block (not in a key-ring)
KEY_USERID_FOUND
User-id block (not in a key-ring)
KEY_KEYSIG_FOUND
Key Signatire block (not in a key-ring)
KEY_NO_USERID
(non-revocation) signature without userid
KEY_REVOKED
Key revocation certificate found and checked
KEY_UNCK_REVOKE
Failed to checked revocation certificate
KEY_BAD_REVOKE
Revocation certificate is a bad signature
KEY_WRONG_REVOKE
Revocation certificate signed with wrong key
KEY_BADSIG_FOUND
Bad key Signature block found
KEY_NOKEY_SIG_FND
Key signature by unknown key found
KEY_RECOVERY_KEY
Key-recovery key found and discarded.
prime_method
This type defines the method used to search for prime numbers in generating PKE keys. All methods for generation consist of selecting a random starting point. The length and the top few bits are selected to place the number in the appropriate magnitude range. All the other bits are generated at random. The available methods differ in how subsequent candidates are generated from the starting value and the criterion for accepting a prime. (Definition now in abstract.h).

The methods are:-
SIMPLE_SCAN
Each new candidate is generated by incrementing the previous candidate by two. The first prime encountered is selected.
JUMP_SCAN
A random increment as well as a random starting value is selected. (The random increment is selected to be mutually prime with the random increment.) Each new candidate is generated by incrementing the previous candidate by the selected increment.

This method is intended to reduce bias towards prime numbers that are greater than the next smaller prime by an greater than average margin.
SOPHIE_GERMAIN
Candidates are selected by the same method as for JUMP_SCAN, but candidate are rejected until one which is both prime and (N-1)/2 is also prime. (Strictly the smaller prime, not the prime actually used, is the Sophie-Germain prime.)  This produces a prime that is in some senses stronger, but at the cost that the search will take far longer as they are far rarer.  (For 1024 bit numbers, it will take about 100 times longer.)
sigValid
This type is used to indicate the result of an attempt to validate a signature.
SIG_OKAY
The Signature is valid.
SIG_NO_KEY
The public key required to check this signature is not available.
SIG_ERROR
checking process failed (e.g. no memory)
SIG_BAD
The signature is WRONG
signature_param
This type is used to indicate the value associated with a signature.
SIG_STATUS
The status of the signature with respect to verification (sigStat)
SIG_TRUST
The trust byte for this signature. (Note trust bytes are stored in plain and so are no more reliable/secure than the media on which they are stored unless locally regenerated.)
SIG_VERSION
Version byte of the signature packet. (Note that as the version of a signature is included in the signature this is fixed.)
SIG_CLASS
The class of the signature, i.e. what semantic meaning is to be attached to the signature. (sig-class)
SIG_PKALG
The public key algorithm used to make the signature.
SIG_MDALG
The message-digest algorithm used to generate the hash actually signed.
SIG_DATETIME
The time at which the signature was generated.
SIG_KEYID
The Id of the key used to make the signature.

Structures

keyType
This datatype provides details how a PKE key is to be generated.
The fields are:-
byte algorithm;
The algorithm byte for the key. Defining the PKE algorithm that the key will be used with. There may be up to three parameters used in key generation
ushort keyLength;
The required length of the key modulus in bits.
prime_method method;
The prime number search method to be used.
ushort publicExponent;
The value to be used as the public exponent
char name[256];
The first username to be associated with the key. (It is possible to add further usernames later)
char passphrase[256];
The pass-phrase that the key is to be initially encrypted with. If NULL the key will not be stored encrypted.
byte selfSignAlg;
message digest algorithm for selfsignature; if =0 implies don't sign.
byte kpAlg;
Key protection algorithm; the conventional encryption algorithm to be used to encrypted the key. (The key for this encryption is derived from the passphrase.)
recordSummary
This structure outlines the contents of a file packet, typically used before the packet has been fully read. (Definition now in pkcipher.h).
long position;
position of packet header; byte offset
long start;
position of contents; byte offset
long length;
length of packet excluding header; this may be -1 meaning "rest of the file".
long next;
file offset of the packet following, where there is no following packet it is the offset of the end-of-file
ushort size;
Key size (if a PKE key certificate)
byte type;
The type of the CTB packet. How this is extracted depends on the whether the header is a PGP2.x or PGP5.x header.
byte version;
Format version of the packet
byte trust;
(Valid only for Trust byte packets:) The Trust-byte value.
byte sigClass;
(valid only for SKE packets) Defines the type of signature
byte itemID[KEYFRAGSIZE];
The full Id. of the public-key associated with the packet. May be the key contained in the packet or the key used to generate the packet, which ever is appropriate to the packet type.
keyringContext
This structure contains the context information that must be maintained during the parsing of a PGP-format key-ring. For example, any user-Id. packet encountered refers to the most recent preceding PKE key. Accordingly the program need to keep track of which key that was. Note that any or all of these may be NULL. An number of operations will clear some of them. For example reading a key will set to NULL the last_name field.
pubkey * last_key;
Most recently read Public-Key
seckey * last_seckey;
Most recently read Secret-Key
username * last_name;
Most recently read User-Id. packet.
byte * last_trust;
Most recently read Trust byte.
hashtable * keyRings;
The In-memory keyRings (public and secret) associated with this read operation.

Macros

DIGESTEXTRAS
Before calculating the message digest of a message for the purpose signing it, a few extra bytes including data like the date and time are appended to the end of the message. DIGESTEXTRAS is the number of bytes added.
IDPRINTSIZE
Size in bytes of a printable key Id. That is the size of the formatted hexadecimal string, not the number of bytes of data being presented. (The number of bytes shown is KEYPRINTFRAGSIZE. The whole Id. size is KEYFRAGSIZE. See abstract.h)

Functions

Generating keys

seckey * makePKEkey(hashtable * table, keyType * keyType);
This function generates an new public/secret-key pair from scratch. The keyType argument defines the characteristics of the key being generated.

File Access (Keys and Key-rings)

boolean writePubRing(DataFileP file, hashtable * keyRings);
This function writes the complete contents of the public key portion of keyRings to the file. If file is NULL, the open public-ring file is overwritten.

This function returns true if successful.
boolean writeSecRing(DataFileP file, hashtable * keyRings);
This function writes the complete contents of the secret key portion of keyRings to the file.

The routine returns true if successful.
hashtableinit_userhash(DataFileP file);
Read the public key-ring file and establish an in-memory hashtable to manage it. Note that the file remains open and the file reference should not be used again the calling program.
boolean read_secring(DataFileP secring, hashtable * pubring);
Read the secret key-ring into the key-ring. Unlike public key-ring files for which a hashtable must have precisely one, there may any number (including zero) of secret key-ring files loaded into the hashtable. The main difference between this and other CTB file reads, is that this one expects only key-ring packets and does not prompt the user to confirm loading any keys.
continue_action keyringPacket(DataFileP input, recordSummary * summary, keyringContext * context);
Reads a keyring packet (one of the CTB packet types that appear in key-rings) from the input file into the supplied context, a summary of the record must be supplied (which must have been read earlier). Note that the input may, but need not, be the file associated with the public key-ring in the context. Whether or not it is modifies the action of the function slightly, to maintain key-ring integrity.
boolean publicChanged(hashtable * table);
Returns true if the public key portion of the table has been changed since it was last written to file.
boolean secretChanged(hashtable * table);
Returns true if the secret key portion of the table has been changed since it was last written to file.
boolean writePubKey(DataFileP file, pubkey * pub_key, boolean overwriting, boolean writeTrust);
This function writes the pub_key to the open file. If overwriting is true the routine records the file position of the new record in the pub_key structure, otherwise the file position recorded in the pub_key remains unchanged. (Note it is very that this argument is set if and only if the new file is taking over a public key reference file.) If writeTrust is true, a trust byte is also written.

This fucntion returns true if successful.
boolean writeSecKey(DataFileP file, seckey * sec_key);
This function writes the sec_key to the open file.

This function returns true if successful.

Keyring manipulation

The following set of key-ring manipulation operations are currently insufficiently general. Notably copy and deletion operations are missing. Possibly other operations are required too. (To date no-one has done any multiple key-ring manipulation that what would really need such operations.)
void setTrust(pubkey * pub_key, byte trust);
Set the value of the trust key associated with the key. (Note CTC pays no attention to trust byte values; this is primarily for PGP compatibility.)
boolean insertPubkey(hashtable * keyRings, pubkey * * pub_key);
This inserts the pub_key into the key-ring, and returns true is successful. The pub_key (i.e. the structure pointed to) must not already be in a different key-ring. If it is the function will return false. If the key structure is already in the key-ring the function is a no-op and returns true. If another copy of same key already exists in the key-ring, the keys will be merged. That is the resulting key will have all the usernames, and signatures of both of the copies. All duplicate records are deallocated. Where the keys are merged *pub_key is updated to refer to the structure in key-ring.
void removePubkey(hashtable * keyRings, pubkey * pub_key);
Removes a pub_key from a hashtable. Note that the pub_key structure is not deallocated. It is available (for example) for insertion into another key-rings.
boolean insertSeckey(hashtable * keyRings, seckey * sec_key);
Insert a secret key into the key-ring. This includes inserting the associated public key into the public part of the key-ring, which cannot be done if the public key is already in a different key-ring.
void removeSeckey(hashtable * keyRings, seckey * sec_key);
Removes (but does not deallocate) a secret key from a key ring. Note that it does not remove the associated public key from the public part of the key-ring. Accordingly it is not a true reverse of insertSeckey().
int mutualFactor(pubkey * left, pubkey * right, char commonFactor[1000]);
Security check: This routine is a type of mutual crack. It looks for common factors in the moduli of all the keys. Return: 0 if mutually prime, 1 if a commonFactor, -1 if an error
void free_pubkey(pubkey * * pub)
This releases all of the storage associated with pub. If pub is in a key-ring hashtable, it will be removed from the table first. This function must not be used with a key associated with a secret key until the secret key has been released with free_seckey(). Note that releasing the secret key may implicitly destroyed the public key too.
void free_seckey(seckey * * sec)
This releases all of the storage associated with sec. If sec is in a key-ring hashtable, it will be removed from the table first. If (and only if) the associated public key is not in a key-ring, the public key is also released.

Public Key enquiry functions

byte getPubkeyVersion(pubkey * pub_key)
This returns the packet format version used to write this key's certificate packet. (Note that as this is included in all signatures this cannot be changed without invalidating all of those signatures.)
byte getPubkeyAlg(pubkey * pub_key)
This returns the PKE algorithm of the public key. Note in the case of two key pairs (signature main-key and encryption sub-key) the algorithm byte refers only to the key actually being enquired about, not the whole pair.
ushort keyLength(pubkey * pub_key);
This function returns the length of the public key modulus in bits.
uint32_t keyDate(pubkey * pub_key);
This function returns the date and time that the key was generated. This is an unsigned integer number of seconds since the PGP time datum, 00:00:00hrs 1st January 1970.
uint16_t validity(pubkey * pub_key);
This returns the validity period (in days) of the key. The key should be assumed to expire, and should not be used this number of days after its creation.
void extract_keyID(byte keyID[KEYFRAGSIZE], pubkey * pub_key);
Extracts keyId (last few bytes of the module) from pub_key.
void fingerPrint(byte * hash, pubkey * pub_key);
This returns the (binary) fingerPrint of the pub_key, using the default algorithm for the key type. Pub_key must be completed before calling this function.
void fingerPrintPlus(byte * hash, pubkey * pub_key, byte algor);
This returns the (binary) fingerPrint of the pub_key, using the hash algorithm indicated by algor. Use algor = MDA_MD5 for PGP compatibility. Pub_key must be completed before calling this function.
byte ownTrust(pubkey * pub_key);
This returns the trust byte from the key.
void name_from_key(pubkey * key, char name[256]);
This function sets name to the text of the first Username record associated with the key.
void text_from_name(hashtable * keyRings, username * nameRec, char name[256]);
Return the text of the Username record. Note that Username records read from keyRing file do not include this text, so the hashtable is necessary to allow CTC to fetch it from file. However whether nameRec is from other sources the text may be in memory in which case keyRings may NULL. The function sets the name to "<unknown>" if it is unable to retrieve the text.
pubkeysignatory(signature * sig);
Returns the public used to make this signature. Note that a pubkey record will be returned irrespective of whether the key is available. It will be place-holding dummy if the key is unavailable. This means that a subsequent key-ring modifications may modify the record to a proper key.
uint32_t getSignatureValue(signature * sig, int keyValue, hashtable * keyrings);
This returns an integer value associated with the signature. Most of these values are in fact single bytes so will be in the range 0-255. However some are timestamps which is what the uint32_t return type is defined for. Currently there are no signed values. If any are defined in future it will be necessary to define another function to return them. The keyValue  identifies the type of value to be returned and may be either a signature_param or a sub-packet type.This set of values is accepted by both getSignatureValue and getSignatureArray(), but most individual values are valid in only one routine. This routine returns maximum uint32_t =~(0L) if there is no valid value to return. The keyrings  argument should refer to the keyring storing the signature (if it is in a key-ring) in case the full data is not in memory.
size_t getSignatureArray(signature * sig, int valueKey, byte * value, size_t maxSize, hashtable * keyRings);
This essentially the same as getSignature valuereturns a byte string value. The value  argument is the buffer to receive the result, and maxSize  is its size. The function returns the number of bytes found, zero if nothing is found. The other details of the function are as for getSignatureValue().
void formatKeyID(char text[IDPRINTSIZE], byte keyID[KEYFRAGSIZE]);
This converts a keyID  in binary, into a printable hexadecimal text  string.

Key location functions

pubkeykey_from_keyID(hashtable * keyRings, byte * keyID);
Searchs the keyRings looking for a public key with Id. keyID. Returns the key if found, otherwise NULL.
seckeyseckey_from_keyID(hashtable * keyRings, byte * keyID);
Searchs the keyRings looking for a secret key with Id. keyID. Return the key if found, otherwise NULL.
pubkeypublicKey(seckey * sec_key);
Returns the public key corresponding to secret key sec_key. This should never return NULL.
seckeysecretKey(pubkey * pub_key);
Returns the secret key corresponding to public key pub_key. This function returns null if the secret key is not available.

Key-ring exhaustive scan operations

The operations in this section allow exhaustive scans and similar navigation operations through key-rings.
pubkeyfirstPubKey(hashtable * keyRings);
Returns the first public key in the key-ring or null if the ring is empty. Note that as this is scanning a hash table, the order the keys are returned in is consistent but is not related to order of insertion. Keys are written to file in the same order as the key-ring write operations uses the same code.
pubkeynextPubKey(pubkey * previous);
Returns the next public key in the key-ring after the one supplied as an argument, or null if previous is the last key in the key-ring.
pubkeysubkey(pubkey * pubKey)
Returns the first subkey associated with the pubKey, or NULL if there is none. If pubKey is itself a sub-key, it returns the next sub-key associated with the same main key, or NULL if pubKey was the last sub-key.
signaturerevocation(pubkey * pub_key);
Returns the first signature on the key that is on the key alone, without any username included, if one exists or null otherwise. At PGP2.x that was always a key revocation certificate, hence the name of the routine. However at PGP5 and later there are other signatures of this type that can exist.
usernamefirstName(pubkey * pub_key);
Returns the first username record for the public key, or null if there are no names for this key. Unlikely public keys with a key-ring, the usernames on a public key are ordered and this order is preserved.
usernamenextName(username * previous);
Returns the next username record on the same public key as previous, or null if previous is the last name.
signaturefirstSig(username * name);
Returns the first signature associating name with the public key to which it is attached, or null if there are no signatures confirming (or denying) the association.
signaturenextSig(signature * sig);
Returns the next signature after sig associating the same public-key/username as sig, or null if sig is the last signature for the pair.
seckeyfirstSecKey(hashtable * keyRings);
Returns the first secret key in the key-ring, or null if there are no secret keys.
seckeynextSecKey(seckey * previous);
Returns the next secret key after previous in the key-ring or null if previous was the last key.

Subordinate record manipulations

username * addUsername(pubkey * key, char * text);
Generates a new Username record with the supplied text and associates it with the key. Note initially this association is not signed by any key. This must be done separately.
void removeUsername(pubkey * key, username * userid);
This removes a Username record (and all associated signatures) from a public key record.
signatureaddSignature(pubkey * key, username * userid, byte sigType, seckey * signing);
This generates a new signature confirming the association between the key and userid. For a revocation signature userid should be NULL
void removeSignature(pubkey * key, username * userid, signature * sig);
This removes a signature associating the public key and username. All three arguments must correspond correctly. (Username should not be NULL; To remove a revocation certificate use unrevoke()).
boolean revoke(seckey * sec_key);
This function generates a revocation certificate for the public key associated with sec_key. (The argument is a secret key as it is required to sign the revocation.) This function completes the public key if it was not already complete.
void unrevoke(pubkey * pub_key);
This functions removes the revocation certificate associated with the public key.

Control of secret key encryption

boolean internalise_seckey(seckey * sec_key, char * passphrase);
This function generates the internal (decrypted) form of a secret key, if and only if the passphrase is correct. Note that the success test is based not merely on a PGP style checksum, but also other key sanity checks. (For RSA it checks that p x q = n). This routine does not destroy the encrypted form.
void externalise_seckey(seckey * sec_key);
This function destroys the internal encrypted form.
boolean set_passphrase(seckey * sec_key, char * passphrase);
This function is maintained for compatibility only. New code should use set_passphrase_UTF8().
Older variant of set_passphrase_UTF8 which assumes not UTF8 conversion.
boolean set_passphrase_UTF8(seckey * sec_key, char * passphrase, boolean convertToUTF8);
This function changes the passphrase for a key and generates an new random encryption initialisation vector. (Note: Unlike PGP, CTC generates a new IV when and only when the key changes. This means that an attacker does not get several ciphertexts with the same key and plaintext but different IVs to attack. Note that this key is only ever used to encrypt a single plaintext (the key), there is no other reason to change the IV.)
skstat keyStatus(seckey * sec_key);
Returns the current status of the key.
boolean sameKey(pubkey * left, pubkey * right);
This routine returns true only if the two keys are definitely the same key. The test is to confirm the data of the two records is identical. This is only possible if both keys are complete so it returns false if either key is incomplete.
boolean completeKey(pubkey * pub_key);
This function completes a key. That it is reads the key itself (typically a few very large numbe