This example uses PKCS #11 functions to create a digest from an input file. The example performs the following steps:
Specifies the digest mechanism.
In this example, the CKM_MD5 digest mechanism is used.
Finds a slot that is capable of the specified digest algorithm.
This example uses the Oracle Solaris convenience function SUNW_C_GetMechSession(). SUNW_C_GetMechSession() opens the cryptoki library, which holds all the PKCS #11 functions that are used in the Oracle Solaris cryptographic framework. SUNW_C_GetMechSession() then finds the slot with the desired mechanism. The session is then started. Effectively, this convenience function replaces the C_Initialize() call, the C_OpenSession() call, and any code needed to find a slot that supports the specified mechanism.
Obtains cryptoki information.
This part is not actually needed to create the message digest, but is included to demonstrate use of the C_GetInfo() function. This example gets the manufacturer ID. The other information options retrieve version and library data.
Conducts a digest operation with the slot.
The message digest is created in this task through these steps:
Opening the input file.
Initializing the digest operation by calling C_DigestInit().
Processing the data a piece at a time with C_DigestUpdate().
Ending the digest process by using C_DigestFinal() to get the complete digest.
Ends the session.
The program uses C_CloseSession() to close the session and C_Finalize() to close the library.
The source code for the message digest example is shown in the following example.
Example 9-1 Creating a Message Digest Using PKCS #11 Functions#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <security/cryptoki.h>
#include <security/pkcs11.h>
#define BUFFERSIZ 8192
#define MAXDIGEST 64
/* Calculate the digest of a user supplied file. */
void
main(int argc, char **argv)
{
CK_BYTE digest[MAXDIGEST];
CK_INFO info;
CK_MECHANISM mechanism;
CK_SESSION_HANDLE hSession;
CK_SESSION_INFO Info;
CK_ULONG ulDatalen = BUFFERSIZ;
CK_ULONG ulDigestLen = MAXDIGEST;
CK_RV rv;
CK_SLOT_ID SlotID;
int i, bytes_read = 0;
char inbuf[BUFFERSIZ];
FILE *fs;
int error = 0;
/* Specify the CKM_MD5 digest mechanism as the target */
mechanism.mechanism = CKM_MD5;
mechanism.pParameter = NULL_PTR;
mechanism.ulParameterLen = 0;
/* Use SUNW convenience function to initialize the cryptoki
* library, and open a session with a slot that supports
* the mechanism we plan on using. */
rv = SUNW_C_GetMechSession(mechanism.mechanism, &hSession);
if (rv != CKR_OK) {
fprintf(stderr, "SUNW_C_GetMechSession: rv = 0x%.8X\n", rv);
exit(1);
}
/* Get cryptoki information, the manufacturer ID */
rv = C_GetInfo(&info);
if (rv != CKR_OK) {
fprintf(stderr, "WARNING: C_GetInfo: rv = 0x%.8X\n", rv);
}
fprintf(stdout, "Manufacturer ID = %s\n", info.manufacturerID);
/* Open the input file */
if ((fs = fopen(argv[1], "r")) == NULL) {
perror("fopen");
fprintf(stderr, "\n\tusage: %s filename>\n", argv[0]);
error = 1;
goto exit_session;
}
/* Initialize the digest session */
if ((rv = C_DigestInit(hSession, &mechanism)) != CKR_OK) {
fprintf(stderr, "C_DigestInit: rv = 0x%.8X\n", rv);
error = 1;
goto exit_digest;
}
/* Read in the data and create digest of this portion */
while (!feof(fs) && (ulDatalen = fread(inbuf, 1, BUFFERSIZ, fs)) > 0) {
if ((rv = C_DigestUpdate(hSession, (CK_BYTE_PTR)inbuf,
ulDatalen)) != CKR_OK) {
fprintf(stderr, "C_DigestUpdate: rv = 0x%.8X\n", rv);
error = 1;
goto exit_digest;
}
bytes_read += ulDatalen;
}
fprintf(stdout, "%d bytes read and digested!!!\n\n", bytes_read);
/* Get complete digest */
ulDigestLen = sizeof (digest);
if ((rv = C_DigestFinal(hSession, (CK_BYTE_PTR)digest,
&ulDigestLen)) != CKR_OK) {
fprintf(stderr, "C_DigestFinal: rv = 0x%.8X\n", rv);
error = 1;
goto exit_digest;
}
/* Print the results */
fprintf(stdout, "The value of the digest is: ");
for (i = 0; i < ulDigestLen; i++) {
fprintf(stdout, "%.2x", digest[i]);
}
fprintf(stdout, "\nDone!!!\n");
exit_digest:
fclose(fs);
exit_session:
(void) C_CloseSession(hSession);
exit_program:
(void) C_Finalize(NULL_PTR);
exit(error);
}