Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
168 changes: 158 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,159 @@ HMAC-SHA256 (Encrypt-then-Mac). HKDF is used to split the user-provided key into
two keys: one for encryption, and the other for authentication. It is
implemented using the `openssl_` and `hash_hmac` functions.

## Installing this Library

### Using Composer

```sh
composer require defuse/php-encryption
```

### Direct Installation (Phar)

Download the PHP Archive and public key. Place both of them in the same directory (e.g. `vendor/defuse/php-encryption.phar` and `vendor/defuse/php-encryption.phar.pubkey`).

Then, just add this line and you're golden:

```php
require_once "vendor/defuse/php-encryption.phar";
```

### Direct Installation (Manual)

Download the [latest release](https://github.com/defuse/php-encryption/releases). Extract all of the files into a directory on your webserver (e.g. `/var/www/lib/defuse/php-encryption`).

Then add this to your PHP scripts:

```php
require '/var/www/lib/defuse/php-encryption/autoload.php';
```

## Using this Library

1. Generate and store an encryption key.
2. Encrypt plaintext strings with your key to obtain ciphertext, using `Crypto`.
3. Decrypt ciphertext strings with your key to obtain plaintext, using `Crypto`.
4. Encrypt/decrypt files with your key, using `File`.

### Generate and Store an Encryption Key

Generate a new key:

```php
$key = \Defuse\Crypto\Key::createNewRandomKey();
````

The above command will generate a random encryption key, using a
cryptographically secure pseudorandom number generator. This will generally only
need to be done *once* if you need to reuse this key for multiple messages.

```php
$encryptionKeyDataForStorage = $key->saveToAsciiSafeString()
```

This returns an encoded string that you can use to persist a key across multiple
runs of the application. You might decide to copy it to a configuration file
not tracked by Git, for example. To load it again on the next script execution,
just do this:

```php
$key = \Defuse\Crypto\Key::LoadFromAsciiSafeString($storedKeyData);
```

### Encrypting Strings

Once you have a `Key` object, you're ready to encrypt data. All you have to do
is pass your desired string and the `Key` object to `Crypto::encrypt()`.

```php
try {
$ciphertext = \Defuse\Crypto\Crypto::encrypt("Test message", $key);
} catch (\Defuse\Crypto\Exception\CryptoTestFailedException $ex) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could throw a bunch of different types of exceptions, like CannotPerformOperationException. I have a new philosophy when it comes to exceptions: Don't catch them unless you can actually do something with the result (if nothing can do something with the result, then the process terminates and that's okay).

I think in our example code we shouldn't put try-catch but instead a comment mentioning it can throw various things (with the exception of InvalidCiphertextException).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good point. Don't enable "copy-paste programmers" to have a silent failure they didn't consciously write themselves.

die("Our platform is not secure enough to use this cryptography library.");
}
```

### Decrypting Strings

If encryption made sense, then the decryption API should be intuitive and
precisely what you expect it to be:

```php
try {
$plaintext = \Defuse\Crypto\Crypto::decrypt($ciphertext, $key);
} catch (\Defuse\Crypto\Exception\CryptoTestFailedException $ex) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again there are more exception types that can be thrown, but let's just mention that in a comment instead of trying to try...catch them all. We do want to try...catch the InvalidCiphertextException one in the example code though.

die("Our platform is not secure enough to use this cryptography library.");
} catch (\Defuse\Crypto\Exception\InvalidCiphertextException $ex) {
die("Ciphertext was modified in transit.");
}
```

### Interlude: A Complete Example

First, generate a key and store it:

```php
<?php
require_once "/path/to/defuse/php-encryption/autoload.php';
$key = \Defuse\Crypto\Key::createNewRandomKey();
file_put_contents('shared_key.txt', $key->saveToAsciiSafeString());
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make this an absolute path, e.g. /etc/examplekey.txt just so if someone copy/pastes this it isn't saving keys to the web root by default.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I see, it's a command line application. That isn't clear until you read the paragraph below.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd fix it by making the key path a command-line option (for all the scripts). That kills two birds with one stone. It 1. Makes it obvious that it's a command-line program, and 2. Fixes the issue of people copy/pasting it into web code.

```

The two scripts below, `encrypt_msg.php` and `decrypt_msg.php` are command-line
PHP scripts meant to encrypt/decrypt messages using a pre-shared-key.

Sender:

```php
<?php
use \Defuse\Crypto\Crypto;
use \Defuse\Crypto\Key;
require_once "/path/to/defuse/php-encryption/autoload.php';

$keyData = file_get_contents('shared_key.txt');
$key = Key::LoadFromAsciiSafeString($keyData);

$encrypted = Crypto::encrypt($argv[1], $key);
echo $encrypted, "\n";
```

Receiver:

```php
<?php
use \Defuse\Crypto\Crypto;
use \Defuse\Crypto\Key;
require_once "/path/to/defuse/php-encryption/autoload.php';

$keyData = file_get_contents('shared_key.txt');
$key = Key::LoadFromAsciiSafeString();

$decrypted = Crypto::decrypt($argv[1], $key);
echo $decrypted, "\n";
```

If you run this command:

php decrypt_msg.php `php encrypt_msg.php It\ Works\!`
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe make decrypt read from standard in so that the command becomes:

echo "It works!" | php encrypt_msg.php | php decrypt_msg.php

Doesn't really matter to me though.


It will print "It works!" into your console. Now, assuming you and your
recipient have the same `shared-key.txt`, you can send messages to/from them and
only they should be able to decrypt them.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be: "...assuming you and your recipient have the same shared-key.txt, and nobody else knows the contents of that file, you can send messages to/from them and only they will be able to decrypt them."


### Encrypting and Decrypting Files

In addition to our standard `Crypto::encrypt()` and `Crypto::decrypt()`
interface, this library has a separate class for encrypting/decrypting files.

This is mostly useful for encrypting large files (say, 1.5 GB) on a machine with
very low memory usage (say, a maximum of 64 MB of RAM).

```php
\Defuse\Crypto\File::encryptFile($inputFilename, $outputFilename, $key);
\Defuse\Crypto\File::decryptFile($encryptedFile, $plaintextFile, $key);
```

Audit Status
-------------

Expand Down Expand Up @@ -74,17 +227,12 @@ This library is developed around several core values:

- Rule #4: The library should require no special installation.

> Some PHP encryption libraries, like libsodium-php [1], are not
> straightforward to install and cannot packaged with "just download and
> extract" applications. This library will always be just a handful of PHP
> files that you can copy to your source tree and require().

References:

[1] https://github.com/jedisct1/libsodium-php
> Some PHP encryption libraries, like [libsodium-php](https://github.com/jedisct1/libsodium-php),
> are not straightforward to install and cannot packaged with "just download
> and extract" applications. This library will always be just a handful of
> PHP files that you can copy to your source tree and require().

Authors
---------

This library is authored by Taylor Hornby and Scott Arciszewski.

This library is authored by [Taylor Hornby](https://bqp.io) and [Scott Arciszewski](https://paragonie.com/blog/author/scott-arciszewski).