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