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.
-
hashtable * init_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.
-
pubkey * signatory(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
-
pubkey * key_from_keyID(hashtable
* keyRings, byte * keyID);
-
Searchs the keyRings looking for a public key with Id. keyID.
Returns the key if found, otherwise NULL.
-
seckey * seckey_from_keyID(hashtable
* keyRings, byte * keyID);
-
Searchs the keyRings looking for a secret key with Id. keyID.
Return the key if found, otherwise NULL.
-
pubkey * publicKey(seckey
* sec_key);
-
Returns the public key corresponding to secret key sec_key. This
should never return NULL.
-
seckey * secretKey(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.
-
pubkey * firstPubKey(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.
-
pubkey * nextPubKey(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.
-
pubkey * subkey(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.
-
signature * revocation(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.
-
username * firstName(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.
-
username * nextName(username
* previous);
-
Returns the next username record on the same public key as previous,
or null if previous is the last name.
-
signature * firstSig(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.
-
signature * nextSig(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.
-
seckey * firstSecKey(hashtable
* keyRings);
-
Returns the first secret key in the key-ring, or null if there are no secret
keys.
-
seckey * nextSecKey(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.
-
signature * addSignature(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