--overview--

OVERVIEW

    cryptostorage.library implements a file-backed key-value store with
    encryption. Key names and key value lengths are not encrypted. The key
    values are encrypted with AES-256 in GCM (Galois/Counter Mode) mode,
    providing both confidentiality and integrity.

    Data on disk is always kept encrypted (encryption at rest). Data in
    memory is kept encrypted until it is needed to be decrypted due to
    a specific operation performed on it (Fetch or Passphrase change).
    Internally the library wipes the clear text data from memory as soon
    as it is no longer needed. Caller is recommended to employ similar
    tactics.

    The encryption key is derived from caller provided passphrase by
    employing PBKDF2-HMAC key derivation function with a SHA-256 hash
    function and caller configurable number of rounds (iterations). The
    default number of rounds is currently 50000. Alternatively a direct
    32-byte AES-256 encryption key can be provided by the caller.

    The crypto storage can be locked or unlocked. Unlocked state means
    that the encryption key is in memory, while locked state means that
    the key is not available. Some operations are only available on
    unlocked storages.

    CryptoStorageOpen is used to create or open (and potentially unlock) a
    crypto storage file.

    The following functions are available for both locked and unlocked
    storage:

    - CryptoStorageClear
    - CryptoStorageClose
    - CryptoStorageCommit
    - CryptoStorageExport
    - CryptoStorageFreeKeyArray
    - CryptoStorageImport (unlocked -> locked transition)
    - CryptoStorageLock (unlocked -> locked transition)
    - CryptoStorageQueryKeyArray
    - CryptoStorageUnlock (locked -> unlocked transition)

    The following functions are only available for unlocked storage:

    - CryptoStorageChangePassphrase (re-encrypts key values)
    - CryptoStorageFetch
    - CryptoStorageStore

    There are two strategies for pushing file changes to disk: Manual and
    automated. Manual method is implemented by calling
    CryptoStorageCommit() function to push changes to disk. Naturally
    CryptoStorageClose() will also push the changes to disk, too.
    The automated commit mode instructs the library commit the changes to
    disk as they are performed to the internal memory buffers.

    In addition to disk backed storages, it is also possible to have
    in-memory storages that have no file backing. These (and other)
    storages can be exported to and imported from a memory buffer at will.

    There are no limits to what kind of data can be stored in the key
    values. The amount of data that can be stored depends on the amount
    of free memory only. Key fetch and store are very fast, even with
    very large number of keys (when manual commit mode is used).

    It is important to understand that MorphOS does not provide memory
    protection, different user privilege levels or other advanced
    security concepts. As such it would be unwise so use this library
    to store any highly confidential information whose security is
    critical for defence, business, finance, health or similar matters.

CryptoStorageChangePassphrase

Change the encryption passphrase

SYNOPSIS

    rc = CryptoStorageChangePassphrase(ctx, tags)
    (sysv)

    LONG CryptoStorageChangePassphrase(APTR, Tag, ...);
    LONG CryptoStorageChangePassphraseA(APTR, struct TagItem *);

DESCRIPTION

    Changes the passphrase used to protect the crypto storage. The crypto
    storage must be unlocked to change the passphrase. All content in the
    crypto storage will be reencrypted with the passphrase provided

INPUTS

    ctx  - Pointer to a valid crypto storage context.
    tags - Pointer to a taglist, or NULL. The following tags are
           relevant for CryptoStorageChangePassphrase():

    CST_Passphrase (CONST_STRPTR)
                   - The new passphrase to use. This passphrase is hashed
                     with PBKDF2 hashing algorithm to produce the
                     encryption key, unless if CST_RawHexKey tag is
                     specified. This tag is required for this call.

    CST_OldPassphrase (CONST_STRPTR) (V51.4 and later)
                   - If specified the old passphrase is verified to be
                     correct before the operation is allowed to proceed.
                     This can be used as a security measure to ensure that
                     malicious users can't just change the passphrase of
                     the crypto storage.

    CST_RawHexKey (BOOL)
                   - If set to non-zero, the string specified in
                     CST_Passphrase and CST_OldPassphrase is a 64
                     character raw hex key. In this case no PBKDF2 will be
                     performed. This way the built-in hashing algorithm
                     can be replaced with a custom method implemented by
                     the caller.

    CST_HashRounds (ULONG)
                   - Specify number of PBKDF2 hashing rounds to be
                     performed. The default value is currently 50000 but
                     this may change in future versions. Higher values are
                     more secure but slower

