Decrypt Function
For our decryption, we want to basically reverse the processes that were covered previously in the encryption section.
1.Following the initial function setup, we firstly check for our input and output files.
2.Once file existence is established, we test for our password-based encryption runtime switch. It can be seen that once again we generate the same secret key from the input password that we will need for the decryption. Since this was a secret key cipher, we use the same key for encryption as well as decryption.
#undef FN
#define FN "decryptFile:"
int decryptFile( char * sender, char * recipient,char * ifile, char * ofile ) {
CK_SLOT_ID hsSlot;
CK_OBJECT_HANDLE hsKey;
CK_SESSION_HANDLE hsSession;
CK_SLOT_ID hrSlot;
CK_OBJECT_HANDLE hrKey;
CK_SESSION_HANDLE hrSession;
CK_RV rv;
CK_MECHANISM mech;
CK_BYTE digest[80];
CK_SIZE len;
CK_OBJECT_HANDLE hKey;
CK_BYTE wrappedKey[2 * 1024];
CK_SIZE wrappedKeyLen;
CK_BYTE signature[2 * 1024];
CK_BYTE iv[8];
unsigned long encodedSize;
FILE * ifp;
FILE * ofp;
int br;
ifp = fopen(ifile, "rb");if ( ifp == NULL ) {fprintf( stderr, "Cannot open %s for input\n",ifile ); return -1;
}
ofp = fopen(ofile, "wb");
if ( ofp == NULL ) {
fprintf( stderr, "Cannot open %s for input\n",ofile ); return -1; } if ( pflag ) {/* use PBE to do the encryption */static CK_OBJECT_CLASS at_class = CKO_SECRET_KEY;static CK_KEY_TYPE kt = CKK_DES2; static const CK_BBOOL True = TRUE;static const CK_BBOOL False = FALSE;CK_ATTRIBUTE attr[] = { {CKA_CLASS, &at_class, sizeof(at_class)}, {CKA_KEY_TYPE, &kt, sizeof(at_class)}, {CKA_EXTRACTABLE, (void*)&True, sizeof(True)},
{CKA_SENSITIVE, (void*)&False,
sizeof(False)},
{CKA_DERIVE, (void*)&True, sizeof(True)} };CK_BYTE iv[8]; CK_PBE_PARAMS params; memset(¶ms, 0x0, sizeof(CK_PBE_PARAMS));params.pInitVector = iv;params.pPassword = sender;params.passwordLen = strlen(sender);params.pSalt = NULL;params.saltLen = 0;params.iteration = 1; memset(&mech, 0x0, sizeof(CK_MECHANISM));mech.mechanism = CKM_PBE_SHA1_DES2_EDE_CBC;mech.pParameter = ¶ms;mech.parameterLen = sizeof(CK_PBE_PARAMS); rv = C_OpenSession(0,
CKF_RW_SESSION|CKF_SERIAL_SESSION, NULL,
NULL, &hsSession);
if ( rv ) return 1;
hrSession = hsSession;
rv = C_GenerateKey(hsSession, &mech, attr,
NUMITEMS(attr),
&hKey);CHECK_RV(FN "C_GenerateKey:CKM_PBE_SHA1_DES2_EDE_CBC", rv);if ( rv ) return 1; memset(&mech, 0x0, sizeof(CK_MECHANISM));mech.mechanism = CKM_SHA1_KEY_DERIVATION; rv = C_DeriveKey(hsSession, &mech, hKey, attr,NUMITEMS(attr),&hrKey);CHECK_RV(FN "C_DeriveKey:CKM_SHA1_KEY_DERIVATION", rv); if ( rv ) return 1;}
3.For our public key cipher, we will use the recipient’s private RSA key to unwrap the secret DES key contained in the input file. The DES key will then be used to decrypt the file.
The PKCS#11 function C_UnwrapKey is used to decrypt (unwrap) a wrapped key, creating a new private key or secret key object. This function requires the session handle, a pointer to the unwrapping mechanism, the handle of the unwrapping key, a pointer to the wrapped key, the length of the wrapped key, a pointer to the template for the new key, the number of attributes in the template, and a pointer to the location that receives the handle of the recovered key.
else {
/* decrypting */
rv = FindKeyFromName(sender, CKO_CERTIFICATE,
&hsSlot, &hsSession, &hsKey);if ( rv ) {rv = FindKeyFromName(sender, CKO_PUBLIC_KEY, &hsSlot, &hsSession, &hsKey);
}
if ( rv ) {
fprintf( stderr, "Unable to access sender (%s)key\n", sender );CHECK_RV(FN "FindKeyFromName", rv);if ( rv ) return 1; }rv = FindKeyFromName(recipient, CKO_PRIVATE_KEY,&hrSlot, &hrSession, &hrKey);if ( rv ) {fprintf( stderr, "Unable to access recipient (%s) key\n", recipient );CHECK_RV(FN "FindKeyFromName", rv);if ( rv ) return 1;} /* read the encrypted key to the file */br = fread(&encodedSize, 1, sizeof(encodedSize), ifp);wrappedKeyLen = (CK_SIZE) ntohl((unsigned long) encodedSize);br = fread(wrappedKey, 1, (int)wrappedKeyLen, ifp); /* unwrap decryption key with the recipients private key */
memset(&mech,0,sizeof(mech));
mech.mechanism = CKM_RSA_PKCS;
rv = C_UnwrapKey(hrSession, &mech, hrKey,
wrappedKey, wrappedKeyLen, wrappedKeyTemp, NUMITEMS(wrappedKeyTemp), &hKey ); CHECK_RV(FN "C_UnwrapKey", rv);
if ( rv ) return 1;
}
4.Now that we have recovered the decryption key, we perform our initialization in exactly the same manner as for our encryption, but using the function C_DecryptInit. The digest is calculated in the same manner used for the encryption.
5.For the file decryption we are using the functions C_DecryptUpdate and C_DecryptFinal which take the same parameters as their encrypt counterparts.
/* set up the decryption operation using the random key */
memset(&mech, 0, sizeof(CK_MECHANISM));
mech.mechanism = CKM_DES3_CBC_PAD;
memset(iv, 0, sizeof(iv));
mech.pParameter = iv;
mech.parameterLen = sizeof(iv);
rv = C_DecryptInit(hrSession, &mech, hKey);
CHECK_RV(FN"C_EncryptInit", rv);
if ( rv ) return 1;
/* Set up the digest operation */
memset(&mech, 0, sizeof(CK_MECHANISM));
mech.mechanism = CKM_SHA_1;
rv = C_DigestInit(hrSession, &mech);
CHECK_RV(FN "C_DigestInit", rv);
if ( rv ) return 1;
{
CK_SIZE curLen;
CK_SIZE slen;
unsigned char buffer[10 * 1024];
unsigned char decbuffer[10 * 1024];
unsigned int br;
br = fread(&encodedSize, 1, sizeof(encodedSize), ifp);
encodedSize = htonl(encodedSize);
for ( ;encodedSize > 0; ) {
br = sizeof(buffer);
if ( encodedSize < br )
br = (unsigned int)encodedSize;br = fread(buffer, 1, br, ifp);encodedSize -= br;if ( br ) { curLen = sizeof(decbuffer); rv = C_DecryptUpdate(hrSession, buffer,(CK_SIZE) br, decbuffer, &curLen); CHECK_RV(FN "C_DecryptUpdate", rv); if ( rv ) return 1;rv = C_DigestUpdate(hrSession, decbuffer, curLen); CHECK_RV(FN "C_DigestUpdate", rv); if ( rv ) return 1;br = fwrite(decbuffer, 1, (unsigned int)curLen,
ofp);
}}curLen = sizeof(decbuffer);rv = C_DecryptFinal(hrSession, decbuffer, &curLen);CHECK_RV(FN "C_DecryptFinal", rv); if ( rv ) return 1;if ( curLen ) {br = fwrite(decbuffer, 1, (unsigned int)curLen, ofp); rv = C_DigestUpdate(hrSession, decbuffer, curLen);CHECK_RV(FN "C_DigestUpdate", rv); }
len = sizeof(digest);
rv = C_DigestFinal(hrSession, digest, &len);
CHECK_RV(FN "C_DigestFinal", rv);
if ( rv ) return 1;
6.Finally, we verify the signature contained in the data file. Since the signature is identical to the digest when using the password-based encryption option, it is a simple matter of comparing the two. For our DES encryption on the other hand, we need to verify the signature against the sender’s public key.
To perform this we start by calling C_VerifyInit that initializes a verification operation, where the signature is an appendix to the data. This function requires the session’s handle, a pointer to the structure that specifies the verification mechanism and the handle of the verification key.
/* read the signature from the file */br = fread(&encodedSize, 1, sizeof(encodedSize), ifp);slen = (CK_SIZE) ntohl((unsigned long) encodedSize);br = fread(signature, 1, (unsigned int)slen, ifp); if ( pflag ) { if ( memcmp(digest, signature, len) ) {fprintf( stderr, "Verify failed\n" );return 1; }
}
else {
/* Set up the signature verify operation */
memset(&mech, 0, sizeof(CK_MECHANISM));
mech.mechanism = CKM_RSA_PKCS;
rv = C_VerifyInit(hsSession, &mech, hsKey);
CHECK_RV(FN "C_VerifyInit", rv);
if ( rv ) return 1;
rv = C_Verify(hsSession, digest, len, signature, slen);
if ( rv ) {
C_ErrorString(rv,ErrorString,sizeof(ErrorString));fprintf( stderr, "Verify failed 0x%x, %s\n", rv, ErrorString ); }} /* clean up */
fclose(ifp);
fclose(ofp);
} C_CloseSession(hrSession);
C_CloseSession(hsSession);
return (int)rv;
}
Next, see FCrypt Usage.