/*********************************************************************** * * Copyright (C) 2005-2006 Novell, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; version 2.1 * of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, Novell, Inc. * * To contact Novell about this file by physical or electronic mail, * you may find current contact information at www.novell.com. * ***********************************************************************/ #include "CryptManager.h" void CryptManager::SetupFunctions(void *funList[]) { //PK11SetPasswordFunc = (PK11_SetPasswordFunc) funList[0]; PK11GetInternalKeySlot = (PK11_GetInternalKeySlot) funList[1]; PK11FreeSlot = (PK11_FreeSlot) funList[2]; PK11Authenticate = (PK11_Authenticate) funList[3]; PK11CheckUserPassword =(PK11_CheckUserPassword) funList[4]; PK11SDRDecrypt = (PK11SDR_Decrypt) funList[5]; PK11SDREncrypt = (PK11SDR_Encrypt) funList[6]; PLBase64Encode = (PL_Base64Encode) funList[7]; PLBase64Decode = (PL_Base64Decode) funList[8]; } int CryptManager::GetEncryptionPref() { return FPM_TRUE; } /** * This function encrypts the clear text data. First it performs TRIPLE DES encryption * and then performs base64 encoding on the encrypted data. * * @param(in) clearData clear text data to be encrypted * @param(out) finalData encrypted data ( null terminated) * * @return FPM_TRUE on success and FPM_FALSE on error. * */ int CryptManager::EncryptString (char *clearData, char **finalData) { int encryptDataLen = 0; char *encryptData = NULL; char *encodeData = NULL; int retValue; if( clearData == NULL ) { PrintMessage(MESG_ERROR, "\n EncryptString : Text Data is NULL"); return FPM_FALSE; } // Do the encryption if encryption pref is set otherwise just do base64 encoding... if ( GetEncryptionPref() ) { PrintMessage(MESG_DEBUG, "\n EncryptString : Performing PK11 Encryption..."); retValue = FPM_FALSE; if( ((retValue = CryptPK11EncryptString(clearData, strlen(clearData), &encryptData, &encryptDataLen)) != FPM_TRUE) || ( encryptData == NULL) ) { PrintMessage(MESG_ERROR, "\n EncryptString : Failed to encrypt the string : %s ", clearData); return retValue; } if( (CryptBase64Encode(encryptData, encryptDataLen, finalData) != FPM_TRUE) || (*finalData == NULL) ) { PrintMessage(MESG_ERROR, "\n EncryptString : BASE64 encoding failed"); return FPM_FALSE; } PrintMessage(MESG_DEBUG, "\n EncryptString : Success "); // WARNING : If you uncomment , then be ready for side effects , crashes..etc // Need full analysis of malloc for this data.. // Free the allocated blocks... //if( encryptData ) // free( encryptData); return FPM_TRUE; } // otherwise do our own obscuring using Base64 encoding PrintMessage(MESG_DEBUG, "\n EncryptString : Performing JUST base64 encoding..."); if( (CryptBase64Encode(clearData, strlen(clearData), &encodeData) == FPM_FALSE) || (encodeData == NULL) ) { PrintMessage(MESG_ERROR, "\n EncryptString : BASE64 encoding failed"); return FPM_FALSE; } // We need to add the CRYPT_PREFIX at the begining of encoded data... // This will help during decrption process to identify type of encryption int prefixLen = strlen( CRYPT_PREFIX ); int encodeLen = strlen( encodeData ); *finalData = (char *)malloc( prefixLen + encodeLen + 1); if( *finalData == NULL ) { PrintMessage(MESG_ERROR, "\n EncryptString : Insufficient memory"); return FPM_FALSE; } // FinalData = CRYPT_PREFIX + Encoded Data + '\0' strcpy(*finalData, CRYPT_PREFIX); strcat(*finalData, encodeData); *(*finalData + prefixLen + encodeLen) = 0; free(encodeData); return FPM_TRUE; } /** * This function decrypts the encrypted data. First it performs base64 decoding and * then performs TRIPLE DES decryption. * * @param(in) cryptData encrypted data * @param(out) clearData clear text data ( null terminated) * * @return FPM_TRUE on success and FPM_FALSE on error. * */ int CryptManager::DecryptString(char *cryptData, char **clearData) { int decodeLen = 0; int finalLen = 0; char *decodeData = NULL; char *finalData = NULL; int retValue; if( cryptData == NULL ) { PrintMessage(MESG_ERROR, "\n DecryptString: CryptData is NULL..."); return FPM_FALSE; } // treat zero-length crypt string as a special case if(cryptData[0] == '\0') { *clearData = (char*) malloc(1); **clearData = 0; return FPM_TRUE; } // use PK11 encryption stuff if crypt doesn't starts with prefix if( cryptData[0] != CRYPT_PREFIX[0] ) { PrintMessage(MESG_DEBUG, "\n Performing PK11 Decryption "); // First do base64 decoding..... if( (CryptBase64Decode(cryptData, &decodeData, &decodeLen) != FPM_TRUE) || (decodeData == NULL) ) { PrintMessage(MESG_ERROR, "\n DecryptString : Base64 decoding of crypt data failed "); return FPM_FALSE; } PrintMessage(MESG_DEBUG, "\n DecryptString : base64data (%d) = %s ", decodeLen, decodeData); // Now do actual PK11 decryption retValue = FPM_FALSE; retValue = CryptPK11DecryptString(decodeData, decodeLen, &finalData, &finalLen); if( retValue != FPM_TRUE ) { PrintMessage(MESG_ERROR, "\n DecryptString : Failed to decrypt the string "); return retValue; } // WARNING : Decrypted string is not NULL terminated // So we will create new NULL terminated string here... *clearData = (char*) malloc( finalLen + 1 ); if( *clearData == NULL ) { PrintMessage(MESG_ERROR, "\n DecryptString :Insufficient memory... "); return FPM_INSUFFICIENT_MEMORY; } else { PrintMessage(MESG_DEBUG, "\n DecryptString : Copying new data ...."); memcpy(*clearData, finalData, finalLen); *(*clearData + finalLen) = 0; // Null terminate the string.... } /* // Free the allocated memory // This is causing the problems currently...Later point we have to reanalyze the cause for this if( decodeData ) free(decodeData); if( finalData ) free(finalData); */ PrintMessage(MESG_DEBUG, "\n decryptString : finalLen = %d ", finalLen); return FPM_TRUE; } // otherwise do our own de-obscuring PrintMessage(MESG_DEBUG, "\n DecryptString : Performing simple Base64 Decoding "); unsigned int PREFIX_Len = strlen(CRYPT_PREFIX); if( strlen(cryptData) == PREFIX_Len ) { *clearData = (char *)malloc(1); **clearData = '\0'; return FPM_TRUE; } if( CryptBase64Decode(&cryptData[PREFIX_Len], clearData, &decodeLen) == FPM_FALSE ) { PrintMessage(MESG_ERROR, "\n DecryptString : Base64 decoding of crypt data failed "); return FPM_FALSE; } return FPM_TRUE; } /** * Performs base64 encoding of the encrypted data.. * * @param(in) cryptData encrypted data * @param(in) cryptDataLen length of encrypted data * @param(out) encodeData base64 encoded data * * @return FPM_TRUE on success and FPM_FALSE on error. * */ int CryptManager::CryptBase64Encode(char *cryptData, int cryptDataLen, char **encodeData) { *encodeData = (*PLBase64Encode)((const char *)cryptData, cryptDataLen, NULL); if ( *encodeData == NULL ) { PrintMessage(MESG_ERROR, "\n Base64 encoding failed ..."); return FPM_FALSE; } return FPM_TRUE; } /** * Performs base64 decoding of the encrypted data.. * * @param(in) cryptData encrypted data * @param(out) decodeData base64 decoded data * @param(out) decodeLen length of base64 decoded data * * @return FPM_TRUE on success and FPM_FALSE on error. * */ int CryptManager::CryptBase64Decode(char *cryptData, char **decodeData, int *decodeLen) { int len = strlen( cryptData ); int adjust = 0; PrintMessage(MESG_DEBUG, "\n CryptBase64Decode : Length of crypt data = %d", len); // Compute length adjustment if (cryptData[len-1] == '=') { adjust++; if (cryptData[len-2] == '=') adjust++; } *decodeData = ( char *)(*PLBase64Decode)(cryptData, len, NULL); if( *decodeData == NULL ) { PrintMessage(MESG_ERROR, "\n Base64 decoding failed ..."); return FPM_FALSE; } *decodeLen = (len*3)/4 - adjust; PrintMessage(MESG_DEBUG, "\n CryptBase64Decode : Length of decoded data = %d", *decodeLen); return FPM_TRUE; } /** * Performs TRIPLE DES encryption of clear text data * * @param(in) clearData clear text data to be encrypted * @param(in) clearDataLen length of clear text data * @param(out) cryptData TRIPLE DES encrypted data * @param(out) cryptDataLen length of encrypted data * * @return FPM_TRUE on success and FPM_FALSE on error. * */ int CryptManager::CryptPK11EncryptString(char *clearData, int clearDataLen, char **cryptData, int *cryptDataLen) { PK11SlotInfo *slot = 0; SECItem keyid; SECItem request; SECItem reply; SECStatus status; slot = (*PK11GetInternalKeySlot)(); if (!slot) { PrintMessage(MESG_ERROR, "\n CryptPK11EncryptString : PK11_GetInternalKeySlot failed ..."); return FPM_FALSE; } // PK11 authentication if ( (*PK11Authenticate)(slot, PR_TRUE, NULL) != SECSuccess) { // since we have specified password callback function , we won't come here... PrintMessage(MESG_ERROR, "\n CryptPK11EncryptString : PK11_Authenticate failed, possibly master password is wrong"); (*PK11FreeSlot) (slot); return FPM_MASTERPASSWORD_WRONG; } // Use default key id keyid.data = 0; keyid.len = 0; request.data = (unsigned char *)clearData; request.len = clearDataLen; reply.data = 0; reply.len = 0; status = (*PK11SDREncrypt)(&keyid, &request, &reply, NULL); if (status != SECSuccess) { PrintMessage(MESG_ERROR, "\n CryptPK11EncryptString : PK11SDR_Encrypt failed ..."); (*PK11FreeSlot) (slot); return FPM_FALSE; } *cryptData = (char*)reply.data; *cryptDataLen = reply.len; (*PK11FreeSlot) (slot); return FPM_TRUE; } /** * Performs TRIPLE DES decryption of base64 decoded data * * @param(in) decodeData base64 decoded data * @param(in) decodeLen length of base64 decoded data * @param(out) clearData decrypted data * @param(out) finalLen length of decrypted data * * @return FPM_TRUE on success and FPM_FALSE on error. * */ int CryptManager::CryptPK11DecryptString(char *decodeData, int decodeLen, char **clearData, int *finalLen) { PK11SlotInfo *slot = 0; SECStatus status; SECItem request; SECItem reply; PrintMessage(MESG_DEBUG, "\n CryptPK11DecryptString entered ..."); // Find token with SDR key slot = (*PK11GetInternalKeySlot)(); if (!slot) { PrintMessage(MESG_ERROR, "\n PK11_GetInternalKeySlot failed ..."); return FPM_FALSE; } PrintMessage(MESG_DEBUG, "\n PK11_GetInternalKeySlot SUCCESS ..."); // Force authentication if ( (*PK11Authenticate)(slot, PR_TRUE, NULL) != SECSuccess) { // since we have specified password callback function , we won't come here... PrintMessage(MESG_ERROR, "\n PK11_Authenticate failed, Probably master password is wrong"); (*PK11FreeSlot) (slot); return FPM_MASTERPASSWORD_WRONG; } PrintMessage(MESG_DEBUG, "\n PK11_Authenticate SUCCESS ..."); // Decrypt the string request.data = (unsigned char *)decodeData; request.len = decodeLen; reply.data = 0; reply.len = 0; PrintMessage(MESG_DEBUG, "\n calling PK11SDR_Decrypt ..."); status = (*PK11SDRDecrypt)(&request, &reply, NULL); if (status != SECSuccess) { PrintMessage(MESG_ERROR, "\n PK11SDR_Decrypt failed ..."); (*PK11FreeSlot) (slot); return FPM_FALSE; } PrintMessage(MESG_DEBUG, "\n PK11SDR_Decrypt SUCCESS "); // WARNING : This string is not NULL terminated.. *clearData = (char*)reply.data; *finalLen = reply.len; // Free the slot (*PK11FreeSlot) (slot); return FPM_TRUE; }