RESULT

    rc - CSS_OK - Operation was successful.
         CSS_LOCKED - Storage is locked.
         CSS_BAD_PASSPHRASE - No new passphrase was provided or the old one
                              was incorrect.
         CSS_NOMEM - Not enough memory is available

SEE ALSO

CryptoStorageClear

Clear all keys

SYNOPSIS

    rc = CryptoStorageClear(ctx)
    (sysv)

    LONG CryptoStorageClear(APTR);

DESCRIPTION

    Clear all keys in the crypto storage. This operation is successful
    even on a locked crypto storage

INPUTS

    ctx - Pointer to a valid crypto storage context

RESULT

    rc - CSS_OK - Operation was successful.
         CSS_IO_ERROR - I/O error occured when writing to disk. This
                        can only happen if CST_CommitAtStore is TRUE

SEE ALSO

CryptoStorageClose

Commit and free crypto storage context

SYNOPSIS

    rc = CryptoStorageClose(ctx)
    (sysv)

    LONG CryptoStorageClose(APTR);

DESCRIPTION

    Commit any pending changes to disk and release the crypto storage
    context. If there are any I/O errors writing the pending data, the
    library will roll back to the previous saved state automatically.

    CryptoStorageOpen() CST_CloseRollback tag can be used to alter this
    behaviour: When specified as FALSE the CryptoStorageClose() will
    instead report the I/O error to the caller, and will not release
    the context. This mode has the disadvantage of that if the I/O error
    doesn't go away the context can never be released either

INPUTS

    ctx - Pointer to a valid crypto storage context

