PKCS#11 API-강좌4

PKCS#11 API-강좌4

RSA Key Generation and Encryption/Decryption 과 Sign/Verify 예제

강좌3 에서는 AES Key를 사용하는 예제를 보여 주었습니다. 강좌4 에서는 Asymmetric Key인 RSA 2048 bit Key를 생성하여, 테스트 데이타로 생성된 64-byte data를 Encryption/Decryption 하고, SHA256으로 Hash 하여 32-byte Digest를 만들고, 이 Digest를 Sign/Verify 하는 기능을 수행하는 예제입니다. 또 이번 예제에서는 생성되어, HSM에 저장된 Key를 삭제하는 C_DistroyObject() 함수도 사용하였습니다.

Asymmetric Key이기 때문에 Private Key 와 Public Key 두 개가 생성됩니다. Key Label은 RSA5Key 를 사용하였습니다. Encryption/Decryption 암호 연산과 Sign/Verify 연산 모두 HSM 장비안에서 수행됩니다.

강좌3 에서 제시한 소스와 유사하므로, 다른 부분만 기술하였습니다.

// *** HEADER FILES ***

      . . . . . . . .
static CK_OBJECT_CLASS PublicKeyClass = CKO_PUBLIC_KEY;
static CK_OBJECT_CLASS PrivateKeyClass = CKO_PRIVATE_KEY;
static CK_KEY_TYPE RSAKeyType = CKK_RSA;

 
// *** MAIN ***************************************************************************************

int main(int argc, char* argv[])
{

             ………….

                  
                     //4. Generate RSA Key and Encryption/Decryption & Sign/Verify test
                          rc = PKCS11_SampleCode::RSASamples(hSession);
                          if ( rc != CKR_OK ) throw buffer ;

                          
             ………..

}

// *** end of MAIN ********************************************************************************

 
// *** RSA SAMPLE CODE ****************************************************************************
CK_RV PKCS11_SampleCode::RSASamples(CK_SESSION_HANDLE hSession)
{

    printf("\n\n~~~ RSA Key Generation, Encryption/Decryption, Signing/Verify ~~~~~~~~~~~~~~~~~~~~~~~~\n");

             // NOTES:
             // Key Generation:    Mechanism CKM_RSA_PKCS_KEY_PAIR_GEN is supported to generate keys
             //                                                                A 2048 bit key pair is generated in this example.
             // Encrypt/Decrypt:    Mechanisms  CKM_RSA_PKCS is used in this example
             //
             // Digest:                            Mechanisms CKM_SHA_256 is used in this example
             //                                                               
             // Sign/Verify:                       Mechanisms CKM_RSA_PKCS is used in this example.
             //                                                               

             CK_RV rc;
    try
    {
                           // generate some data
                           CK_BYTE data[64];
                           CK_ULONG dataLen = sizeof(data);
                           int          i;
 
                           rc = pkcs11.GenerateRandom(hSession, data, dataLen);

                          printf("\r\nOriginal  Data : ") ;
                           for ( i = 0 ; i  < 64 ; i++ ) {
                                        printf(" %02X ",data[i]) ;
                           }             


                           // generate a key pair
                           CK_OBJECT_HANDLE hPubKey;
                           CK_OBJECT_HANDLE hPrivKey;
                           CK_ULONG ModulusBits = 2048 ; // for RSA 2048
                           CK_CHAR label[] = "RSA5Key";

                           rc = PKCS11_SampleCode::generateRSAKeyPair(hSession, hPubKey, hPrivKey, ModulusBits,label);
                           if ( rc != CKR_OK ) return rc ;
      

                          // encrypt/decrypt
                           rc = PKCS11_SampleCode::RSAEncryptDecrypt(hSession, hPubKey, hPrivKey, data, dataLen);
                           if ( rc != CKR_OK )
                                        {
                                         // tidy up
                                        pkcs11.DestroyObject(hSession, hPubKey);
                                        pkcs11.DestroyObject(hSession, hPrivKey);
                                        return rc  ;
                                        }


                           // digest
                           CK_BYTE hash[32] = {0};
                           CK_ULONG hashLen = sizeof(hash);
                           rc = PKCS11_SampleCode::sha256Hash(hSession, data, dataLen, hash, &hashLen);
    
                           // sign/verify
                           rc = PKCS11_SampleCode::RSASignVerify(hSession, hPubKey, hPrivKey, hash, hashLen);                        

                           // tidy up
                           pkcs11.DestroyObject(hSession, hPubKey);                          
                           pkcs11.DestroyObject(hSession, hPrivKey);

    }
             catch (char* e)
    {
                 printf(e);
    }
    catch (...){}

    return rc;
}


