当前位置: 动力学知识库 > 问答 > 编程问答 >

php - Same string salting code giving different results

问题描述:

I have a class in both PHP and C++ to simply take a value string and salt string to do some salting for privacy. The idea is a PHP script will encrypt a string for a C++ program to receive and decrypt. They use a pre-shared salt string, synchronous mode.

The issue is with what appears to be the same logic they generate a different result for encrypting the same string. This means that decrypting the string either end will not result in the original string it was given.

It is probably something really simple I have missed or made a mistake on. Or possibly it is related to PHP using character encoding where as C++ is a raw bit stream. The PHP script is set to use a plain text output, with 'us-ascii' encoding.

Here is the PHP class:

define( 'NUM_STRINGS', 256 );

class CTwEncryption

{

function Crypt( $szValue, $szSalt )

{

$iValueSize = (int)strlen( $szValue );

$iSaltSize = (int)strlen( $szSalt );

$szStrings = array();

$szKeys = array();

$j = 1;

// Init array of 0-255

for ( $i = 0; $i < NUM_STRINGS; $i++ )

$szStrings[ $i ] = $i;

// Init array of 0-255 with a calculated char value

for ( $i = 0; $i < NUM_STRINGS; $i++ )

{

if ( $j > $iSaltSize )

$j = 1;

$szKeys[ $i ] = ord( substr( $szSalt, $j, 1 ) );

$j++;

}

// Shuffle the array values around to give a random value

$j = 0;

for ( $i = 0; $i < NUM_STRINGS; $i++ )

{

$j = ( $j + $szStrings[ $i ] + $szKeys[ $i ] ) % NUM_STRINGS;

$szTemp = $szStrings[ $i ];

$szStrings[ $i ] = $szStrings[ $j ];

$szStrings[ $j ] = $szTemp;

}

// Encrypt/decrypt the string

$szReturnValue = null;

$i = 0;

$j = 0;

for ( $x = 0; $x < $iValueSize; $x++ )

{

$i = ( $i + 1 ) % NUM_STRINGS;

$j = ( $j + $szStrings[ $i ] ) % NUM_STRINGS;

$szTemp = $szStrings[ $i ];

$szStrings[ $i ] = $szStrings[ $j ];

$szStrings[ $j ] = $szTemp;

$t = ( $szStrings[ $i ] + ( $szStrings[ $j ] % NUM_STRINGS ) ) % NUM_STRINGS;

$y = $szStrings[ $t ];

$cCrypt = chr( substr( $szValue, $x, 1 ) ^ $y );

$szReturnValue .= $cCrypt;

}

// Return encrypted/decrypted string

return $szReturnValue;

}

}

Here is the C++ class:

#define NUM_STRINGS 256

class CTwEncryption

{

private:

char *szWorking;

public:

CTwEncryption() { szWorking = NULL; };

~CTwEncryption() { if ( szWorking != NULL ) { delete szWorking; szWorking = NULL; } };

char *Crypt( const char szValue[], const char szSalt[] )

{

const int iValueSize = (int)strlen( szValue );

const int iSaltSize = (int)strlen( szSalt );

if ( iValueSize == 0 || iSaltSize == 0 )

return NULL;

int j = 1;

char *szStrings[ NUM_STRINGS ];

char *szKeys[ NUM_STRINGS ];

// Init array of 0-255

for ( int i = 0; i < NUM_STRINGS; i++ )

{

char *szString = new char[ iValueSize + 1 ];

itoa( i, szString, 10 );

szString[ iValueSize ] = 0;

szStrings[ i ] = szString;

}

// Init array of 0-255 with a calculated char value

for ( int i = 0; i < NUM_STRINGS; i++ )

{

char *szKey = new char[ iValueSize + 1 ];

if ( j > iSaltSize )

j = 1;

itoa( (int)( szSalt[ j ] ), szKey, 10 );

szKey[ iValueSize ] = 0;

szKeys[ i ] = szKey;

j++;

}

// Shuffle the array values around to give a random value

j = 0;

for ( int i = 0; i < NUM_STRINGS; i++ )

{

j = ( j + atoi( szStrings[ i ] ) + atoi( szKeys[ i ] ) ) % NUM_STRINGS;

char *szTemp = szStrings[ i ];

szStrings[ i ] = szStrings[ j ];

szStrings[ j ] = szTemp;

}

// Encrypt/decrypt the string

szWorking = new char[ iValueSize + 1 ];

for ( int i = 0; i <= iValueSize; i++ )

szWorking[ i ] = 0;

int i = 0;

j = 0;

for ( int x = 0; x <= iValueSize; x++ )

{

i = ( i + 1 ) % NUM_STRINGS;

j = ( j + atoi( szStrings[ i ] ) ) % NUM_STRINGS;

char *szTemp = szStrings[ i ];

szStrings[ i ] = szStrings[ j ];

szStrings[ j ] = szTemp;

int t = ( atoi( szStrings[ i ] ) + ( atoi( szStrings[ j ] ) % NUM_STRINGS ) ) % NUM_STRINGS;

int y = atoi( szStrings[ t ] );

char cCrypt = char( (int)( szValue[ x ] ) ^ y );

szWorking[ x ] = cCrypt;

}

// Clean dynamic memory

for ( int i = 0; i < NUM_STRINGS; i++ )

{

delete szStrings[ i ];

delete szKeys[ i ];

szStrings[ i ] = NULL;

szKeys[ i ] = NULL;

}

// Return encrypted/decrypted string

szWorking[ iValueSize ] = 0;

return szWorking;

}

};

