# PKCS#11 API-강좌5(C 언어로 된 Sample Code)

## PKCS#11 API-강좌5(C 언어로 된 Sample Code)

### C 언어 Sample Code

PKCS#11 API-강좌3에서 기술하였듯이, KeyperPlus 제품과 함께 제공되는 CD에 있는 Sample Code는 C++ 언어로 되어 있습니다. PKCS#11 API 자체는 C 언어로 되어 있지만, Sample Code는 C++ 언어로 되어 있어서, C 언어 Sample Code를 필요로 하시는 분들을 위해서, 일부를 C 언어 규칙에 맞게 수정한 Sample Code를 제시하고자 합니다. &#x20;

강좌3에서 기술한 예제 Source Code를 가지고 C 언어로 작성하였습니다. 이번 강좌의 목적이 C++ 언어로 된 Sample Code를 C 언어로 변환하는 것이기 때문에  “Retrieve AES Key from HSM by FindObject()” 부분은 제외하였습니다. &#x20;

Windows 와 LINUX 환경에서 동작되는 Source Code를 제공하기 위하여, 아래와 같은 #define 변수를 사용하여 OS별 차이점을 구별하였습니다.

{% code fullWidth="false" %}

```c
#ifdef WIN32   
  lm = LoadLibrary( libraryPath );
#elif defined(LINUX32)
  lm = dlopen( libraryPath, RTLD_LAZY | RTLD_LOCAL );
#else
  #error OS not defined.
#endif
```

{% endcode %}

CD에서 제공되는 Source Program 인 PKCS11\_SampleCode.cpp, Cryptoki.cpp, PKCS11\_SampleCode.h, Cryptoki.h 대신에 강좌에서 제공하는 CCodeSample.c 만 사용하시면 됩니다. 제공되는 기본적인 header file 인 pkcs11.h, pkcs11f.h, pkcs11t.h 은 그대로 사용하시면 됩니다.

<br>

&#x20;

### C++ 언어를 C 언어로 변환

기본적인 골격은 C 언어를 기준으로 되어 있기 때문에, 사용자가 추가 기능을 구현하고자 하면서, C++ Sample Code를 참조하고자 할 때, 변환해야 하는 부분만 기술하고자 합니다.&#x20;

1\.  C++ 언어에서는 reference 변수를 지원하지만, C 언어에서는 지원하지 않으므로, reference변수를 사용하여 함수를 call 하는 부분은, 변수의 Address를 parameter로 넘기도록 수정 하였고,  받는 함수에서는 Pointer 변수로 받아서 구현 하였습니다.

2\.  C++ 언어에서는 new 와 delete 라는 keyword를 지원하지만, C 언어에서는 지원하지 않으므로 malloc() 과 free() 함수를 사용하여 수정 하였습니다.

3\.  C++ 언어 에서는 변수를 아무데서나 선언 할 수 있지만, C 언어 에서는 앞부분에 선언 해야 하므로, 변수를 앞 부분으로 이동 하였습니다.

4\.  C++ 언어에서는 간단한 주석 처리를 위하여, “ // “로 시작되는 라인을 지원하나 C 언어에서는 지원하지 않기 때문에 “/\*  \*/ “ 형식으로 수정 하였습니다.

5\.  C++ 언어에서 사용한 예외 처리 기능(try, catch, throw)을 삭제 하였습니다.

6\.  C 언어와는 관계 없지만, PKCS#11 API 함수를 call 할 때, Original 이름을 그대로 사용하도록 수정하였습니다.

#### CCodeSample.c file 내용

{% code overflow="wrap" fullWidth="true" %}