// ___ GENERATE AN RSA KEY PAIR _______________________________________________
CK_RV PKCS11_SampleCode::generateRSAKeyPair(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE& hPubKey, CK_OBJECT_HANDLE& hPrivKey, CK_ULONG ModulusBits, CK_CHAR_PTR label)
{
    printf("\n\n--- Generate RSA Key Pair --------------\n");

             CK_RV rc;
    try
    {
                           // get an RSA Key Generation mechanism
                          CK_MECHANISM genMech = {CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0};

                           // declare a Public Exponent
                           CK_BYTE PublicExponent[] = {0,0,0,0x03};

 
                           // generate the RSA Public Template
        CK_ATTRIBUTE pubKeyTemplate[]  =
        {
            {CKA_CLASS, &PublicKeyClass, sizeof(PublicKeyClass)},
            {CKA_TOKEN, &bTrue, sizeof(bTrue)},
            {CKA_PRIVATE, &bTrue, sizeof(bTrue)},
            {CKA_MODIFIABLE, &bFalse, sizeof(bFalse)},             
            {CKA_ENCRYPT, &bTrue, sizeof(bTrue)}, 
            {CKA_VERIFY, &bTrue, sizeof(bTrue)},   
            {CKA_WRAP, &bTrue, sizeof(bTrue)},                               
            {CKA_KEY_TYPE, &RSAKeyType, sizeof(RSAKeyType)},
            {CKA_MODULUS_BITS, &ModulusBits, sizeof(ModulusBits)},
            {CKA_PUBLIC_EXPONENT, &PublicExponent, sizeof(PublicExponent)}
        };


                           // generate the RSA Private Template
        CK_ATTRIBUTE privKeyTemplate[]  =
        {
            {CKA_CLASS, &PrivateKeyClass, sizeof(PrivateKeyClass)},
            {CKA_TOKEN, &bTrue, sizeof(bTrue)},
            {CKA_PRIVATE, &bTrue, sizeof(bTrue)},
            {CKA_LABEL, label, strlen((char*)label)},
            {CKA_MODIFIABLE, &bFalse, sizeof(bFalse)},
            {CKA_KEY_TYPE, &RSAKeyType, sizeof(RSAKeyType)},
            {CKA_DECRYPT, &bTrue, sizeof(bTrue)},
            {CKA_SIGN, &bTrue, sizeof(bTrue)},
            {CKA_UNWRAP, &bTrue, sizeof(bTrue)}, 
            {CKA_SENSITIVE, &bTrue, sizeof(bTrue)},     
            {CKA_EXTRACTABLE, &bFalse, sizeof(bFalse)}
        };

 
                           // reset the RSA Key handles
            hPubKey = 0;
            hPrivKey = 0;

 
                           // generate the RSA Key Pair
        rc = pkcs11.GenerateKeyPair( hSession, &genMech,
                                                     pubKeyTemplate, sizeof(pubKeyTemplate)/sizeof(CK_ATTRIBUTE),
                                                     privKeyTemplate, sizeof(privKeyTemplate)/sizeof(CK_ATTRIBUTE),
                                                     &hPubKey, &hPrivKey );
 

    }
             catch (char* e)
    {
                 printf(e);
    }
    catch (...){}

    return rc;
}

 

// ___ RSA ENCRYPT/DECRYPT ____________________________________________________
CK_RV PKCS11_SampleCode::RSAEncryptDecrypt(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hPubKey,CK_OBJECT_HANDLE hPriKey, const CK_BYTE_PTR data, const CK_ULONG dataLen)
{
    printf("\n\n--- RSA Encrypt/Decrypt ----------------\n");


    CK_RV rc;
    try
    {
                           // declare variables
                           CK_ULONG realDataLen = 256 ;  //  Max Size for 2048 bit key
                           CK_BYTE_PTR encData = new CK_BYTE[realDataLen]; 
                           CK_BYTE_PTR decData = new CK_BYTE[realDataLen]; 
                           CK_ULONG encLen = realDataLen;
                           CK_ULONG decLen = realDataLen;
                           CK_ULONG i ;


                           // set up the RSA encrypt/decrypt mechanism (dependent upon the bit length)
              
                          CK_MECHANISM encDecMech = { CKM_RSA_PKCS, NULL_PTR, 0 } ;

                           // encrypt the data
                          rc = pkcs11.EncryptInit(hSession, &encDecMech, hPubKey);
                          rc = pkcs11.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.DecryptInit(hSession, &encDecMech, hPriKey);
                           rc = pkcs11.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
                         delete [] encData;
                         delete [] decData;
    }
             catch (char* e)
    {
                 printf(e);
    }
    catch (...) {}

    return rc;
}

 

 

