> -----Original Message-----
> From: [EMAIL PROTECTED]
> [mailto:[EMAIL PROTECTED] On Behalf Of Shaw Graham George
> Sent: Wednesday, March 12, 2008 6:01 PM
> To: [email protected]
> Subject: RE: crypto library in openssl
>
>
> Encrypted values are byte arrays, not strings. They may
> contain null characters. So you can't use strlen(). It's a
> common error.
But how to explain that passwords like "$dlkins02", "$flkins02", and
"$Elkins02" can be decrypted correctly? Only "$elkins02" is decrypted into
empty string.
To be more specific, this is the code to decrypt:
============================================================
bool_t esscrypto_decryptString(unsigned char *toDecrypt,
unsigned char *passPhrase,
int sizeOfStrToDecrypt,
int maxDecryptedStringSize,
int *sizeOfDecryptedString,
unsigned char **decryptedString)
{
EVP_CIPHER_CTX openSSLDecryptionStructure;
int tempOutputLength = 0;
int i = 0;
int tmpOutputBufferPosition = 0;
int tmpOffset = 0;
char *tempPassPhrase = NULL;
int currentDecryptedStrLength = 0;
char *tempPtr = NULL;
LOGLIBENTER(__FUNCTION__);
tempPtr = ess_crypto_get_hex_string_from_string(toDecrypt);
if (tempPtr != NULL)
{
LOGFORCE("Decrypting string (in hex) [%s]", tempPtr);
free(tempPtr);
}
/* initialize return values */
*sizeOfDecryptedString = 0;
*decryptedString = NULL;
/*
* Paranoia, if we get "really" big strings to decrypt, we should reject
* them in favor of a buffered string decryption method (like what is
* done for files). So spit out a warning and return false.
******/
if ( sizeOfStrToDecrypt > ESS_CRYPTO_MAX_TO_DECRYPT_STR_SIZE )
{
LOGWARN("Decrypting string of size [%d] is too big to decrypt",
sizeOfStrToDecrypt);
LOGLIBRETURN(__FUNCTION__);
return (FALSE);
}
tempPassPhrase = essCrypto_setupPassPhrase(passPhrase);
if (tempPassPhrase == NULL)
{
LOGWARN("PassPhrase is null");
LOGLIBRETURN(__FUNCTION__);
return(FALSE);
}
EVP_DecryptInit(&openSSLDecryptionStructure, EVP_des_cbc(), tempPassPhrase,
(char *) NULL);
/****
* Since we are using DES, we don't need to set the key length always
set to 64 bits, but if we use other ciphers, we need to do the following:
EVP_CIPHER_CTX_set_key_length(&openSSLDecryptionStructure, <size>);
// re-init
EVP_DecryptInit(&openSSLDecryptionStructure, NULL, passPhrase,
(char *)NULL);
****/
tempOutputLength = sizeOfStrToDecrypt +
EVP_CIPHER_CTX_block_size(&openSSLDecryptionStructure) + 1;
/*
* If the caller put in a non-negative or zero value for the max decrypted
* size, then the caller cares about how big of a string will be returned
* to it. So check to make sure it can handle the size of string that will
* be returned for decrypted data.
******/
if (maxDecryptedStringSize > 0)
{
/*
* If we are going to need more memory than the caller wants to use for
* the decrypted string, spit out an error and return false (since
* we cannot decrypt the string to the callers limitations).
******/
if (tempOutputLength > maxDecryptedStringSize)
{
LOGERROR(
"Cannot decrypt data, decrypted Size [%d] is going to be too big!",
tempOutputLength);
essCrypto_freePassPhrase(tempPassPhrase);
LOGLIBRETURN(__FUNCTION__);
return(FALSE);
}
}
/* malloc memory for the decrypted string */
*decryptedString = malloc(tempOutputLength);
/*
* Make sure we successfully malloced memory for the decryptedString string
******/
if (*decryptedString == NULL)
{
LOGERROR("Unable to malloc memory for decryption");
essCrypto_freePassPhrase(tempPassPhrase);
LOGLIBRETURN(__FUNCTION__);
return (FALSE);
}
/* clean out the memory for the returned string */
memset(*decryptedString, 0, tempOutputLength);
/*
* Loop around decrypting the string with the buffer allocated for
* decryption till we cannot fill up the buffer with data anymore.
******/
for (i = 0; i < sizeOfStrToDecrypt/ ESS_CRYPTO_CRYPT_BUFFER_SIZE; i++)
{
/* decrypt the contents of the buffer */
EVP_DecryptUpdate(&openSSLDecryptionStructure,
&((*decryptedString)[tmpOutputBufferPosition]),
&tmpOffset,
&toDecrypt[tmpOutputBufferPosition],
ESS_CRYPTO_CRYPT_BUFFER_SIZE);
/* Increment the position we are at in decrypting the string */
tmpOutputBufferPosition = tmpOutputBufferPosition + tmpOffset;
}
/*
* if there is data left to decrypt that did not fit exactly within
* the buffer, decrypt that remaining bit.
******/
if ( sizeOfStrToDecrypt % ESS_CRYPTO_CRYPT_BUFFER_SIZE)
{
/* decrypt the contents of the buffer */
EVP_DecryptUpdate(&openSSLDecryptionStructure,
&((*decryptedString)[tmpOutputBufferPosition]),
&tmpOffset,
&toDecrypt[tmpOutputBufferPosition],
sizeOfStrToDecrypt % ESS_CRYPTO_CRYPT_BUFFER_SIZE);
/* Increment the position we are at in decrypting the string */
tmpOutputBufferPosition = tmpOutputBufferPosition + tmpOffset;
}
/* finalize the results from decryption (check CRC) */
EVP_DecryptFinal(&openSSLDecryptionStructure,
&((*decryptedString)[tmpOutputBufferPosition]),
&tmpOffset);
/* set the final length of the decrypted string */
*sizeOfDecryptedString = tmpOutputBufferPosition + tmpOffset;
/* see what the length is according to strlen */
currentDecryptedStrLength = strlen(*decryptedString);
LOGFORCE("lenght of decrypted string is %d", currentDecryptedStrLength); //xq
/*
* If we have the room in memory, NULL terminate the string (just in case
* it has not already been done). Even thought we null out the entire
* string when memory was malloc'ed for it.
******/
if (*sizeOfDecryptedString < tempOutputLength)
{
(*decryptedString)[*sizeOfDecryptedString] = (char) 0;
}
/*
* If the OpenSSL length (sizeOfDecryptedString is less than the determined
* strlen, it means OpenSSL didn't clean up after itself and it left the
* encryption "salt" in the string. If this is the case, remove the
* salt from memory (since it could contain sensitive information).
******/
if (*sizeOfDecryptedString < currentDecryptedStrLength)
{
LOGDEBUG("Cleaning up Salt in Decrypted String");
/*
* loop around and null out each "salt" character in the string
******/
for (i = *sizeOfDecryptedString; i < currentDecryptedStrLength; i++)
{
(*decryptedString)[i] = (char) 0;
}
}
LOGREALLYSECURE("Decrypted String is [%s]", *decryptedString);
essCrypto_freePassPhrase(tempPassPhrase);
LOGLIBRETURN(__FUNCTION__);
return (TRUE);
}
============================================================
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?).
The code to encrypt is:
============================================================
bool_t esscrypto_encryptString(unsigned char *toEncrypt,
unsigned char *passPhrase,
int sizeOfStrToEncrypt,
int maxEncryptedStringSize,
int *sizeofEncryptedString,
unsigned char **encryptedString)
{
EVP_CIPHER_CTX openSSLEncryptionStructure;
int tempOutputLength = 0;
int i = 0;
int tmpOutputBufferPosition = 0;
int tmpOffset = 0;
char *tempPassPhrase = NULL;
char *tempStrPtr = NULL;
LOGLIBENTER(__FUNCTION__);
LOGFORCE("Encrypting [%s] ", toEncrypt);
/* initialize return values */
*sizeofEncryptedString = 0;
*encryptedString = NULL;
/*
* Paranoia, if we get "really" big strings to encrypt, we should reject
* them in favor of a buffered string encryption method (like what is
* done for files). So spit out a warning and return false.
******/
if ( sizeOfStrToEncrypt > ESS_CRYPTO_MAX_TO_ENCRYPT_STR_SIZE )
{
LOGWARN("Encrypting string of size [%d] is too big to encrypt",
sizeOfStrToEncrypt);
LOGLIBRETURN(__FUNCTION__);
return (FALSE);
}
/* format the password to be OpenSSL friendly */
tempPassPhrase = essCrypto_setupPassPhrase(passPhrase);
/*
* If we have a null password, something is not right, spit out a warning
* and return false.
******/
if (tempPassPhrase == NULL)
{
LOGWARN("PassPhrase is NULL");
LOGLIBRETURN(__FUNCTION__);
return(FALSE);
}
/* Initialize OpenSSL for DES encryption */
EVP_EncryptInit(&openSSLEncryptionStructure, EVP_des_cbc(), tempPassPhrase,
(char *)NULL);
/****
* Since we are using DES, we don't need to set the key length always
set to 64 bits, but if we use other ciphers, we need to do the following:
EVP_CIPHER_CTX_set_key_length(&openSSLEncryptionStructure, <size>);
// re-init
EVP_EncryptInit(&openSSLEncryptionStructure, NULL, passPhrase,
(char *)NULL);
****/
/* Get potential size of the output data with a null terminator*/
tempOutputLength = sizeOfStrToEncrypt +
EVP_CIPHER_CTX_block_size(&openSSLEncryptionStructure) + 1;
/*
* If the caller put in a non-negative or zero value for the max encrypted
* size, then the caller cares about how big of a string will be returned
* to it. So check to make sure it can handle the size of string that will
* be returned for encrypted data.
******/
if (maxEncryptedStringSize > 0)
{
/*
* If we are going to need more memory than the caller wants to use for
* the encrypted string, spit out an error and return false (since
* we cannot encrypt the string to the callers limitations).
******/
if (tempOutputLength > maxEncryptedStringSize)
{
LOGERROR(
"Cannot Encrypt data, Encrypted Size is going to be too big!");
essCrypto_freePassPhrase(tempPassPhrase);
LOGLIBRETURN(__FUNCTION__);
return(FALSE);
}
}
/* malloc memory for the encrypted string */
*encryptedString = malloc(tempOutputLength);
/*
* Make sure we successfully malloced memory for the encrypted string
******/
if (*encryptedString == NULL)
{
LOGERROR("Unable to malloc memory for encryption");
LOGLIBRETURN(__FUNCTION__);
essCrypto_freePassPhrase(tempPassPhrase);
return (FALSE);
}
/* clean out the memory for the returned string */
memset(*encryptedString, 0, tempOutputLength);
/*
* Loop around encrypting the string with the buffer allocated for
* encryption till we cannot fill up the buffer with data anymore.
******/
for (i = 0; i < sizeOfStrToEncrypt/ ESS_CRYPTO_CRYPT_BUFFER_SIZE; i++)
{
/* encrypt the buffer contents) */
EVP_EncryptUpdate(&openSSLEncryptionStructure,
&((*encryptedString)[tmpOutputBufferPosition]),
&tmpOffset,
&toEncrypt[tmpOutputBufferPosition],
ESS_CRYPTO_CRYPT_BUFFER_SIZE);
/* Increment the position we are at in encrypting the string */
tmpOutputBufferPosition = tmpOutputBufferPosition + tmpOffset;
}
/*
* if there is data left to encrypt that did not fit exactly within
* the buffer, encrypt that remaining bit.
******/
if ( sizeOfStrToEncrypt % ESS_CRYPTO_CRYPT_BUFFER_SIZE)
{
/* encrypt the buffer contents) */
EVP_EncryptUpdate(&openSSLEncryptionStructure,
&((*encryptedString)[tmpOutputBufferPosition]),
&tmpOffset,
&toEncrypt[tmpOutputBufferPosition],
sizeOfStrToEncrypt % ESS_CRYPTO_CRYPT_BUFFER_SIZE);
/* Increment the position we are at in encrypting the string */
tmpOutputBufferPosition = tmpOutputBufferPosition + tmpOffset;
}
/* Finalize the encryption results (generate CRC for example) */
EVP_EncryptFinal(&openSSLEncryptionStructure,
&((*encryptedString)[tmpOutputBufferPosition]),
&tmpOffset);
/* set the total size of the string encrypted */
*sizeofEncryptedString = tmpOutputBufferPosition + tmpOffset;
tempStrPtr = ess_crypto_get_hex_string_from_string(*encryptedString);
if (tempStrPtr != NULL)
{
LOGFORCE("Encrypted String (in HEX) is [%s]", tempStrPtr);
free(tempStrPtr);
}
essCrypto_freePassPhrase(tempPassPhrase);
LOGLIBRETURN(__FUNCTION__);
return (TRUE);
}
============================================================
I am not sure whether some algorithm in these functions would go awry when
dealing with the password "$elkins02".
Thanks,
Xu Qiang
______________________________________________________________________
OpenSSL Project http://www.openssl.org
Development Mailing List [email protected]
Automated List Manager [EMAIL PROTECTED]