```c
#ifdef WIN32
  #include <windows.h>
  #include <stdio.h>
  #include <stdlib.h>
  #include <memory.h>
#elif defined (LINUX32)
  #include <memory.h>
  #include <stdio.h>
  #include <stdlib.h>
  #include <unistd.h>
  #include <dlfcn.h>
#else
  #error OS Specific defined required
#endif

#include "pkcs11.h"

/* *** DECLARE/INITIALIZE GLOBAL VARIABLES *** */
CK_FUNCTION_LIST  *pkcs11;

#ifdef WIN32
#ifdef WIN64
  static char const libraryPath[] = "ap220w64HSM.dll";
  static HINSTANCE lm ;
#else
  static char const libraryPath[] = "bp201w32hsm.dll";
  static HINSTANCE lm ;
#endif
#elif defined(LINUX32)
  static char const libraryPath[] = "pkcs11.so" ;
  static void     *lm ;
#else
  #error OS not defined.
#endif

static CK_BYTE UserPin[] = "1234";  /* It depends on actual User Pin Number */
static CK_BBOOL bTrue = TRUE;
static CK_BBOOL bFalse = FALSE;
static CK_OBJECT_CLASS SecretKeyClass = CKO_SECRET_KEY;

void        CloseLibModule(void) ;
CK_RV   LoadPKCS11Module(void) ;
CK_RV   getSlot(CK_SLOT_ID *) ;
CK_RV   AESSamples(CK_SESSION_HANDLE) ;
CK_RV   generateAESKey(CK_SESSION_HANDLE, CK_OBJECT_HANDLE *, int , CK_CHAR_PTR) ;
CK_RV   AESEncryptDecrypt(CK_SESSION_HANDLE, CK_OBJECT_HANDLE, int , const CK_BYTE_PTR, const CK_ULONG) ;

 
/* *** MAIN *************************************************************************************** */
int main(int argc, char* argv[])
{
             CK_RV rc = 0;
             CK_BBOOL bInitialized = FALSE;
             char buffer[256] = {0};

             CK_C_INITIALIZE_ARGS args = {0};
             CK_SLOT_ID slotID = -1 ;
             CK_SESSION_HANDLE hSession = -1 ;

             rc = LoadPKCS11Module() ;
             if ( rc != CKR_OK ) return rc ;

                            /* 1. Initialize the pkcs#11 library ... */
                               rc = pkcs11->C_Initialize(&args);
                               if ( rc != CKR_OK )
                                             {
                                             CloseLibModule() ;
                                             return rc ;
                                             }
                               bInitialized = TRUE;

                           /* 2. Get the 1st SlotID  */
                /* When you already know the SlotID, there is no need to call getSlot() : SlotID information is in the machine file . For example, CK_SLOT_ID slotID = n */                                 
                             rc = getSlot(&slotID);
                             if ( rc != CKR_OK )
                                           {
                                           CloseLibModule() ;
                                           return rc ;
                                           }

                           /* 3. Then open a session and login as a User ... */
                           /* open session (must be serial/rw) */
                             rc = pkcs11->C_OpenSession(slotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL, NULL, &hSession);
                               if ( rc != CKR_OK )
                                             {
                                             printf("\n\n---There is no HSM or HSM is not ON-Line ----\n");
                                             CloseLibModule() ;
                                             return rc ;
                                             }

                                       
                              /* login as a User   */
                              rc = pkcs11->C_Login(hSession, CKU_USER, UserPin, strlen((char*) UserPin));
                              if ( rc != CKR_OK )
                                            {
                                            printf("\n\n--- Incorrect User PIN number-----------\n");
                                            CloseLibModule() ;
                                            return rc ;
                                            }

                           /* 4. Generate AES Key and Encryption & Decryption test  */
                               rc = AESSamples(hSessio
                               if ( rc != CKR_OK )
                                             {
                                             CloseLibModule() ;
                                             return rc ;
                                             }

                           /* 5. When we have completed the Crypto Operations, we must tidy up ... */
                               /* logout  */
                               rc = pkcs11->C_Logout(hSession);
                               /* close session */
                               rc = pkcs11->C_CloseSession(hSession);

                           /* 6. The last Cryptoki call - always finalize the library (if it has been initialised)!  */
                              if (bInitialized)
                                        {            
                                        rc = pkcs11->C_Finalize(NULL_PTR);
                                        }

             CloseLibModule() ;

            return rc;
}
/* *** end of MAIN ******************************************************************************** */

 
CK_RV LoadPKCS11Module(void)
{
             CK_RV           rc;
             CK_RV           (*pFunction)();

            #ifdef WIN32   
              lm = LoadLibrary( libraryPath );
            #elif defined(LINUX32)
              lm = dlopen( libraryPath, RTLD_LAZY | RTLD_LOCAL );
            #else
              #error OS not defined.
             #endif

              if ( lm == NULL )
                           {
                           printf("There is no PKCS11 Module : %s\n",libraryPath);
                           return !CKR_OK ;
                          }

 
            #ifdef WIN32   
                  pFunction = (CK_RV (*)())GetProcAddress(lm,"C_GetFunctionList");
            #elif defined(LINUX32)
                  pFunction = (CK_RV (*)())dlsym(lm,"C_GetFunctionList") ;
            #else
                  #error OS not defined.
             #endif

              
             if (pFunction == NULL )
                           {
                           printf("There is no C_GetFunctionList()\n"); 
                           CloseLibModule() ;
                           return !CKR_OK;
                           }

             rc = pFunction(&pkcs11);

             if (rc != CKR_OK)
                           {
                           printf("C_GetFunctionList() Error \n");
                           CloseLibModule() ;
                           return !CKR_OK;
                           }

   return CKR_OK;
}

 
void        CloseLibModule(void)
{ 
            #ifdef WIN32   
              FreeLibrary(lm);
            #elif defined(LINUX32)
              dlclose(lm);
            #else
              #error OS not defined.
             #endif
}

 

/* *** GET the 1st SLOT ********************************************************************************* */
CK_RV getSlot(CK_SLOT_ID *pSlotID)
{ 
        CK_RV rc; 
        CK_SLOT_ID_PTR pSlotList ;
 
             /* see if there are slots with tokens */ 
        CK_ULONG numSlots;

        rc = pkcs11->C_GetSlotList(TRUE, NULL, &numSlots); 
        if (numSlots)   
             { /* we've got one or more */ 
              /* call pkcs11->C_GetSlotList() again with a correctly sized buffer */ 
             pSlotList = (CK_SLOT_ID_PTR)malloc(sizeof(CK_SLOT_ID)*numSlots); 
             if ( pSlotList == NULL ) 
                      { /* Memory Full */ 
                      printf(" Memory Full \n") ; 
                      return !CKR_OK; 
                      }                         

            memset(pSlotList, 0xFF, sizeof(CK_SLOT_ID)*numSlots); 
            rc = pkcs11->C_GetSlotList(TRUE, pSlotList, &numSlots);
 
            *pSlotID = pSlotList[0]; /* Get the 1st slot ID */
 
                 /* tidy up */ 
            free(pSlotList) ;  
           }
 
             return rc; 
}

  
/* *** AES SAMPLE CODE **************************************************************************** */ 
CK_RV AESSamples(CK_SESSION_HANDLE hSession) 
{ 
                CK_RV rc; 
                char buffer[256] = {0}; 
                CK_BYTE data[64]; 
                CK_ULONG dataLen = sizeof(data); 
                int   i ; 
                CK_OBJECT_HANDLE hAESKey; 
                 int ByteLength = 16;  // 128 bit key :  16 byte = 128 bit   
                 CK_CHAR label[] = "AES2Key";
 
                           printf("\n\n~~~ AES Key Generation & Encryption & Decryption Test ~~~~~~~~~~~\n");
 
                     /*  generate some 64-byte data  for test */ 
                           rc = pkcs11->C_GenerateRandom(hSession, data, dataLen);
 
                           printf("\r\nOriginal  Data : ") ; 
                           for ( i = 0 ; i  < 64 ; i++ ) { 
                                        printf(" %02X ",data[i]) ; 
                           }
 
                    /* generate a AES key */                
                           rc = generateAESKey(hSession, &hAESKey, ByteLength, label);  
                           if ( rc != CKR_OK ) return rc ;
 
                    /* encrypt/decrypt */ 
                           rc = AESEncryptDecrypt(hSession, hAESKey, ByteLength, data, dataLen);
 
    return rc; 
}

 

/* ___GENERATE A AES KEY ______________________________________________________ */ 
CK_RV generateAESKey(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE *phAESKey, int ByteLength, CK_CHAR_PTR label) 
{ 
             CK_RV rc; 
             CK_ULONG KeySize=0;  
             CK_KEY_TYPE KeyType; 
             CK_MECHANISM genMech; 
             KeyType = CKK_AES; 
             KeySize=ByteLength;
 
             printf("\n\n--- Generate AES Key -------------------\n");
 
                           /* get the AES Key Generation mechanism */          
                           genMech.mechanism = CKM_AES_KEY_GEN; 
                           genMech.pParameter = 0; 
                           genMech.ulParameterLen = 0;
 
               /* reset the AES Key handle */ 
            *phAESKey = 0;
 
                           /* set up the AES Key template */ 
                       CK_ATTRIBUTE AESKeyTemplate[]  =  
                       { 
                                    {CKA_CLASS, &SecretKeyClass, sizeof(SecretKeyClass)}, 
                                    {CKA_KEY_TYPE, &KeyType, sizeof(KeyType)}, 
                                    {CKA_LABEL, label, strlen((char*)label)}, 
                                    {CKA_TOKEN, &bTrue, sizeof(bTrue)}, 
                                    {CKA_EXTRACTABLE, &bTrue, sizeof(bTrue)}, 
                                    {CKA_SIGN, &bTrue, sizeof(bTrue)}, 
                                    {CKA_VERIFY, &bTrue, sizeof(bTrue)}, 
                                    {CKA_ENCRYPT, &bTrue, sizeof(bTrue)}, 
                                    {CKA_DECRYPT, &bTrue, sizeof(bTrue)}, 
                                    {CKA_WRAP, &bTrue, sizeof(bTrue)}, 
                                    {CKA_UNWRAP, &bTrue, sizeof(bTrue)}, 
                                    {CKA_VALUE_LEN, &KeySize, sizeof(KeySize)} 
                        };
 
                           /* generate the AES Key */ 
                           rc = pkcs11->C_GenerateKey(hSession, &genMech, AESKeyTemplate, sizeof(AESKeyTemplate)/sizeof(AESKeyTemplate[0]), phAESKey);
 
    return rc; 
}

 
 
/* ___ AES ENCRYPT/DECRYPT ____________________________________________________ */ 
CK_RV AESEncryptDecrypt(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hAESKey, int ByteLength, const CK_BYTE_PTR data, const CK_ULONG dataLen) 
{     
             CK_RV rc;      
             CK_ULONG realDataLen ; 
             CK_BYTE_PTR encData ;  
             CK_BYTE_PTR decData ;   
             CK_ULONG encLen ; 
             CK_ULONG decLen ; 
             unsigned char IV[16] =  {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; 
             CK_ULONG i ; 
             CK_MECHANISM encDecMech;
 
             printf("\n\n--- AES Encrypt/Decrypt ----------------\n");
 
             realDataLen = dataLen + 8; 
             encData = (CK_BYTE_PTR)malloc(realDataLen); 
             if ( encData == NULL ) 
                           { /* Memory Full */ 
                           printf(" Memory Full \n") ; 
                           return !CKR_OK; 
                           }
 
             decData = (CK_BYTE_PTR)malloc(realDataLen); 
             if ( decData == NULL ) 
                           { /* Memory Full */ 
                           printf(" Memory Full \n") ; 
                           free(encData) ; 
                           return !CKR_OK; 
                           }
 
             encLen = realDataLen; 
             decLen = realDataLen;
 
                           /* set up the AES encrypt/decrypt mechanism (dependent upon the bit length) */ 
                           encDecMech.mechanism = CKM_AES_CBC; 
                           encDecMech.pParameter = IV; 
                           encDecMech.ulParameterLen = 16;
 
                           /* encrypt the data */ 
                          rc = pkcs11->C_EncryptInit(hSession, &encDecMech, hAESKey); 
                          rc = pkcs11->C_Encrypt(hSession, data, dataLen, encData, &encLen);
 
                           printf("\r\nEncrypted Data : ") ; 
                           for ( i = 0 ; i  < encLen  ; i++ ) { 
                                        printf(" %02X ",encData[i]) ; 
                           } 
                           printf("\r\n") ;
 
                           /* decrypt the data */ 
                           rc = pkcs11->C_DecryptInit(hSession, &encDecMech, hAESKey); 
                           rc = pkcs11->C_Decrypt(hSession, encData, encLen, decData, &decLen);
 
                           printf("\r\nDecrypted Data : ") ; 
                           for ( i = 0 ; i  < decLen  ; i++ ) { 
                                        printf(" %02X ",decData[i]) ; 
                           } 
                           printf("\r\n") ;
 
                           /* tidy up */ 
                         free(encData) ; 
                         free(decData) ;
 
            return rc; 
}
```

{% endcode %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://jihoony.gitbook.io/developers-notes/developer/pkcs-11-api/pkcs-11-api-5-c-sample-code.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