Any help here would be appreciated, thanks :)

网友答案:

I'm not sure but maybe using mb_* functions could help:

  • instead of strlen use mb_strlen
  • instead of substr use mb_substr

Either give it just the value or also the encoding (but each mb_* function should check for the string encoding if no one is provided).

网友答案:

Figured this out. Looks like I need to send input to a PHP script via a HTTP PUT request, and read it using fopen( "php://input", "rb" ). It appeared that PHP was not hanlding anything in a binary safe fashion. Also both on C++ and PHP I'm treating each character as an integer, which should allow UTF-32 strings to be handled correctly in binary safe mode.

Here is my C++ class, I have mine in "twencrypt.h":

#ifndef TWCRYPT_H
#define TWCRYPT_H

/***
*
*   Two-way string encryption
*   This will encrypt/decrypt a string using a salt.
*
*   -AdamR
*
****/

#define NUM_STRINGS 256

class CTwEncryption
{
private:
    char    *szWorking;

public:
    CTwEncryption()     { szWorking = NULL; };
    ~CTwEncryption()    { if ( szWorking != NULL ) { delete szWorking; szWorking = NULL; } };

    char *Crypt( const char szValue[], const char szSalt[] )
    {
        const int iValueSize = (int)strlen( szValue );
        const int iSaltSize = (int)strlen( szSalt );

        if ( iValueSize < 1 || iSaltSize <  1 )
            return NULL;

        int j = 1;

        int iChars[ NUM_STRINGS ];
        int iKeys[ NUM_STRINGS ];

        // Init array of 0-255
        for ( int i = 0; i < NUM_STRINGS; i++ )
            iChars[ i ] = i;

        // Init array of 0-255 with a calculated char value
        for ( int i = 0; i < NUM_STRINGS; i++ )
        {
            if ( j > iSaltSize )
                j = 1;

            iKeys[ i ] = szSalt[ j ];
            j++;
        }

        // Shuffle the array values around to give a random value
        j = 0;
        for ( int i = 0; i < NUM_STRINGS; i++ )
        {
            j = ( j + iChars[ i ] + iKeys[ i ] ) % NUM_STRINGS;

            int iTemp = iChars[ i ];
            iChars[ i ] = iChars[ j ];
            iChars[ j ] = iTemp;
        }

        // Encrypt/decrypt the string
        szWorking = new char[ iValueSize + 1 ];
        for ( int i = 0; i <= iValueSize; i++ )
            szWorking[ i ] = 0;

        int i = 0;
        j = 0;

        for ( int x = 0; x <= iValueSize; x++ )
        {
            i = ( i + 1 ) % NUM_STRINGS;
            j = ( j + iChars[ i ] ) % NUM_STRINGS;

            int iTemp = iChars[ i ];
            iChars[ i ] = iChars[ j ];
            iChars[ j ] = iTemp;

            int t = ( iChars[ i ] + ( iChars[ j ] % NUM_STRINGS ) ) % NUM_STRINGS;
            int y = iChars[ t ];

            char cCrypt = char( (int)( szValue[ x ] ) ^ y );
            szWorking[ x ] = cCrypt;
        }

        // Return encrypted/decrypted string
        szWorking[ iValueSize ] = 0;
        return szWorking;
    }
};