RESULT

    rc - CSS_OK - Operation was successful.
         CSS_IO_ERROR - I/O error occured when writing to disk (only
                        returned if the context was opened with
                        CST_CloseRollback tag set to FALSE

BUGS

    Earlier a persistent disk error could lead to a situation where it was
    not possible to release the context at all. If this condition was
    ignored it would lead to leak of the context and all associated
    resources. This behaviour was changed in v52.5 where the library will
    now rather roll back to the previous version of the saved file by
    default. The old behaviour can be restored by specifying
    CST_CloseRollback to FALSE.

SEE ALSO

CryptoStorageCommit

Commit pending crypto storage changes to disk

SYNOPSIS

    rc = CryptoStorageCommit(ctx)
    (sysv)

    LONG CryptoStorageCommit(APTR);

DESCRIPTION

    Commit any pending crypto srorage changes to disk. If there are no
    pending changes, nothing is written and CSS_OK is returned

INPUTS

    ctx - Pointer to a valid crypto storage context

RESULT

    rc - CSS_OK - Operation was successful.
         CSS_IO_ERROR - I/O error occured when writing to disk. This error
                        is also returned if commit of memory only store is
                        attempted

SEE ALSO

CryptoStorageExport

Export crypto storage to a memory buffer

SYNOPSIS

    rc = CryptoStorageExport(ctx, buffer, bufsize)
    (sysv)

    LONG CryptoStorageExport(APTR, APTR, ULONG *);

DESCRIPTION

    Exports the entire crypto storage (in encrypted form) to a memory
    buffer. Works on both locked and unlocked crypto storage

INPUTS

    ctx     - Pointer to a valid crypto storage context.
    buffer  - Buffer to store crypto storage to, or NULL to query the
              total crypto storage size.
    bufsize - Pointer to size. If 'buffer' is NULL the current size of the
              crypto storage is stored here. If 'buffer' is non-NULL, then
              it specifies the size of the available storage pointed by
              'buffer'. Upon successful export the actual number of
              bytes exported is stored to 'bufsize

RESULT

    rc - CSS_OK - Operation was successful. Actual size of the exported
                  crypto storage is stored to 'bufsize

EXAMPLE

    ULONG bufsize;
    LONG rc = CryptoStorageExport(storagectx,
                                  NULL, &bufsize);
    if (rc == CSS_OK)
    {
            UBYTE *buf = AllocVec(bufsize, MEMF_ANY);
            rc = CryptoStorageExport(storagectx,
                                    buf, &bufsize);
            if (rc == CSS_OK)
            {
                    /* ... */
            }
            FreeVec(buf

SEE ALSO

CryptoStorageFetch

Get key value

SYNOPSIS

    rc = CryptoStorageFetch(ctx, key, value, valsize)
    (sysv)

    LONG CryptoStorageStore(APTR, CONST_STRPTR, UBYTE *, ULONG *);

DESCRIPTION

    Get the specified key value. Specifying value as NULL can be used to
    query the current value size

INPUTS

    ctx     - Pointer to a valid crypto storage context.
    key     - Key name.
    value   - Buffer to store value to, or NULL to query the key value
              size.
    valsize - Pointer to size. If 'value' is NULL the current size of the
              key value is stored here. If 'value' is non-NULL, then it
              specifies the size of the available storage pointed by
              'value'. Upon successful retrieval the actual number of
              bytes fetched is stored to 'valsize

RESULT

    rc - CSS_OK - Operation was successful. Actual size of the key value
                  is stored to 'valsize'.
         CSS_LOCKED - Storage is locked.
         CSS_NOKEY - Key name was not specified or is empty, or key
                     was not found.
         CSS_BUFFER_OVERFLOW - Not enough storage was provided for
                               fetching the data

EXAMPLE

    ULONG valsize;
    LONG rc = CryptoStorageFetch(storagectx, "mykey",
                                 NULL, &valsize);
    if (rc == CSS_OK)
    {
            UBYTE *value = AllocVec(valsize, MEMF_ANY);
            rc = CryptoStorageFetch(storagectx, "mykey",
                                    value, &valsize);
            if (rc == CSS_OK)
            {
                    /* ... */
            }
            FreeVec(value

SEE ALSO

CryptoStorageFreeKeyArray

Free an array of existing keys

SYNOPSIS

    CryptoStorageFreeKeyArray(ctx, array)
    (sysv)

    VOID CryptoStorageFreeKeyArray(APTR, STRPTR *);

DESCRIPTION

    Releases the array returned by previous call to
    CryptoStorageQueryKeyArray

INPUTS

    ctx   - Pointer to a valid crypto storage context.
    array - array returned by CryptoStorageQueryKeyArray

SEE ALSO

CryptoStorageImport

Import crypto storage from memory buffer

SYNOPSIS

    rc = CryptoStorageImport(ctx, buf, bufsize)
    (sysv)

    LONG CryptoStorageStore(APTR, CONST_APTR, ULONG);

DESCRIPTION

    Imports a crypto storage from a given memory buffer. If successful
    all old contents of the crypto storage are removed and replaced with
    the imported content. Afterwards the storage will appear as locked

INPUTS

    ctx     - Pointer to a valid crypto storage context.
    buf     - Pointer to buffer to import from.
    bufsize - Size of the buffer to import from

RESULT

    rc - CSS_OK - Operation was successful.
         CSS_NOMEM - Not enough memory is available.
         CSS_IO_ERROR - I/O error occured when writing to disk. This
                        can only happen if CST_CommitAtStore is TRUE

SEE ALSO

CryptoStorageLock

Lock the crypto storage

SYNOPSIS

    CryptoStorageLock(ctx)
    (sysv)

    void CryptoStorageLock(APTR);

DESCRIPTION

    Locks the crypto storage by wiping the encryption key in memory.

    At this stage the stored data cannot be accessed again unless if the
    correct passphrase (and thus encryption key) is provided again

INPUTS

    ctx - Pointer to a valid crypto storage context

EXAMPLES

    CryptoStorageLock(storagectx);

SEE ALSO

CryptoStorageOpen

Open existing or create a new crypto storage

SYNOPSIS

    ctx = CryptoStorageOpen(tags)
    (sysv)

    APTR CryptoStorageOpenA(struct TagItem *);
    APTR CryptoStorageOpen(Tag, ...);

DESCRIPTION

    Open an existing crypto strorage or create a new one

INPUTS

    tags - Pointer to a taglist, or NULL. The following tags are
           relevant for CryptoStorageOpen():

    CST_FileName (CONST_STRPTR)
                   - A string specifying the storage file path. The
                     storage is saved to this location when committed on
                     disk. If no file name is provided the store will
                     remain in memory only.

    CST_Passphrase (CONST_STRPTR)
                   - A passphrase used to unlock the storage (existing
                     file) or to encrypt future stored content. This
                     passphrase is hashed with PBKDF2 hashing algorithm to
                     produce the encryption key, unless if CST_RawHexKey
                     tag is specified. Omitting the tag or passing a NULL
                     value means that the store will remain locked until
                     opened with CryptoStorageUnlock() call.

    CST_RawHexKey (BOOL)
                   - If set to non-zero, the string specified in
                     CST_Passphrase is a 64 character raw hex key. In this
                     case no PBKDF2 hashing will be performed. This way
                     the built-in hashing algorithm can be replaced with a
                     custom method implemented by the caller.

    CST_FailIfMissing (BOOL)
                   - If set to TRUE the function will return an error if
                     the storage file doesn't already exist.

    CST_CreateNew (BOOL)
                   - If set to TRUE wipe the storage empty if it already
                     exists.

    CST_CommitAtStore (BOOL)
                   - If set to TRUE the storage file is automatically
                     written to disk on each CryptoStorageStore() call. If
                     this tag is omitted or set to FALSE the file is only
                     written at CryptoStorageCommit() and
                     CryptoStorageClose().

    CST_HashRounds (ULONG)
                   - Specify number of PBKDF2 hashing rounds to be
                     performed. The default value is currently 50000 but
                     this may change in future versions. Higher values are
                     more secure but slower. This tag is only applicabple
                     if a new crypto storage is created, else the number
                     of rounds is fetched from the existing file.

    CST_CloseRollback. (BOOL) (V52.5 and later)
                   - If set to TRUE CryptoStorageClose() will quietly roll
                     back the crypto store if it cannot be written to disk
                     and no error will be reported. Setting this tag to
                     FALSE restores the older strategy of returning the
                     I/O error to the caller and not releasing the context.
                     Defaults to TRUE

RESULT

    ctx - Pointer to a crypto storage context or NULL if error occurred

EXAMPLES

    APTR storagectx;
    storagectx = CryptoStorageOpen(CST_FileName, (IPTR) "work:secret.cs",
                                   CST_Passphrase, (IPTR) pass,
                                   TAG_DONE);
    if (storagectx)
    {
            UBYTE dummy[1];
            ULONG dummysize = sizeof(dummy);
            LONG rc = CryptoStorageFetch(storagectx, "__passcheck__",
                                         dummy, &dummysize);
            if (rc == CSS_BAD_PASSPHRASE)
            {
                    Printf("Incorrect passphrase was given\n");
            }
            else if (rc == CSS_NOKEY)
            {
                    /* It's a new store so add the key. */
                    rc = CryptoStorageStore(storagectx, "__passcheck__",
                                            "", 0);
            }
            if (rc == CSS_OK)
            {
                    /* ... */
            }

            /*
             * This loop is required for pre-52.5 cryptostorage.library
             * to avoid leaking resources in case of I/O errors. Newer
             * library versions default to quiet rollback instead and
             * CSS_OK is always returned.
             */
            while (CryptoStorageClose(storagectx) != CSS_OK))
            {
                   Printf("Failed to commit to disk - Retry...\n");
                   Delay(50);
            }
    }

NOTE

    This function does not check if the passphrase given in CST_Passphrase
    (and the resulting encryption key) is a correct one. This checking is
    only performed when actual decryption operation is performed with
    CryptoStorageFetch(). If such checking is needed this can be achieved
    by storing a empty value ("") to some fixed key at storage creation
    time and attempting to fetch it after unlocking. If this fetch fails
    with CSS_BAD_PASSPHRASE the provided passphrase was an incorrect one.

    This function can take considerable time to execute due to the
    passphrase PBKDF2 hashing.

SEE ALSO

CryptoStorageQueryKeyArray

Query an array of existing keys

SYNOPSIS

    array = CryptoStorageQueryKeyArray(ctx)
    (sysv)

    STRPTR *CryptoStorageQueryKeyArray(APTR);

DESCRIPTION

    Queries the crypto storage for a list of currently existing keys. The
    keys are returned in no particular order

INPUTS

    ctx - Pointer to a valid crypto storage context

RESULT

    array - NULL terminated array of string pointers or NULL if out of
            memory. The returned array must be released with
            CryptoStorageFreeKeyArray

EXAMPLES

    STRPTR *array = CryptoStorageQueryKeyArray(storagectx);
    if (array)
    {
            LONG i;
            for (i = 0; array[i]; i++)
                    Printf("key[%ld]: %s\n", i, array[i]);

            CryptoStorageFreeKeyArray(array);
    }

NOTE

    The returned array and the strings in it must not be modified in any
    way.

SEE ALSO

CryptoStorageStore

Set key value

SYNOPSIS

    rc = CryptoStorageStore(ctx, key, value, valsize)
    (sysv)

    LONG CryptoStorageStore(APTR, CONST_STRPTR, CONST_STRPTR, ULONG);

DESCRIPTION

    Set key to specified value. Specifying value as NULL removes the
    key

INPUTS

    ctx     - Pointer to a valid crypto storage context.
    key     - Key name. Maximum key name length is about 64KB.
    value   - Data to store. Can be any data, including binary.
    valsize - Size of the data to store in bytes. The size is limited by
              amount of free memory

RESULT

    rc - CSS_OK - Operation was successful.
         CSS_LOCKED - Storage is locked.
         CSS_NOKEY - Key name was not specified or is empty, or key
                     was not found when attempting to remove it with
                     NULL value.
         CSS_BUFFER_OVERFLOW - Key name is too long or value size is
                               too large.
         CSS_IO_ERROR - I/O error occured when writing to disk. This
                        can only happen if CST_CommitAtStore is TRUE

SEE ALSO

CryptoStorageUnlock

Unlock the crypto storage

SYNOPSIS

    rc = CryptoStorageUnlock(ctx, tags)
    (sysv)

    LONG CryptoStorageUnlockA(APTR, struct TagItem *);
    LONG CryptoStorageUnlock(APTR, Tag, ...);

DESCRIPTION

    Unlocks the crypto storage with a passphrase or RAW hex key

INPUTS

    ctx  - Pointer to a valid crypto storage context.
    tags - Pointer to a taglist, or NULL. The following tags are
           relevant for CryptoStorageUnlock():

    CST_Passphrase (CONST_STRPTR)
                   - A passphrase used to unlock the storage. This
                     passphrase is hashed with PBKDF2 hashing algorithm to
                     produce the encryption key, unless if CST_RawHexKey
                     tag is specified. Omitting the tag or passing a NULL
                     value locks the storage instead.

    CST_RawHexKey (BOOL)
                   - If set to non-zero, the string specified in
                     CST_Passphrase is a 64 character raw hex key. In this
                     case no PBKDF2 hashing is performed. This way the
                     built-in hashing algorithm can be replaced with a
                     custom method implemented by the caller

RESULT

    rc - CSS_OK - Operation was successful. Note that this does not mean
                  that the resulting key is necessarily the correct one!
         CSS_BAD_PASSPHRASE - Invalid hex string was passed when
                              CST_RawHexKey is used.
         CSS_NOMEM - Not enough memory is available

EXAMPLES

    LONG rc = CryptoStorageUnlock(storagectx,
                                  CST_Passphrase, (IPTR) pass,
                                  TAG_DONE);
    if (rc == CSS_OK)
    {
        /* ... */
    }

NOTE

    This function does not check if the passphrase given in CST_Passphrase
    (and the resulting encryption key) is a correct one. This checking is
    only performed when actual decryption operation is performed with
    CryptoStorageFetch(). If such checking is needed this can be achieved
    by storing a empty value ("") to some fixed key at storage creation
    time and attempting to fetch it after unlocking. If this fetch fails
    with CSS_BAD_PASSPHRASE the provided passphrase was an incorrect one.

    This function can take considerable time to execute due to the
    passphrase PBKDF2 hashing.

SEE ALSO