diff -rupN softhsm-1.1.3/src/lib/main.cpp softhsm-mod/src/lib/main.cpp --- softhsm-1.1.3/src/lib/main.cpp 2010-01-25 20:54:14.000000000 +0100 +++ softhsm-mod/src/lib/main.cpp 2010-02-17 12:38:08.000000000 +0100 @@ -62,6 +62,7 @@ #include #include #include +#include #include #include #include @@ -794,20 +795,190 @@ CK_RV C_FindObjectsFinal(CK_SESSION_HAND return CKR_OK; } -CK_RV C_EncryptInit(CK_SESSION_HANDLE, CK_MECHANISM_PTR, CK_OBJECT_HANDLE) { +CK_RV C_EncryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { DEBUG_MSG("C_EncryptInit", "Calling"); - DEBUG_MSG("C_EncryptInit", "The function is not implemented."); - return CKR_FUNCTION_NOT_SUPPORTED; + CHECK_DEBUG_RETURN(softHSM == NULL_PTR, "C_EncryptInit", "Library is not initialized", + CKR_CRYPTOKI_NOT_INITIALIZED); + + softHSM->lockMutex(); + + SoftSession *session = softHSM->getSession(hSession); + + if(session == NULL_PTR) { + softHSM->unlockMutex(); + + DEBUG_MSG("C_EncryptInit", "Can not find the session"); + return CKR_SESSION_HANDLE_INVALID; + } + + CK_BBOOL hasObject = session->db->hasObject(hKey); + + // TODO: + // Should also add: session->db->getBooleanAttribute(hKey, CKA_SIGN, CK_TRUE) == CK_FALSE + // in the if-statement below. "If this key is allowed to sign data" + // Not doing this for now, because you get higher performance. + + if(hasObject == CK_FALSE || session->db->getObjectClass(hKey) != CKO_PUBLIC_KEY || + session->db->getKeyType(hKey) != CKK_RSA) { + softHSM->unlockMutex(); + + DEBUG_MSG("C_EncryptInit", "This key can not be used"); + return CKR_KEY_HANDLE_INVALID; + } + + CK_BBOOL userAuth = userAuthorization(session->getSessionState(), session->db->getBooleanAttribute(hKey, CKA_TOKEN, CK_TRUE), + session->db->getBooleanAttribute(hKey, CKA_PRIVATE, CK_TRUE), 0); + if(userAuth == CK_FALSE) { + softHSM->unlockMutex(); + + DEBUG_MSG("C_EncryptInit", "User is not authorized"); + return CKR_KEY_HANDLE_INVALID; + } + + if(session->encryptInitialized) { + softHSM->unlockMutex(); + + DEBUG_MSG("C_EncryptInit", "Encrypt is already initialized"); + return CKR_OPERATION_ACTIVE; + } + + if(pMechanism == NULL_PTR) { + softHSM->unlockMutex(); + + DEBUG_MSG("C_EncryptInit", "pMechanism must not be NULL_PTR"); + return CKR_ARGUMENTS_BAD; + } + + EME *paddingFunc = NULL_PTR; + session->encryptSinglePart = false; + + // Selects the correct padding and hash algorithm. + switch(pMechanism->mechanism) { + case CKM_RSA_PKCS: + paddingFunc = new EME_PKCS1v15(); + break; + default: + softHSM->unlockMutex(); + + DEBUG_MSG("C_EncryptInit", "The selected mechanism is not supported"); + return CKR_MECHANISM_INVALID; + break; + } + + if(paddingFunc == NULL_PTR) { + softHSM->unlockMutex(); + + DEBUG_MSG("C_EncryptInit", "Could not create the hash function"); + return CKR_DEVICE_MEMORY; + } + + // Get the key from the session key store. + Public_Key *cryptoKey = session->getKey(hKey); + if(cryptoKey == NULL_PTR) { + softHSM->unlockMutex(); + + DEBUG_MSG("C_EncryptInit", "Could not load the crypto key"); + return CKR_GENERAL_ERROR; + } + + // Creates the encrypter with given key and mechanism. + PK_Encrypting_Key *encryptKey = dynamic_cast(cryptoKey); + session->encryptSize = (cryptoKey->max_input_bits() + 7) / 8; + session->pkEncryptor = new PK_Encryptor_MR_with_EME(*encryptKey, &*paddingFunc); + + if(!session->pkEncryptor) { + softHSM->unlockMutex(); + + DEBUG_MSG("C_EncryptInit", "Could not create the signing function"); + return CKR_DEVICE_MEMORY; + } + + session->encryptInitialized = true; + + softHSM->unlockMutex(); + + DEBUG_MSG("C_EncryptInit", "OK"); + return CKR_OK; } -CK_RV C_Encrypt(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR, CK_ULONG_PTR) { +// Encrypts the data and return the results + +CK_RV C_Encrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pEncrypted, + CK_ULONG_PTR pulEncryptedLen) { DEBUG_MSG("C_Encrypt", "Calling"); - DEBUG_MSG("C_Encrypt", "The function is not implemented."); - return CKR_FUNCTION_NOT_SUPPORTED; + CHECK_DEBUG_RETURN(softHSM == NULL_PTR, "C_Encrypt", "Library is not initialized", + CKR_CRYPTOKI_NOT_INITIALIZED); + + softHSM->lockMutex(); + + SoftSession *session = softHSM->getSession(hSession); + + if(session == NULL_PTR) { + softHSM->unlockMutex(); + + DEBUG_MSG("C_Encrypt", "Can not find the session"); + return CKR_SESSION_HANDLE_INVALID; + } + + if(!session->encryptInitialized) { + softHSM->unlockMutex(); + + DEBUG_MSG("C_Encrypt", "Encrypt is not initialized"); + return CKR_OPERATION_NOT_INITIALIZED; + } + + if(pulEncryptedLen == NULL_PTR) { + softHSM->unlockMutex(); + + DEBUG_MSG("C_Encrypt", "pulEncryptedLen must not be a NULL_PTR"); + return CKR_ARGUMENTS_BAD; + } + + if(pEncrypted == NULL_PTR) { + *pulEncryptedLen = session->encryptSize; + softHSM->unlockMutex(); + + DEBUG_MSG("C_Encrypt", "OK, returning the size of the encrypted"); + return CKR_OK; + } + + if(*pulEncryptedLen < session->encryptSize) { + *pulEncryptedLen = session->encryptSize; + softHSM->unlockMutex(); + + DEBUG_MSG("C_Encrypt", "The given buffer is too small"); + return CKR_BUFFER_TOO_SMALL; + } + + if(pData == NULL_PTR) { + softHSM->unlockMutex(); + + DEBUG_MSG("C_Encrypt", "pData must not be a NULL_PTR"); + return CKR_ARGUMENTS_BAD; + } + + // Encrypt + SecureVector encryptResult = session->pkEncryptor->encrypt(pData, ulDataLen, *session->rng); + + // Returns the result + memcpy(pEncrypted, encryptResult.begin(), session->encryptSize); + *pulEncryptedLen = session->encryptSize; + + // Finalizing + session->encryptSize = 0; + delete session->pkEncryptor; + session->pkEncryptor = NULL_PTR; + session->encryptInitialized = false; + + softHSM->unlockMutex(); + + DEBUG_MSG("C_Encrypt", "OK"); + return CKR_OK; } +// Buffer the data before final encryption CK_RV C_EncryptUpdate(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR, CK_ULONG_PTR) { DEBUG_MSG("C_EncryptUpdate", "Calling"); DEBUG_MSG("C_EncryptUpdate", "The function is not implemented."); @@ -815,6 +986,7 @@ CK_RV C_EncryptUpdate(CK_SESSION_HANDLE, return CKR_FUNCTION_NOT_SUPPORTED; } +// Encrypts the collected data and returns the encrypted data. CK_RV C_EncryptFinal(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG_PTR) { DEBUG_MSG("C_EncryptFinal", "Calling"); DEBUG_MSG("C_EncryptFinal", "The function is not implemented."); @@ -822,18 +994,187 @@ CK_RV C_EncryptFinal(CK_SESSION_HANDLE, return CKR_FUNCTION_NOT_SUPPORTED; } -CK_RV C_DecryptInit(CK_SESSION_HANDLE, CK_MECHANISM_PTR, CK_OBJECT_HANDLE) { +CK_RV C_DecryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { DEBUG_MSG("C_DecryptInit", "Calling"); - DEBUG_MSG("C_DecryptInit", "The function is not implemented."); - return CKR_FUNCTION_NOT_SUPPORTED; + CHECK_DEBUG_RETURN(softHSM == NULL_PTR, "C_DecryptInit", "Library is not initialized", + CKR_CRYPTOKI_NOT_INITIALIZED); + + softHSM->lockMutex(); + + SoftSession *session = softHSM->getSession(hSession); + + if(session == NULL_PTR) { + softHSM->unlockMutex(); + + DEBUG_MSG("C_DecryptInit", "Can not find the session"); + return CKR_SESSION_HANDLE_INVALID; + } + + CK_BBOOL hasObject = session->db->hasObject(hKey); + + // TODO: + // Should also add: session->db->getBooleanAttribute(hKey, CKA_SIGN, CK_TRUE) == CK_FALSE + // in the if-statement below. "If this key is allowed to sign data" + // Not doing this for now, because you get higher performance. + + if(hasObject == CK_FALSE || session->db->getObjectClass(hKey) != CKO_PRIVATE_KEY || + session->db->getKeyType(hKey) != CKK_RSA) { + softHSM->unlockMutex(); + + DEBUG_MSG("C_DecryptInit", "This key can not be used"); + return CKR_KEY_HANDLE_INVALID; + } + + CK_BBOOL userAuth = userAuthorization(session->getSessionState(), session->db->getBooleanAttribute(hKey, CKA_TOKEN, CK_TRUE), + session->db->getBooleanAttribute(hKey, CKA_PRIVATE, CK_TRUE), 0); + if(userAuth == CK_FALSE) { + softHSM->unlockMutex(); + + DEBUG_MSG("C_DecryptInit", "User is not authorized"); + return CKR_KEY_HANDLE_INVALID; + } + + if(session->decryptInitialized) { + softHSM->unlockMutex(); + + DEBUG_MSG("C_DecryptInit", "Encrypt is already initialized"); + return CKR_OPERATION_ACTIVE; + } + + if(pMechanism == NULL_PTR) { + softHSM->unlockMutex(); + + DEBUG_MSG("C_DecryptInit", "pMechanism must not be NULL_PTR"); + return CKR_ARGUMENTS_BAD; + } + + EME *paddingFunc = NULL_PTR; + session->decryptSinglePart = false; + + // Selects the correct padding and hash algorithm. + switch(pMechanism->mechanism) { + case CKM_RSA_PKCS: + paddingFunc = new EME_PKCS1v15(); + break; + default: + softHSM->unlockMutex(); + + DEBUG_MSG("C_DecryptInit", "The selected mechanism is not supported"); + return CKR_MECHANISM_INVALID; + break; + } + + if(paddingFunc == NULL_PTR) { + softHSM->unlockMutex(); + + DEBUG_MSG("C_DecryptInit", "Could not create the hash function"); + return CKR_DEVICE_MEMORY; + } + + // Get the key from the session key store. + Public_Key *cryptoKey = session->getKey(hKey); + if(cryptoKey == NULL_PTR) { + softHSM->unlockMutex(); + + DEBUG_MSG("C_DecryptInit", "Could not load the crypto key"); + return CKR_GENERAL_ERROR; + } + + // Creates the decrypter with given key and mechanism. + PK_Decrypting_Key *decryptKey = dynamic_cast(cryptoKey); + session->decryptSize = (cryptoKey->max_input_bits() + 7) / 8; + session->pkDecryptor = new PK_Decryptor_MR_with_EME(*decryptKey, &*paddingFunc); + + if(!session->pkDecryptor) { + softHSM->unlockMutex(); + + DEBUG_MSG("C_DecryptInit", "Could not create the signing function"); + return CKR_DEVICE_MEMORY; + } + + session->decryptInitialized = true; + + softHSM->unlockMutex(); + + DEBUG_MSG("C_DecryptInit", "OK"); + return CKR_OK; + } -CK_RV C_Decrypt(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR, CK_ULONG_PTR) { +CK_RV C_Decrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pDecrypted, + CK_ULONG_PTR pulDecryptedLen) { DEBUG_MSG("C_Decrypt", "Calling"); - DEBUG_MSG("C_Decrypt", "The function is not implemented."); - return CKR_FUNCTION_NOT_SUPPORTED; + CHECK_DEBUG_RETURN(softHSM == NULL_PTR, "C_Decrypt", "Library is not initialized", + CKR_CRYPTOKI_NOT_INITIALIZED); + + softHSM->lockMutex(); + + SoftSession *session = softHSM->getSession(hSession); + + if(session == NULL_PTR) { + softHSM->unlockMutex(); + + DEBUG_MSG("C_Decrypt", "Can not find the session"); + return CKR_SESSION_HANDLE_INVALID; + } + + if(!session->decryptInitialized) { + softHSM->unlockMutex(); + + DEBUG_MSG("C_Decrypt", "Decrypt is not initialized"); + return CKR_OPERATION_NOT_INITIALIZED; + } + + if(pulDecryptedLen == NULL_PTR) { + softHSM->unlockMutex(); + + DEBUG_MSG("C_Decrypt", "pulDecryptedLen must not be a NULL_PTR"); + return CKR_ARGUMENTS_BAD; + } + + if(pDecrypted == NULL_PTR) { + *pulDecryptedLen = session->decryptSize; + softHSM->unlockMutex(); + + DEBUG_MSG("C_Decrypt", "OK, returning the size of the decrypted"); + return CKR_OK; + } + + if(*pulDecryptedLen < session->decryptSize) { + *pulDecryptedLen = session->decryptSize; + softHSM->unlockMutex(); + + DEBUG_MSG("C_Decrypt", "The given buffer is too small"); + return CKR_BUFFER_TOO_SMALL; + } + + if(pData == NULL_PTR) { + softHSM->unlockMutex(); + + DEBUG_MSG("C_Decrypt", "pData must not be a NULL_PTR"); + return CKR_ARGUMENTS_BAD; + } + + // Decrypt + SecureVector decryptResult = session->pkDecryptor->decrypt(pData, ulDataLen); + + // Returns the result + memcpy(pDecrypted, decryptResult.begin(), session->decryptSize); + *pulDecryptedLen = session->decryptSize; + + // Finalizing + session->decryptSize = 0; + delete session->pkDecryptor; + session->pkDecryptor = NULL_PTR; + session->decryptInitialized = false; + + softHSM->unlockMutex(); + + DEBUG_MSG("C_Decrypt", "OK"); + return CKR_OK; + } CK_RV C_DecryptUpdate(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR, CK_ULONG_PTR) { diff -rupN softhsm-1.1.3/src/lib/mechanisms.cpp softhsm-mod/src/lib/mechanisms.cpp --- softhsm-1.1.3/src/lib/mechanisms.cpp 2010-01-25 20:54:14.000000000 +0100 +++ softhsm-mod/src/lib/mechanisms.cpp 2010-02-17 11:02:46.000000000 +0100 @@ -50,7 +50,7 @@ CK_RV getMechanismInfo(CK_MECHANISM_TYPE case CKM_RSA_PKCS: pInfo->ulMinKeySize = 512; pInfo->ulMaxKeySize = 4096; - pInfo->flags = CKF_SIGN | CKF_VERIFY | CKF_HW; + pInfo->flags = CKF_SIGN | CKF_VERIFY | CKF_ENCRYPT | CKF_DECRYPT | CKF_HW; break; case CKM_MD5: case CKM_RIPEMD160: diff -rupN softhsm-1.1.3/src/lib/SoftSession.cpp softhsm-mod/src/lib/SoftSession.cpp --- softhsm-1.1.3/src/lib/SoftSession.cpp 2010-01-25 20:54:14.000000000 +0100 +++ softhsm-mod/src/lib/SoftSession.cpp 2010-02-17 10:42:52.000000000 +0100 @@ -73,6 +73,16 @@ SoftSession::SoftSession(CK_FLAGS rwSess verifySize = 0; verifyInitialized = false; + pkEncryptor = NULL_PTR; + encryptSinglePart = false; + encryptSize = 0; + encryptInitialized = false; + + pkDecryptor = NULL_PTR; + decryptSinglePart = false; + decryptSize = 0; + decryptInitialized = false; + keyStore = new SoftKeyStore(); rng = new AutoSeeded_RNG(); @@ -99,6 +109,8 @@ SoftSession::~SoftSession() { DELETE_PTR(pkSigVerData); #endif DELETE_PTR(pkVerifier); + DELETE_PTR(pkEncryptor); + DELETE_PTR(pkDecryptor); DELETE_PTR(keyStore); DELETE_PTR(rng); DELETE_PTR(db); diff -rupN softhsm-1.1.3/src/lib/SoftSession.h softhsm-mod/src/lib/SoftSession.h --- softhsm-1.1.3/src/lib/SoftSession.h 2010-01-25 20:54:14.000000000 +0100 +++ softhsm-mod/src/lib/SoftSession.h 2010-02-17 10:42:52.000000000 +0100 @@ -92,6 +92,18 @@ class SoftSession { bool verifySinglePart; CK_ULONG verifySize; bool verifyInitialized; + + // Encrypt + PK_Encryptor *pkEncryptor; + bool encryptSinglePart; + CK_ULONG encryptSize; + bool encryptInitialized; + + // Decrypt + PK_Decryptor *pkDecryptor; + bool decryptSinglePart; + CK_ULONG decryptSize; + bool decryptInitialized; // Key store Public_Key* getKey(CK_OBJECT_HANDLE hKey);