Structure of an openCryptoki application

The basic structure of an application that uses an openCryptoki token in order to encrypt and decrypt with an RSA key pair is described in this topic. You can use it as a template for general cryptographic applications.

Before you begin

Consider two things:
  1. Identify the slot ID of the token you want to utilize.
  2. Check whether the mechanisms that you must use or want to use are supported by the selected token.

Procedure

  1. Provide the openCryptoki data types, functions, attributes and all other available items for programming via the following ANSI C header files.
    
    #include <opencryptoki/pkcs11.h>   /* top-level Cryptoki include file */ 
    #include <stdlib.h>
    #include <errno.h>
    #include <stdio.h>
    #include <dlfcn.h>
    #include <defs.h>
  2. Use function C_Initialize to initialize Cryptoki.
    
    CK_RV C_Initialize(CK_VOID_PTR pInitArgs);

    An application becomes an openCryptoki application by calling the C_Initialize function from one of its threads. After this call, the application can call other openCryptoki functions.

  3. Use function C_InitToken to initialize the desired token in the specified slot. (if token not yet initialized, for example, with pkcsconf).
    
    CK_RV C_InitToken(
        CK_SLOT_ID slotID,
        CK_UTF8CHAR_PTR pPin,
        CK_ULONG ulPinLen,
        CK_UTF8CHAR_PTR pLabel
    );
    
  4. Use function C_OpenSession to open a connection between an application and a particular token.
    
    CK_RV openSession(CK_SLOT_ID slotID, CK_FLAGS sFlags,
    CK_SESSION_HANDLE_PTR phSession) {
        CK_RV rc;
        rc = C_OpenSession(slotID, sFlags, NULL, NULL, phSession);
    
        printf("Open session successful.\n");
        return CKR_OK;
    }
  5. Use function C_Login to log a user into a token. Variable userType specifies the user role (SO or normal User).
    CK_RV loginSession(CK_USER_TYPE userType, CK_CHAR_PTR pPin,
    CK_ULONG ulPinLen, CK_SESSION_HANDLE hSession) {
        CK_RV rc;
        rc = C_Login(hSession, userType, pPin, ulPinLen);
    
        printf("Login session successful.\n");
        return CKR_OK;
    }
  6. Use function C_GenerateKeyPair to generate an RSA private and public key pair. The used mechanism is CKM_RSA_PKCS_KEY_PAIR_GEN.
    
    CK_SESSION_HANDLE hSession;
    CK_OBJECT_HANDLE hPublicKey, hPrivateKey;
    CK_MECHANISM mechanism = {
      CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0
    };
    
    CK_ULONG modulusBits = 768;
    CK_BYTE publicExponent[] = { 3 };
    CK_BYTE subject[] = {...};
    CK_BYTE id[] = {123};
    CK_BBOOL true = CK_TRUE;
    
    CK_ATTRIBUTE publicKeyTemplate[] = {
      {CKA_ENCRYPT, &true, sizeof(true)},
      {CKA_VERIFY, &true, sizeof(true)},
      {CKA_WRAP, &true, sizeof(true)},
      {CKA_MODULUS_BITS, &modulusBits, sizeof(modulusBits)},
      {CKA_PUBLIC_EXPONENT, publicExponent, sizeof (publicExponent)}
    };
    
    CK_ATTRIBUTE privateKeyTemplate[] = {
      {CKA_TOKEN, &true, sizeof(true)},
      {CKA_PRIVATE, &true, sizeof(true)},
      {CKA_SUBJECT, subject, sizeof(subject)},
      {CKA_ID, id, sizeof(id)},
      {CKA_SENSITIVE, &true, sizeof(true)},
      {CKA_DECRYPT, &true, sizeof(true)},
      {CKA_SIGN, &true, sizeof(true)},
      {CKA_UNWRAP, &true, sizeof(true)}
    };
    
    CK_RV rv;
    
    rv = C_GenerateKeyPair(
      hSession, &mechanism,
      publicKeyTemplate, 5,
      privateKeyTemplate, 8,
      &hPublicKey, &hPrivateKey);
    if (rv == CKR_OK) {
      .
      .
    }
    
  7. Use functions C_EncryptInit and C_Encrypt to initialize an encryption operation and to encrypt data with the previously generated RSA private key.
    
    #define PLAINTEXT_BUF_SZ 200
    #define CIPHERTEXT_BUF_SZ 256
    
    CK_ULONG firstPieceLen, secondPieceLen;
    CK_SESSION_HANDLE hSession;
    CK_OBJECT_HANDLE hKey;
    CK_BYTE iv[8];
    CK_MECHANISM mechanism = {
      CKM_DES_CBC_PAD, iv, sizeof(iv)
    };
    
    CK_BYTE data[PLAINTEXT_BUF_SZ];
    CK_BYTE encryptedData[CIPHERTEXT_BUF_SZ];
    CK_ULONG ulEncryptedData1Len;
    CK_ULONG ulEncryptedData2Len;
    CK_ULONG ulEncryptedData3Len;
    CK_RV rv;
    ...
    firstPieceLen = 90;
    secondPieceLen = PLAINTEXT_BUF_SZ-firstPieceLen;
    rv = C_EncryptInit(hSession, &mechanism, hKey);
    
    if (rv == CKR_OK) {
      /* Encrypt first piece */
      ulEncryptedData1Len = sizeof(encryptedData);
      rv = C_EncryptUpdate(
        hSession,
        &data[0], firstPieceLen,
        &encryptedData[0], &ulEncryptedData1Len);
      
    
      /* Encrypt second piece */
      ulEncryptedData2Len = sizeof(encryptedData)-ulEncryptedData1Len;
      rv = C_EncryptUpdate(
        hSession,
        &data[firstPieceLen], secondPieceLen,
        &encryptedData[ulEncryptedData1Len], &ulEncryptedData2Len);
      if (rv != CKR_OK) { ... }
    
      /* Get last little encrypted bit */
    
      ulEncryptedData3Len =
        sizeof(encryptedData)-ulEncryptedData1Len-ulEncryptedData2Len;
      rv = C_EncryptFinal(
        hSession,
        &encryptedData[ulEncryptedData1Len+ulEncryptedData2Len],
        &ulEncryptedData3Len);
      if (rv != CKR_OK) {...}
    
    }
    
  8. Use function C_Logout to logout from the openCryptoki session and close the session.
    
       rv = C_Logout(session);
         if (rv != CKR_OK) goto err; 
    
        rv = C_CloseSession(session);
         if (rv != CKR_OK) goto err;
  9. Use function C_Finalize to finalize the operation.
    
     rv = fn->C_Finalize(NULL);
         if (rv != CKR_OK) goto err;