Opaque blobs (also known as OPAQUEBLOBs) are used to store session keys. They don't merely contain the base key material though, they also contain all of the current state information. This includes information such as the salt, the initialization vector, the key table, etc. Opaque blobs are called "opaque" because their format is unpublished. Each CSP vendor determines their own format, which should include encrypting the opaque blobs with some sort of symmetric key.
Once a key has been exported into an opaque blob, it can only be imported back into the same CSP from which it was originally exported.
When two processes are involved, each independently calls CryptAcquireContext, such that they both end up with a handle to a key container, possibly the same container. One process creates the keys and exports them into opaque blobs, then passes them to a second process, which imports them again.
If the CSP uses a hardware token that doesn't support exporting keys, then the blob may only contain the index of a key register, or something similar. In this case, the hardware can remain unaware of the whole procedure.
When the CRYPT_DESTROYKEY flag is passed into the CryptExportKey function, the original key is automatically destroyed by the CSP. For a hardware CSP, the handle to the original key is destroyed. This avoids the necessity of calling CryptDestroyKey on the original key, which may confuse some hardware CSPs by causing them to delete a key that you are still planning to use.
<secure process>
cbBlob = sizeof(rgbBlob);
CryptExportKey(hKey, 0, OPAQUEBLOB, CRYPT_DESTROYKEY,
rgbBlob, &cbBlob);
hKey = 0;
<blob is transferred to other process>
<user process>
CryptImportKey(hProv, pbBlob, cbBlob, 0, 0, &hKey);