// *** SHA256 HASH **********************************************************************************

CK_RV PKCS11_SampleCode::sha256Hash(CK_SESSION_HANDLE hSession, CK_BYTE* data, CK_ULONG dataLen, CK_BYTE* hash, CK_ULONG* hashLen) 
{ 
             printf("\n\n--- SHA256 Hash --------------------------\n"); 
    CK_RV rc;
 
    try 
    { 
                           CK_ULONG hLength , i ;
 
                           // declare the hashing mechanism 
                          CK_MECHANISM hashMech = {CKM_SHA256, NULL_PTR, 0};
 
                           // perform a digest 
                           rc = pkcs11.DigestInit(hSession, &hashMech); 
                           rc = pkcs11.Digest(hSession, data, dataLen, hash, hashLen); 
                           hLength = *hashLen ;
 
                           printf("\r\nHashed  Data : %d bytes \r\n", hLength ) ; 
                           for ( i = 0 ; i  < hLength  ; i++ ) { 
                                        printf(" %02X ",hash[i]) ; 
                           } 
                           printf("\r\n") ; 

             } 
             catch (char* e) 
    { 
                 printf(e); 
    } 
    catch (...) {}
 
    return rc; 
}

  

// ___ RSA SIGN/VERIFY ________________________________________________________ 
CK_RV PKCS11_SampleCode::RSASignVerify(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hPubKey, CK_OBJECT_HANDLE hPrivKey, const CK_BYTE_PTR data, const CK_ULONG dataLen) 
{ 
    printf("\n\n--- RSA Sign/Verify --------------------\n");
 
             CK_RV rc; 
    try 
             { 
                           // declare a signature buffer 
                           unsigned char signature[512]; 
                           CK_ULONG signatureLen = sizeof(signature); 
                           CK_ULONG i ;

                           // get an RSA sign/verify mechanism 
                           CK_MECHANISM signVerifyMech = { CKM_RSA_PKCS, NULL_PTR, 0 };

                           // sign the data    
                           rc = pkcs11.SignInit(hSession, &signVerifyMech, hPrivKey);   
                           rc = pkcs11.Sign(hSession, data, dataLen, signature, &signatureLen);

                           printf("\r\nSigned Data : %d bytes \r\n",signatureLen ) ; 
                           for ( i = 0 ; i  < signatureLen  ; i++ ) { 
                                        printf(" %02X ",signature[i]) ; 
                           } 
                           printf("\r\n") ;

                           // verify the signature 
                           rc = pkcs11.VerifyInit(hSession, &signVerifyMech, hPubKey); 
                           rc = pkcs11.Verify(hSession, data, dataLen,  signature, signatureLen); 
                           if ( rc == CKR_OK )  printf("\r\n--Verification is OK----\r\n"); 
                           else printf("\r\n--Verification is  Fail ----\r\n"); 
             } 
             catch (char* e) 
    { 
                 printf(e); 
    } 
             catch(...) {} 
  
             return rc; 
}

예제 프로그램 수행 결과 값

위 프로그램을 수행한 결과 값은 아래와 같이 나옵니다. 2048 Bit RSA Key를 사용하였기 때문에, Encryption 및 Signing 결과 값이 256 byte 입니다. 참고로 CKM_RSA_PKCS Mechanism을 사용할 시, Input Data의 최대 크기는 245(256 – 11) byte 가 되며, Output Data는 256 Byte 가 됩니다. 256 Byte인 이유는 2048 Bit 이기 때문입니다(RSA Encryption에서 결과치는 Key Length와 동일하고, Input Data 최대치는 Key Length – 11 byte 입니다)

Last updated