Mam klasę zarówno w PHP, jak i C++, aby po prostu wziąć ciąg wartości i ciąg soli, aby wykonać solenie dla prywatności. Pomysł polega na tym, że skrypt PHP zaszyfruje ciąg znaków dla programu C++ do odebrania i odszyfrowania. Używają wstępnie udostępnionego ciągu soli w trybie synchronicznym.

Problem polega na tym, że wydaje się, że jest to ta sama logika, w której generują różne wyniki w przypadku szyfrowania tego samego ciągu. Oznacza to, że odszyfrowanie ciągu na obu końcach nie spowoduje powstania oryginalnego ciągu, który został podany.

Prawdopodobnie jest to coś naprawdę prostego, co przegapiłem lub popełniłem błąd. Lub prawdopodobnie jest to związane z PHP używającym kodowania znaków, gdzie jako C++ jest surowym strumieniem bitów. Skrypt PHP jest ustawiony tak, aby używał zwykłego tekstu wyjściowego z kodowaniem 'us-ascii'.

Oto klasa PHP:

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;
    }
}

Oto klasa C++:

#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;
    }
};

Jakakolwiek pomoc tutaj byłaby mile widziana, dzięki :)

2
Adambean 3 maj 2012, 15:48

2 odpowiedzi

Najlepsza odpowiedź

Rozgryzłem to. Wygląda na to, że muszę wysłać dane wejściowe do skryptu PHP za pośrednictwem żądania HTTP PUT i odczytać je za pomocą fopen("php://input", "rb"). Wyglądało na to, że PHP nie obsługuje niczego w sposób binarny. Również w C++ i PHP każdy znak traktuję jako liczbę całkowitą, co powinno pozwolić na poprawną obsługę ciągów UTF-32 w binarnym trybie bezpiecznym.

Oto moja klasa C++, mam swoją w "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

Ponieważ zwraca wskaźnik znaku, zalecam użycie strcpy(), aby umieścić go w bezpiecznym miejscu. Oto przykład i pamiętaj, że dokładnie ten sam kod jest używany do odszyfrowania łańcucha.

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;

Oto moja klasa PHP:

<?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;
?>

Ten jest nieco łatwiejszy w użyciu. To po prostu:

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

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

Pamiętaj, że nie powinieneś definiować $szString lub $szSalt (po stronie PHP) przez żądanie HTTP GET lub POST. Bądź bezpieczny i użyj żądania PUT i przeczytaj to w ten sposób:

$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." );

Cieszyć się.

0
Adambean 27 czerwiec 2012, 00:03

Nie jestem pewien, ale może użycie funkcji mb_* może pomóc:

  • zamiast strlen użyj mb_strlen
  • zamiast substr użyj mb_substr

Podaj tylko wartość lub kodowanie (ale każda funkcja mb_* powinna sprawdzić kodowanie ciągu, jeśli nie podano żadnego).

1
shadyyx 3 maj 2012, 16:59