Note: openssl-dev is inappropriate, as it is meant for the _development_ _of_ OpenSSL. Your inquiry is about the _use_ of OpenSSL, making openssl-users much more appropriate. I'm therefore redirecting it there.
In message <[EMAIL PROTECTED]> on Wed, 12 Mar 2008 18:50:10 +0800, "Xu, Qiang (FXSGSC)" <[EMAIL PROTECTED]> said: Qiang.Xu> But how to explain that passwords like "$dlkins02", Qiang.Xu> "$flkins02", and "$Elkins02" can be decrypted correctly? Qiang.Xu> Only "$elkins02" is decrypted into empty string. Sheer freaking luck! You're doing three mistakes: 1. you're assuming the EVP routines treat your data as character strings. That's incorrect, it treats them as binary blobs. Any of the bytes in that blob can be zero, and apparently, you're getting a result that starts with a zero byte. 2. you're not using the resulting length from the EVP routines. Doing so will give you correct answer, strlen() is not guaranteed to do that (it will only give you the correct answer if you have no zero byte anywhere in the result). 3. you're also not checking the returned result from the EVP routines. Qiang.Xu> To be more specific, this is the code to decrypt: Qiang.Xu> ============================================================ Qiang.Xu> bool_t esscrypto_decryptString(unsigned char *toDecrypt, Qiang.Xu> unsigned char *passPhrase, Qiang.Xu> int sizeOfStrToDecrypt, Qiang.Xu> int maxDecryptedStringSize, Qiang.Xu> int *sizeOfDecryptedString, Qiang.Xu> unsigned char **decryptedString) Qiang.Xu> { Qiang.Xu> EVP_CIPHER_CTX openSSLDecryptionStructure; Qiang.Xu> int tempOutputLength = 0; Qiang.Xu> int i = 0; Qiang.Xu> int tmpOutputBufferPosition = 0; Qiang.Xu> int tmpOffset = 0; Qiang.Xu> char *tempPassPhrase = NULL; Qiang.Xu> int currentDecryptedStrLength = 0; Qiang.Xu> char *tempPtr = NULL; Qiang.Xu> Qiang.Xu> LOGLIBENTER(__FUNCTION__); Qiang.Xu> Qiang.Xu> tempPtr = ess_crypto_get_hex_string_from_string(toDecrypt); Qiang.Xu> if (tempPtr != NULL) Qiang.Xu> { Qiang.Xu> LOGFORCE("Decrypting string (in hex) [%s]", tempPtr); Qiang.Xu> free(tempPtr); Qiang.Xu> } Qiang.Xu> Qiang.Xu> /* initialize return values */ Qiang.Xu> *sizeOfDecryptedString = 0; Qiang.Xu> *decryptedString = NULL; Qiang.Xu> Qiang.Xu> /* Qiang.Xu> * Paranoia, if we get "really" big strings to decrypt, we should reject Qiang.Xu> * them in favor of a buffered string decryption method (like what is Qiang.Xu> * done for files). So spit out a warning and return false. Qiang.Xu> ******/ Qiang.Xu> if ( sizeOfStrToDecrypt > ESS_CRYPTO_MAX_TO_DECRYPT_STR_SIZE ) Qiang.Xu> { Qiang.Xu> LOGWARN("Decrypting string of size [%d] is too big to decrypt", Qiang.Xu> sizeOfStrToDecrypt); Qiang.Xu> LOGLIBRETURN(__FUNCTION__); Qiang.Xu> return (FALSE); Qiang.Xu> } Qiang.Xu> Qiang.Xu> tempPassPhrase = essCrypto_setupPassPhrase(passPhrase); Qiang.Xu> Qiang.Xu> if (tempPassPhrase == NULL) Qiang.Xu> { Qiang.Xu> LOGWARN("PassPhrase is null"); Qiang.Xu> LOGLIBRETURN(__FUNCTION__); Qiang.Xu> return(FALSE); Qiang.Xu> } Qiang.Xu> Qiang.Xu> EVP_DecryptInit(&openSSLDecryptionStructure, EVP_des_cbc(), tempPassPhrase, Qiang.Xu> (char *) NULL); Qiang.Xu> Qiang.Xu> /**** Qiang.Xu> * Since we are using DES, we don't need to set the key length always Qiang.Xu> set to 64 bits, but if we use other ciphers, we need to do the following: Qiang.Xu> EVP_CIPHER_CTX_set_key_length(&openSSLDecryptionStructure, <size>); Qiang.Xu> // re-init Qiang.Xu> EVP_DecryptInit(&openSSLDecryptionStructure, NULL, passPhrase, Qiang.Xu> (char *)NULL); Qiang.Xu> ****/ Qiang.Xu> tempOutputLength = sizeOfStrToDecrypt + Qiang.Xu> EVP_CIPHER_CTX_block_size(&openSSLDecryptionStructure) + 1; Qiang.Xu> Qiang.Xu> /* Qiang.Xu> * If the caller put in a non-negative or zero value for the max decrypted Qiang.Xu> * size, then the caller cares about how big of a string will be returned Qiang.Xu> * to it. So check to make sure it can handle the size of string that will Qiang.Xu> * be returned for decrypted data. Qiang.Xu> ******/ Qiang.Xu> if (maxDecryptedStringSize > 0) Qiang.Xu> { Qiang.Xu> /* Qiang.Xu> * If we are going to need more memory than the caller wants to use for Qiang.Xu> * the decrypted string, spit out an error and return false (since Qiang.Xu> * we cannot decrypt the string to the callers limitations). Qiang.Xu> ******/ Qiang.Xu> if (tempOutputLength > maxDecryptedStringSize) Qiang.Xu> { Qiang.Xu> LOGERROR( Qiang.Xu> "Cannot decrypt data, decrypted Size [%d] is going to be too big!", Qiang.Xu> tempOutputLength); Qiang.Xu> essCrypto_freePassPhrase(tempPassPhrase); Qiang.Xu> LOGLIBRETURN(__FUNCTION__); Qiang.Xu> return(FALSE); Qiang.Xu> } Qiang.Xu> } Qiang.Xu> Qiang.Xu> /* malloc memory for the decrypted string */ Qiang.Xu> *decryptedString = malloc(tempOutputLength); Qiang.Xu> Qiang.Xu> /* Qiang.Xu> * Make sure we successfully malloced memory for the decryptedString string Qiang.Xu> ******/ Qiang.Xu> if (*decryptedString == NULL) Qiang.Xu> { Qiang.Xu> LOGERROR("Unable to malloc memory for decryption"); Qiang.Xu> essCrypto_freePassPhrase(tempPassPhrase); Qiang.Xu> LOGLIBRETURN(__FUNCTION__); Qiang.Xu> return (FALSE); Qiang.Xu> } Qiang.Xu> Qiang.Xu> /* clean out the memory for the returned string */ Qiang.Xu> memset(*decryptedString, 0, tempOutputLength); Qiang.Xu> Qiang.Xu> /* Qiang.Xu> * Loop around decrypting the string with the buffer allocated for Qiang.Xu> * decryption till we cannot fill up the buffer with data anymore. Qiang.Xu> ******/ Qiang.Xu> for (i = 0; i < sizeOfStrToDecrypt/ ESS_CRYPTO_CRYPT_BUFFER_SIZE; i++) Qiang.Xu> { Qiang.Xu> /* decrypt the contents of the buffer */ Qiang.Xu> EVP_DecryptUpdate(&openSSLDecryptionStructure, Qiang.Xu> &((*decryptedString)[tmpOutputBufferPosition]), Qiang.Xu> &tmpOffset, Qiang.Xu> &toDecrypt[tmpOutputBufferPosition], Qiang.Xu> ESS_CRYPTO_CRYPT_BUFFER_SIZE); Qiang.Xu> Qiang.Xu> /* Increment the position we are at in decrypting the string */ Qiang.Xu> tmpOutputBufferPosition = tmpOutputBufferPosition + tmpOffset; Qiang.Xu> } Qiang.Xu> Qiang.Xu> /* Qiang.Xu> * if there is data left to decrypt that did not fit exactly within Qiang.Xu> * the buffer, decrypt that remaining bit. Qiang.Xu> ******/ Qiang.Xu> if ( sizeOfStrToDecrypt % ESS_CRYPTO_CRYPT_BUFFER_SIZE) Qiang.Xu> { Qiang.Xu> /* decrypt the contents of the buffer */ Qiang.Xu> EVP_DecryptUpdate(&openSSLDecryptionStructure, Qiang.Xu> &((*decryptedString)[tmpOutputBufferPosition]), Qiang.Xu> &tmpOffset, Qiang.Xu> &toDecrypt[tmpOutputBufferPosition], Qiang.Xu> sizeOfStrToDecrypt % ESS_CRYPTO_CRYPT_BUFFER_SIZE); Qiang.Xu> Qiang.Xu> /* Increment the position we are at in decrypting the string */ Qiang.Xu> tmpOutputBufferPosition = tmpOutputBufferPosition + tmpOffset; Qiang.Xu> Qiang.Xu> } Qiang.Xu> Qiang.Xu> /* finalize the results from decryption (check CRC) */ Qiang.Xu> EVP_DecryptFinal(&openSSLDecryptionStructure, Qiang.Xu> &((*decryptedString)[tmpOutputBufferPosition]), Qiang.Xu> &tmpOffset); Qiang.Xu> Qiang.Xu> /* set the final length of the decrypted string */ Qiang.Xu> *sizeOfDecryptedString = tmpOutputBufferPosition + tmpOffset; Qiang.Xu> Qiang.Xu> /* see what the length is according to strlen */ Qiang.Xu> currentDecryptedStrLength = strlen(*decryptedString); Qiang.Xu> LOGFORCE("lenght of decrypted string is %d", currentDecryptedStrLength); //xq Qiang.Xu> Qiang.Xu> Qiang.Xu> /* Qiang.Xu> * If we have the room in memory, NULL terminate the string (just in case Qiang.Xu> * it has not already been done). Even thought we null out the entire Qiang.Xu> * string when memory was malloc'ed for it. Qiang.Xu> ******/ Qiang.Xu> if (*sizeOfDecryptedString < tempOutputLength) Qiang.Xu> { Qiang.Xu> (*decryptedString)[*sizeOfDecryptedString] = (char) 0; Qiang.Xu> } Qiang.Xu> Qiang.Xu> /* Qiang.Xu> * If the OpenSSL length (sizeOfDecryptedString is less than the determined Qiang.Xu> * strlen, it means OpenSSL didn't clean up after itself and it left the Qiang.Xu> * encryption "salt" in the string. If this is the case, remove the Qiang.Xu> * salt from memory (since it could contain sensitive information). Qiang.Xu> ******/ Qiang.Xu> if (*sizeOfDecryptedString < currentDecryptedStrLength) Qiang.Xu> { Qiang.Xu> LOGDEBUG("Cleaning up Salt in Decrypted String"); Qiang.Xu> Qiang.Xu> /* Qiang.Xu> * loop around and null out each "salt" character in the string Qiang.Xu> ******/ Qiang.Xu> for (i = *sizeOfDecryptedString; i < currentDecryptedStrLength; i++) Qiang.Xu> { Qiang.Xu> (*decryptedString)[i] = (char) 0; Qiang.Xu> } Qiang.Xu> } Qiang.Xu> Qiang.Xu> LOGREALLYSECURE("Decrypted String is [%s]", *decryptedString); Qiang.Xu> Qiang.Xu> essCrypto_freePassPhrase(tempPassPhrase); Qiang.Xu> LOGLIBRETURN(__FUNCTION__); Qiang.Xu> return (TRUE); Qiang.Xu> } Qiang.Xu> ============================================================ Qiang.Xu> Here, the decrypted byte array is re-arranged into a character string representing the decrypted string. As far as I can see, EVP_DecryptInit(), EVP_DecryptUpdate(), and EVP_DecryptFinal() are all library functions in OpenSSL (in crypto library?). Qiang.Xu> Qiang.Xu> Qiang.Xu> The code to encrypt is: Qiang.Xu> ============================================================ Qiang.Xu> bool_t esscrypto_encryptString(unsigned char *toEncrypt, Qiang.Xu> unsigned char *passPhrase, Qiang.Xu> int sizeOfStrToEncrypt, Qiang.Xu> int maxEncryptedStringSize, Qiang.Xu> int *sizeofEncryptedString, Qiang.Xu> unsigned char **encryptedString) Qiang.Xu> { Qiang.Xu> EVP_CIPHER_CTX openSSLEncryptionStructure; Qiang.Xu> int tempOutputLength = 0; Qiang.Xu> int i = 0; Qiang.Xu> int tmpOutputBufferPosition = 0; Qiang.Xu> int tmpOffset = 0; Qiang.Xu> char *tempPassPhrase = NULL; Qiang.Xu> char *tempStrPtr = NULL; Qiang.Xu> Qiang.Xu> LOGLIBENTER(__FUNCTION__); Qiang.Xu> Qiang.Xu> LOGFORCE("Encrypting [%s] ", toEncrypt); Qiang.Xu> Qiang.Xu> /* initialize return values */ Qiang.Xu> *sizeofEncryptedString = 0; Qiang.Xu> *encryptedString = NULL; Qiang.Xu> Qiang.Xu> /* Qiang.Xu> * Paranoia, if we get "really" big strings to encrypt, we should reject Qiang.Xu> * them in favor of a buffered string encryption method (like what is Qiang.Xu> * done for files). So spit out a warning and return false. Qiang.Xu> ******/ Qiang.Xu> if ( sizeOfStrToEncrypt > ESS_CRYPTO_MAX_TO_ENCRYPT_STR_SIZE ) Qiang.Xu> { Qiang.Xu> LOGWARN("Encrypting string of size [%d] is too big to encrypt", Qiang.Xu> sizeOfStrToEncrypt); Qiang.Xu> LOGLIBRETURN(__FUNCTION__); Qiang.Xu> return (FALSE); Qiang.Xu> } Qiang.Xu> Qiang.Xu> /* format the password to be OpenSSL friendly */ Qiang.Xu> tempPassPhrase = essCrypto_setupPassPhrase(passPhrase); Qiang.Xu> Qiang.Xu> /* Qiang.Xu> * If we have a null password, something is not right, spit out a warning Qiang.Xu> * and return false. Qiang.Xu> ******/ Qiang.Xu> if (tempPassPhrase == NULL) Qiang.Xu> { Qiang.Xu> LOGWARN("PassPhrase is NULL"); Qiang.Xu> LOGLIBRETURN(__FUNCTION__); Qiang.Xu> return(FALSE); Qiang.Xu> } Qiang.Xu> Qiang.Xu> /* Initialize OpenSSL for DES encryption */ Qiang.Xu> Qiang.Xu> EVP_EncryptInit(&openSSLEncryptionStructure, EVP_des_cbc(), tempPassPhrase, Qiang.Xu> (char *)NULL); Qiang.Xu> Qiang.Xu> /**** Qiang.Xu> * Since we are using DES, we don't need to set the key length always Qiang.Xu> set to 64 bits, but if we use other ciphers, we need to do the following: Qiang.Xu> EVP_CIPHER_CTX_set_key_length(&openSSLEncryptionStructure, <size>); Qiang.Xu> // re-init Qiang.Xu> EVP_EncryptInit(&openSSLEncryptionStructure, NULL, passPhrase, Qiang.Xu> (char *)NULL); Qiang.Xu> ****/ Qiang.Xu> Qiang.Xu> Qiang.Xu> /* Get potential size of the output data with a null terminator*/ Qiang.Xu> tempOutputLength = sizeOfStrToEncrypt + Qiang.Xu> EVP_CIPHER_CTX_block_size(&openSSLEncryptionStructure) + 1; Qiang.Xu> Qiang.Xu> /* Qiang.Xu> * If the caller put in a non-negative or zero value for the max encrypted Qiang.Xu> * size, then the caller cares about how big of a string will be returned Qiang.Xu> * to it. So check to make sure it can handle the size of string that will Qiang.Xu> * be returned for encrypted data. Qiang.Xu> ******/ Qiang.Xu> if (maxEncryptedStringSize > 0) Qiang.Xu> { Qiang.Xu> /* Qiang.Xu> * If we are going to need more memory than the caller wants to use for Qiang.Xu> * the encrypted string, spit out an error and return false (since Qiang.Xu> * we cannot encrypt the string to the callers limitations). Qiang.Xu> ******/ Qiang.Xu> if (tempOutputLength > maxEncryptedStringSize) Qiang.Xu> { Qiang.Xu> LOGERROR( Qiang.Xu> "Cannot Encrypt data, Encrypted Size is going to be too big!"); Qiang.Xu> essCrypto_freePassPhrase(tempPassPhrase); Qiang.Xu> LOGLIBRETURN(__FUNCTION__); Qiang.Xu> return(FALSE); Qiang.Xu> } Qiang.Xu> } Qiang.Xu> Qiang.Xu> /* malloc memory for the encrypted string */ Qiang.Xu> *encryptedString = malloc(tempOutputLength); Qiang.Xu> Qiang.Xu> /* Qiang.Xu> * Make sure we successfully malloced memory for the encrypted string Qiang.Xu> ******/ Qiang.Xu> if (*encryptedString == NULL) Qiang.Xu> { Qiang.Xu> LOGERROR("Unable to malloc memory for encryption"); Qiang.Xu> LOGLIBRETURN(__FUNCTION__); Qiang.Xu> essCrypto_freePassPhrase(tempPassPhrase); Qiang.Xu> return (FALSE); Qiang.Xu> } Qiang.Xu> Qiang.Xu> /* clean out the memory for the returned string */ Qiang.Xu> memset(*encryptedString, 0, tempOutputLength); Qiang.Xu> Qiang.Xu> /* Qiang.Xu> * Loop around encrypting the string with the buffer allocated for Qiang.Xu> * encryption till we cannot fill up the buffer with data anymore. Qiang.Xu> ******/ Qiang.Xu> for (i = 0; i < sizeOfStrToEncrypt/ ESS_CRYPTO_CRYPT_BUFFER_SIZE; i++) Qiang.Xu> { Qiang.Xu> /* encrypt the buffer contents) */ Qiang.Xu> EVP_EncryptUpdate(&openSSLEncryptionStructure, Qiang.Xu> &((*encryptedString)[tmpOutputBufferPosition]), Qiang.Xu> &tmpOffset, Qiang.Xu> &toEncrypt[tmpOutputBufferPosition], Qiang.Xu> ESS_CRYPTO_CRYPT_BUFFER_SIZE); Qiang.Xu> Qiang.Xu> /* Increment the position we are at in encrypting the string */ Qiang.Xu> tmpOutputBufferPosition = tmpOutputBufferPosition + tmpOffset; Qiang.Xu> } Qiang.Xu> Qiang.Xu> /* Qiang.Xu> * if there is data left to encrypt that did not fit exactly within Qiang.Xu> * the buffer, encrypt that remaining bit. Qiang.Xu> ******/ Qiang.Xu> if ( sizeOfStrToEncrypt % ESS_CRYPTO_CRYPT_BUFFER_SIZE) Qiang.Xu> { Qiang.Xu> /* encrypt the buffer contents) */ Qiang.Xu> EVP_EncryptUpdate(&openSSLEncryptionStructure, Qiang.Xu> &((*encryptedString)[tmpOutputBufferPosition]), Qiang.Xu> &tmpOffset, Qiang.Xu> &toEncrypt[tmpOutputBufferPosition], Qiang.Xu> sizeOfStrToEncrypt % ESS_CRYPTO_CRYPT_BUFFER_SIZE); Qiang.Xu> Qiang.Xu> /* Increment the position we are at in encrypting the string */ Qiang.Xu> tmpOutputBufferPosition = tmpOutputBufferPosition + tmpOffset; Qiang.Xu> Qiang.Xu> } Qiang.Xu> Qiang.Xu> /* Finalize the encryption results (generate CRC for example) */ Qiang.Xu> EVP_EncryptFinal(&openSSLEncryptionStructure, Qiang.Xu> &((*encryptedString)[tmpOutputBufferPosition]), Qiang.Xu> &tmpOffset); Qiang.Xu> Qiang.Xu> /* set the total size of the string encrypted */ Qiang.Xu> *sizeofEncryptedString = tmpOutputBufferPosition + tmpOffset; Qiang.Xu> Qiang.Xu> tempStrPtr = ess_crypto_get_hex_string_from_string(*encryptedString); Qiang.Xu> Qiang.Xu> if (tempStrPtr != NULL) Qiang.Xu> { Qiang.Xu> LOGFORCE("Encrypted String (in HEX) is [%s]", tempStrPtr); Qiang.Xu> free(tempStrPtr); Qiang.Xu> } Qiang.Xu> essCrypto_freePassPhrase(tempPassPhrase); Qiang.Xu> Qiang.Xu> LOGLIBRETURN(__FUNCTION__); Qiang.Xu> return (TRUE); Qiang.Xu> } Qiang.Xu> ============================================================ Qiang.Xu> I am not sure whether some algorithm in these functions Qiang.Xu> would go awry when dealing with the password "$elkins02". They probably don't, but you need to treat them right. Cheers, Richard -- Richard Levitte [EMAIL PROTECTED] http://richard.levitte.org/ "When I became a man I put away childish things, including the fear of childishness and the desire to be very grown up." -- C.S. Lewis ______________________________________________________________________ OpenSSL Project http://www.openssl.org User Support Mailing List openssl-users@openssl.org Automated List Manager [EMAIL PROTECTED]