Search code examples
javaphpencryptionblowfishcommutativity

Is there a way to use commutative encryption in php?


I have used the encrypt and decrypt functions from this answer to implement message passing using Three-pass protocol with the Blowfish cipher.

And I tried using commutative ecryption/decryption. That is,

$tmp = encrypt($input, $key1);
$tmp = encrypt($tmp, $key2);
$tmp = decrypt($tmp, $key1);
$dec2 = decrypt($tmp, $key2);

But it does not work. I used a single key instead of 2 different keys and it works(has to!).

So there's no problem in the way I'm using these functions, but I simply cant get it working with two keys.

Am I doing something wrong? Is this not possible, or is there another way?

Or, is there a way I could do it in Java?

Edit: For those who don't understand the procedure, Three-pass protocol is a way to send encrypted messages without having to send the keys. So the procedure is

  1. Sender encrypts with key1 and sends

  2. Receiver encrypts with key2 and sends back

  3. Sender decrypts with key1 and sends back

  4. Receiver decrypts with key2 to get the original message

You can see that keys are not exchanged, but the message is sent only in encrypted form. That's the whole point.


Solution

  • Using the XOR function provided by a user in this thread

    Encrypt/decrypt with XOR in PHP

        function xor_this($string,$key) {
    
     // Our plaintext/ciphertext
     $text =$string;
    
     // Our output text
     $outText = '';
    
     // Iterate through each character
     for($i=0;$i<strlen($text);)
     {
         for($j=0;($j<strlen($key) && $i<strlen($text));$j++,$i++)
         {
             $outText .= $text{$i} ^ $key{$j};
             //echo 'i='.$i.', '.'j='.$j.', '.$outText{$i}.'<br />'; //for debugging
         }
     }  
     return $outText;
    }
    
    //The sender chooses a private encryption key s and a corresponding decryption key t. The sender encrypts the message m with the key s and sends the encrypted message E(s,m) to the receiver.
    //The receiver chooses a private encryption key r and a corresponding decryption key q and super-encrypts the first message E(s,m) with the key r and sends the doubly encrypted message E(r,E(s,m)) back to the sender.
    //The sender decrypts the second message with the key t. Because of the commutativity property described above D(t,E(r,E(s,m)))=E(r,m) which is the message encrypted with only the receiver's private key. The sender sends this to the receiver.
    
    $senderkey=base64_encode('chicken');
    $receiverkey=base64_encode('ardvark');
    
    $itemwewanttoshare='hello darling';
    echo'$itemwewanttoshare: '.$itemwewanttoshare.'<BR>';
    $packet1=xor_this($itemwewanttoshare,$senderkey);
    echo'$packet1: '.$packet1.'<BR>';
    
    $packet2=xor_this($packet1,$receiverkey);
    echo'$packet2: '.$packet2.'<BR>';
    
    $packet3=xor_this($packet2,$senderkey);
    echo'$packet3: '.$packet3.'<BR>';
    
    $packet4=xor_this($packet3,$receiverkey);
    echo'$packet4: '.$packet4.'<BR>';
    

    You get this

    $itemwewanttoshare: hello darling
    $packet1: 1W6 TS>
    $packet2: hNwRVtq|ing
    $packet3: 1=&M"TS>
    $packet4: hello darling
    

    EDIT addition

    I base64'd the key for simplicity. Use a key with more variation and the results will be more complicated.
    use mcrypt_create_iv(40) to create your keys and you end up with something like this

    $senderkey='<²#H[Ô\´(µÑ/KÀ®"熺¥ç|Ëvr%O›eu$nºbe';
    $receiverkey='Øh\5PÀKO[ù¬òZH‰•Ê¬h/¥nëk¾ðéíPÄ"Uü';
    

    which will change the output to

    $itemwewanttoshare: hello darling
    $packet1: T§ÞO'{§õ.®ÝF¥
    $packet2: —?¶+¦6®½– þ
    $packet3: «ý0Zpe¢ò"!<
    $packet4: hello darling
    

    Edit 2

    Duskwuff brings up a good point. $itemwewanttoshare should be created by the system(program) and not be a user created item. This method could be used to establish a shared encryption key that both send and receiver could use to encrypt further communication. Sender would generate the key, and then that would be the itemwewanttoshare , thus allowing both sides to know the encryption key without passing it directly.