#endif

As it returns a char pointer I recommend you use strcpy() to put it in a safe place. Here is an example, and bare in mind the exact same code is used to decrypt a string too.

const char *szString = "My string to encrypt";
const char *szSalt   = "Some salt here :D";
int iStringSize      = (int)strlen( szString );

char *szEncrypted = new char( iStringSize ) + 1 );
CTwEncryption *pTwCrypt = new CTwEncryption();
strcpy( szEncrypted, pTwCrypt->Crypt( szString, szSalt );
szEncrypted[ iStringSize ] = 0;
delete pTwCrypt;

Here is my PHP class:

<?php
    define( 'NUM_STRINGS', 256 );

    class CTwEncryption
    {
        function Crypt( $szValue, $szSalt )
        {
            $iValueSize = strlen( $szValue );
            $iSaltSize  = strlen( $szSalt );

            if ( $iValueSize == 0 || $iSaltSize == 0 )
                return null;

            $j = 1;

            $iChars = array();
            $iKeys  = array();

            // Init array of 0-255
            for ( $i = 0; $i < NUM_STRINGS; $i++ )
                $iChars[ $i ] = $i;

            // Init array of 0-255 with a calculated char value
            for ( $i = 0; $i < NUM_STRINGS; $i++ )
            {
                if ( $j > $iSaltSize )
                    $j = 1;

                $iKeys[ $i ] = ord( $szSalt[ $j ] );
                $j++;
            }

            // Shuffle the array values around to give a random value
            $j = 0;
            for ( $i = 0; $i < NUM_STRINGS; $i++ )
            {
                $j = ( $j + $iChars[ $i ] + $iKeys[ $i ] ) % NUM_STRINGS;

                $iTemp = $iChars[ $i ];
                $iChars[ $i ] = $iChars[ $j ];
                $iChars[ $j ] = $iTemp;
            }

            // Encrypt/decrypt the string
            $szReturnValue = null;
            $i = 0;
            $j = 0;

            for ( $x = 0; $x < $iValueSize; $x++ )
            {
                $i = ( $i + 1 ) % NUM_STRINGS;
                $j = ( $j + $iChars[ $i ] ) % NUM_STRINGS;

                $iTemp = $iChars[ $i ];
                $iChars[ $i ] = $iChars[ $j ];
                $iChars[ $j ] = $iTemp;

                $t = ( $iChars[ $i ] + ( $iChars[ $j ] % NUM_STRINGS ) ) % NUM_STRINGS;
                $y = $iChars[ $t ];

                $iValue = str_split( $szValue );
                for ( $c = 0; $c < $iValueSize; $c++ )
                    $iValue[ $c ] = ord( $iValue[ $c ] );

                $cCrypt = chr( $iValue[ $x ] ^ $y );
                $szReturnValue .= $cCrypt;
            }

            // Return encrypted/decrypted string
            return $szReturnValue;
        }
    }

    $c_TwEncryption = new CTwEncryption;
?>

This one is a bit easier to use. It's simply:

$szString    = "My string to hide lollercoaster";
$szSalt      = "super duper password of doom";

$szEncrypted = $c_TwEncryption->Crypt( $szString, $szSalt );
$szDecrypted = $c_TwEncryption->Crypt( $szEncrypted, $szSalt );

Remember that you should not define $szString or $szSalt (PHP side) via a HTTP GET or POST request. Be safe and use a PUT request, and read it like this:

$szString = null;
$hInData = fopen( "php://input", "rb" ) || die( "Unable to open HTTP PUT handle." );

if( $hInData != null )
{
    while ( $bData = fread( $hRequest, 1024 ) )
        $szString .= $bData;
}
else
    die( "Unable to read HTTP PUT data." );

fClose( $hInData ) || die( "Unable to close HTTP PUT handle." );

if( $szString == null || empty( $szString ) )
    die( "No data read from HTTP PUT stream." );

Enjoy.

分享给朋友:
您可能感兴趣的文章:
随机阅读: