Skip to main content
SoftHSM v2 exposes the PKCS#11 digest function family for computing cryptographic hash values. Both single-part and multi-part operations are supported.

Functions

C_DigestInit

Initializes a digest operation on a session.
CK_RV C_DigestInit(
    CK_SESSION_HANDLE hSession,
    CK_MECHANISM_PTR  pMechanism
);
hSession
CK_SESSION_HANDLE
required
Handle of the open session.
pMechanism
CK_MECHANISM_PTR
required
Pointer to a CK_MECHANISM structure that specifies the hash algorithm. No mechanism parameters are required; pParameter should be NULL_PTR and ulParameterLen should be 0.
You must call C_DigestInit before any other digest function. If another operation is already active on the session, CKR_OPERATION_ACTIVE is returned.

C_Digest

Computes the hash of data in a single-part operation.
CK_RV C_Digest(
    CK_SESSION_HANDLE hSession,
    CK_BYTE_PTR       pData,
    CK_ULONG          ulDataLen,
    CK_BYTE_PTR       pDigest,
    CK_ULONG_PTR      pulDigestLen
);
pData
CK_BYTE_PTR
required
Pointer to the data to hash.
ulDataLen
CK_ULONG
required
Length of pData in bytes.
pDigest
CK_BYTE_PTR
Buffer to receive the digest. Pass NULL_PTR on the first call to obtain the required buffer size.
pulDigestLen
CK_ULONG_PTR
required
On input: size of pDigest. On output: number of bytes written (or required size if pDigest is NULL_PTR).
Use the two-pass pattern. Call C_Digest with pDigest = NULL_PTR — the function writes the hash output size to *pulDigestLen and returns CKR_OK. Allocate the buffer, then call again to produce the actual digest.

C_DigestUpdate

Continues a multi-part digest with an additional chunk of data.
CK_RV C_DigestUpdate(
    CK_SESSION_HANDLE hSession,
    CK_BYTE_PTR       pPart,
    CK_ULONG          ulPartLen
);
pPart
CK_BYTE_PTR
required
Pointer to the next chunk of data.
ulPartLen
CK_ULONG
required
Length of this chunk in bytes.
Call C_DigestUpdate one or more times, then call C_DigestFinal to obtain the digest.

C_DigestKey

Includes the value of a secret key in the ongoing digest computation.
CK_RV C_DigestKey(
    CK_SESSION_HANDLE hSession,
    CK_OBJECT_HANDLE  hObject
);
hObject
CK_OBJECT_HANDLE
required
Handle of a secret key whose value is to be included in the digest. The key must be a CKO_SECRET_KEY object.
C_DigestKey is typically used to hash the raw key material of a secret key without ever exposing the key value to the calling application. You can interleave calls to C_DigestKey and C_DigestUpdate freely during a multi-part operation.

C_DigestFinal

Finishes a multi-part digest operation and returns the resulting hash.
CK_RV C_DigestFinal(
    CK_SESSION_HANDLE hSession,
    CK_BYTE_PTR       pDigest,
    CK_ULONG_PTR      pulDigestLen
);
pDigest
CK_BYTE_PTR
Buffer to receive the final digest. Pass NULL_PTR to query the required size without consuming the operation.
pulDigestLen
CK_ULONG_PTR
required
On input: size of pDigest. On output: number of bytes written (or required size).
After C_DigestFinal returns successfully, the digest operation is cleared. You must call C_DigestInit again before starting another digest.

Supported hash mechanisms

MechanismOutput sizeNotes
CKM_MD516 bytesNot available in FIPS mode
CKM_SHA_120 bytes
CKM_SHA22428 bytes
CKM_SHA25632 bytes
CKM_SHA38448 bytes
CKM_SHA51264 bytes
CKM_GOSTR341132 bytesGOST R 34.11-94; requires WITH_GOST build
All mechanisms require pMechanism->pParameter = NULL_PTR and pMechanism->ulParameterLen = 0; any non-NULL parameter returns CKR_ARGUMENTS_BAD.

Error codes

Return valueMeaning
CKR_OKSuccess
CKR_ARGUMENTS_BADpData or pulDigestLen is NULL_PTR
CKR_MECHANISM_INVALIDHash algorithm not supported
CKR_OPERATION_ACTIVEAnother operation is already running on this session
CKR_OPERATION_NOT_INITIALIZEDC_DigestInit was not called
CKR_BUFFER_TOO_SMALLOutput buffer too small; required size written to *pulDigestLen

Example: SHA-256 digest

#include <stdlib.h>
#include <pkcs11.h>

/*
 * Compute a SHA-256 digest using the single-part C_Digest call.
 * pDigestOut must point to a buffer of at least 32 bytes.
 */
void sha256_digest(CK_SESSION_HANDLE hSession,
                   CK_BYTE *data, CK_ULONG dataLen,
                   CK_BYTE *pDigestOut, CK_ULONG *pulDigestOutLen)
{
    CK_MECHANISM mechanism = { CKM_SHA256, NULL_PTR, 0 };

    CK_RV rv = C_DigestInit(hSession, &mechanism);
    if (rv != CKR_OK) { return; }

    /* First pass: query digest size */
    CK_ULONG digestLen = 0;
    rv = C_Digest(hSession, data, dataLen, NULL_PTR, &digestLen);
    if (rv != CKR_OK) { return; }

    /* digestLen == 32 for SHA-256 */
    rv = C_Digest(hSession, data, dataLen, pDigestOut, &digestLen);
    if (rv == CKR_OK)
        *pulDigestOutLen = digestLen;
}

/*
 * Compute a SHA-256 digest of multiple data chunks using the
 * multi-part C_DigestUpdate / C_DigestFinal pattern.
 */
void sha256_multipart(CK_SESSION_HANDLE hSession,
                      CK_BYTE **chunks, CK_ULONG *chunkLens, CK_ULONG numChunks,
                      CK_BYTE *pDigestOut, CK_ULONG *pulDigestOutLen)
{
    CK_MECHANISM mechanism = { CKM_SHA256, NULL_PTR, 0 };

    CK_RV rv = C_DigestInit(hSession, &mechanism);
    if (rv != CKR_OK) { return; }

    for (CK_ULONG i = 0; i < numChunks; i++) {
        rv = C_DigestUpdate(hSession, chunks[i], chunkLens[i]);
        if (rv != CKR_OK) { return; }
    }

    CK_ULONG digestLen = 32;
    rv = C_DigestFinal(hSession, pDigestOut, &digestLen);
    if (rv == CKR_OK)
        *pulDigestOutLen = digestLen;
}

Build docs developers (and LLMs) love