0

I'm trying to encode and decode a string using AES. At the moment, I'm encoding the string in Mono C# using the highest-rated answer here, because System.Security.Crytpography.Aes is not available in Mono. However, this implementation uses a Salt, and the PHP method I'm using to decrypt it does not take a salt, only an Initialization Vector, which I generate.

My problem: The encrypted data is salted, and I don't know how to un-salt it even with the known salt string.

  1. Should I try to remove the salt from the C# class?
    • Is the implementation good enough using only the plaintext, password/key, and initialization vector?
  2. Or is there another form of decryption that I can use in PHP that will take ciphertext, key, salt, and initialization vector?
  3. Or should I try to un-salt the decrypted text after calling mcrypt_decrypt on it? Is that the right order of things?
  4. Or should I rewrite the C# AES class completely? Is it actually a bad example?
  5. [edit] Or does anyone know of a Rfc2898DeriveBytes implementation I can use in PHP? I'm not sure I'm confident enough to write the implementation myself, lest I completely defeat the point of security through some error.

Sorry for my ignorance, this is the first time I've ever dealt with encryption, and there's a lot of information to take in.

Community
  • 1
  • 1
Arcandio
  • 310
  • 2
  • 13
  • 1
    It's not possible to unsalt something. You have to recreate the same key derivation code in PHP. Hint: it's probably PBKDF2. You have to ask yourself whether you need a password-based solution or a key-based solution. – Artjom B. May 27 '15 at 22:51
  • So after reading that code closer, what I'd have to do is derive a new set of bytes to use as the decryption key from the original password/key and the salt? Do I have that right? Which means that I'd still need to implement `Rfc2898DeriveBytes` in PHP as stated in @Ospho's answer, I assume? – Arcandio May 28 '15 at 14:01

2 Answers2

2

The answer you have posted implements the Rfc2898DeriveBytes class to get the bytes of the encrypting key. This is advised, but not mandatory. You don't have to use Rfc2898DeriveBytes and can simply modify that AES implementation not to take a salt and simply take the password's bytes as the key directly. Although I don't recommend this in practice.

What I do recommend is finding a more suitable PHP AES implementation that allows salting of your password to get the key bytes - which should be available (sorry but I have little experience with PHP to aid you in this; you may find that an additional method exists in the PHP crypto libraries to form a key based on a password and salt input similar to .NET/MONO's Rfc2898DeriveBytes).

Community
  • 1
  • 1
Ospho
  • 2,756
  • 5
  • 26
  • 39
  • I would like to help out. Is Rfc2898DeriveBytes just 1000 iterations with the salt using sha1? I would post some php code but I have no way of testing it is giving the correct results and I cant find an online implementation to test with. Is there any test data? – Phil May 28 '15 at 21:09
  • I ended up going with phpseclib and it works great. Thanks for the help. – Arcandio Jun 02 '15 at 19:58
1

#1 No

#2 Yes (See below)

#3 No

#4 No, it looks fine to me

#5 Please try this PHP implementation with your encrypted data. I haven't tested it.

<?php

function pbkdf2( $p, $s, $c, $kl, $a = 'sha1' ) {
    $hl = strlen(hash($a, null, true)); # Hash length
    $kb = ceil($kl / $hl);              # Key blocks to compute
    $dk = '';                           # Derived key
    # Create key
    for ( $block = 1; $block <= $kb; $block ++ ) {
        # Initial hash for this block
        $ib = $b = hash_hmac($a, $s . pack('N', $block), $p, true);
        # Perform block iterations
        for ( $i = 1; $i < $c; $i ++ )
            # XOR each iterate
            $ib ^= ($b = hash_hmac($a, $b, $p, true));
        $dk .= $ib; # Append iterated block
    }
    # Return derived key of correct length
    return substr($dk, 0, $kl);
}

//Usage example (Decryption by PHP)
$ciphertext_b64 = "owiCMbopBmr+NvjBEUT2Hg==";

$password = "password";
$salt = "g46dzQ80"; //Please change to the salt you are using.  Copied from the referenced answer code.

//This is the key derivation part.  I think .net uses 1000 iterations of sha1.
$key = pbkdf2($password, $salt, 1000, 32, "sha1");
$iv = "OFRna74m*aze01xY"; //Again, I copied the IV from the .NET code in the answer you referenced.

$plaintext = rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, base64_decode($ciphertext_b64), MCRYPT_MODE_CBC, $iv), "\0");

echo $plaintext;
// Output = hello
Phil
  • 1,996
  • 1
  • 19
  • 26