views:

990

answers:

4

It's seems that there isn't any pleasant way to encrypt a file in php.

The built in methods of php, mcrypt, aren't very portable as most servers don't support them.

Command line encryption tools are like ugly hacks.

There's encryption for strings which is nice, but if we want to encrypt a file it doesn't help very much especially for someone else to unencrypt it.

Other encryption tools require public keys, key rings, private keys, blood sample... These seem much too complicated for just encrypting a file.

It seems that we should just have a simple funtion for php that could work like so:

$crypt = new Crypt();
$crypt->encryptFile("Password1245!", 'secret_file.txt', 'encrypted_file.txt');
$crypt->decryptFile("Password1245!", 'encrypted_file.txt', 'original_file.txt');

Any one have any ideas? I'm pulling out hair!!

EDIT: Another thing I should add, for the end user to be able to decrypt the file with ease.

Basically I'm trying to find something that can replace a password protected zip file

+5  A: 

Take a look at the PEAR encryption packages. They don't all rely on mcrypt - for example Crypt_Blowfish.

Greg
+2  A: 

If you don't mind having the mcrypt extension installed, this code should do it:

function Encrypt($string, $key)
{
    if (extension_loaded('mcrypt') === true)
    {
     return base64_encode(mcrypt_encrypt(MCRYPT_BLOWFISH, substr($key, 0, mcrypt_get_key_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB)), trim($string), MCRYPT_MODE_ECB, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB), MCRYPT_RAND)));
    }

    return false;
}

function Decrypt($string, $key)
{
    if (extension_loaded('mcrypt') === true)
    {
     return trim(mcrypt_decrypt(MCRYPT_BLOWFISH, substr($key, 0, mcrypt_get_key_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB)), base64_decode($string), MCRYPT_MODE_ECB, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB), MCRYPT_RAND)));
    }

    return false;
}

function Encrypt_File($source, $destination, $key)
{
    if (extension_loaded('mcrypt') === true)
    {
     if (is_file($source) === true)
     {
      $source = file_get_contents($source);

      if (file_put_contents($destination, Encrypt($source, $key), LOCK_EX) !== false)
      {
       return true;
      }
     }
    }

    return false;
}

function Decrypt_File($source, $destination, $key)
{
    if (extension_loaded('mcrypt') === true)
    {
     if (is_file($source) === true)
     {
      $source = file_get_contents($source);

      if (file_put_contents($destination, Decrypt($source, $key), LOCK_EX) !== false)
      {
       return true;
      }
     }
    }

    return false;
}
Alix Axel
Why would you want to base64 encode the contents of a file? There is nothing wrong with binary contents for files. base64 encoding increases data size by 33%
Jacco
I don't like to have new lines, since they might not be copied if I need to use the encrypted data in a copy/paste scenario, but yes it still works without base64 encoding/decoding.
Alix Axel
A: 

what about simple xor?

function Crypt($source, $key)
{
 $rv='';
 for($i=0;$i<strlen($source);$i++)
 {
  $rv.=chr(ord($source[$i]) ^ ord($key[$i%strlen($key)]));
 }
 return $rv;
}

=> Crypt(Crypt('aaa','key'),'key') returns 'aaa'.

EDIT: of course, you should use

file_put_contents(Crypt(file_get_contents('file'), 'key'));

for file read+write :]

Yossarian
That's a nice algorithm, but the problem comes when the end user needs to decrypt it. Short of writing a windows app to decode there probably isn't an easy way for them to decode it. I'll probably use what you've got here in other projects, it's nice clean and simple.
SeanDowney
Fatal error: Cannot redeclare crypt()...Fatal error: Call to undefined function asc()...NULL...?
Alix Axel
@SeanDowney: according to Yossarian it should encrypt and decrypt strings, the only problem is that I can't get it to work even after fixing the bugs. =\
Alix Axel
Nevermind, forgot that it needs to return something.
Alix Axel
Although it looks like an encrypted file, this is not encryption and it should not be used for data that needs to stay secret.
Jacco
+1, but its might still be useful for other not so sensitive purposes.
Alix Axel
sorry, my faults, i didnt read that after myself. in fact, if the key is as long as the data, it is the only unbreakable encryption ;-)
Yossarian
Umm, pretty much *any* encryption is unbreakable if you encrypt 1GB of data with a 1GB key.
soulmerge
It is only unbreakable if the key is as long as the data AND if the key is ONLY EVER USED ONCE.Use the same key twice and the key has effectively become public.
Jacco
The key also has to be random.If the key is repeated, this algorithm is a type of Vigenère cipher, which isn't very hard to crack: http://www.simonsingh.net/The_Black_Chamber/vigenere_cracking.html http://www.perlmonks.org/?node_id=161722
outis
@Yossarian: Got even more down-votes than you did. =(
Alix Axel
A: 

Yossarian's Crypt() function fixed:

function _Crypt($source, $key)
{
    $result = '';

    for($i = 0; $i < strlen($source); $i++)
    {
     $result .= chr(ord($source[$i]) ^ ord($key[$i % strlen($key)]));
    }

    return $result;
}

_Crypt('aaa', 'key'); // 
_Crypt(_Crypt('aaa', 'key'), 'key'); // aaa
Alix Axel
Is that XOR? That's a so-called "kid sister encryption", i.e. only useful for hiding stuff from your kid sister. (yeah, you could use OTP and stuff, but that's far from simple)
Piskvor
Still, useful sometimes. :P
Alix Axel
This is not useful in a security context at all. _Crypt is a misleading function name. It is not encryption, it is obfuscation at best.
Jacco
I'm aware of that, and so is Yossarian (see the post below), I just fixed a couple of errors in his code, why am I being voted down? blah :P
Alix Axel