PHPackages                             starekrow/lockbox - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Security](/categories/security)
4. /
5. starekrow/lockbox

ActiveLibrary[Security](/categories/security)

starekrow/lockbox
=================

Lockbox is a simple, tiered system for working with cryptographic keys and encrypted data.

96916[7 issues](https://github.com/starekrow/lockbox/issues)[1 PRs](https://github.com/starekrow/lockbox/pulls)PHP

Since Dec 15Pushed 7y ago6 watchersCompare

[ Source](https://github.com/starekrow/lockbox)[ Packagist](https://packagist.org/packages/starekrow/lockbox)[ RSS](/packages/starekrow-lockbox/feed)WikiDiscussions master Synced 2d ago

READMEChangelogDependenciesVersions (3)Used By (0)

[![build status](https://camo.githubusercontent.com/84bbe1ac6ca6c2abf371a69856aa673c648a5d1e4f0e5d15d28a19a5a1f55756/68747470733a2f2f7472617669732d63692e6f72672f73746172656b726f772f6c6f636b626f782e7376673f6272616e63683d6d6173746572)](https://travis-ci.org/starekrow/lockbox)

Lockbox
=======

[](#lockbox)

Lockbox is a simple, tiered system for working with cryptographic keys and encrypted data. It provides a set of easy-to-use interfaces that encourage a "secure by default" design.

There are three primary concepts to Lockbox: *Keys*, *secrets* and *vaults*. Keys are used for encryption or decryption of data. Secrets are data values that can be read or written using multiple keys. A vault is one way to store a collection of secrets, that also comes with some built-in key management tools.

Interesting fact: The classes here were originally designed to support responsible handling of authentication tokens for server applications, to ensure that the various passwords and API keys for production servers weren't just dumped in plain text into the file system. This is particularly important for cloud servers, where access to the disk images is entirely out of the so-called "site owner's" control.

Quick-Start
-----------

[](#quick-start)

### Manual Install

[](#manual-install)

Grab all the files from the `src/` directory here and stick them somewhere. Arrange to autoload them. If you instead want to require() them, this is the block you'll need:

```
require_once "CryptoCore.php";
require_once "CryptoCoreLoader.php";
require_once "CryptoCoreFailed.php";
require_once "CryptoCoreBuiltin.php";
require_once "CryptoCoreOpenssl.php";
require_once "Crypto.php";
require_once "CryptoKey.php";
require_once "Secret.php";
require_once "Vault.php";
```

### Composer Install

[](#composer-install)

See . Greetz to @KJLJon.

### Using Lockbox

[](#using-lockbox)

Suck the classes you'll be using into your namespace (or don't, but you'll be typing "starekrow" a lot).

```
use starekrow\Lockbox\CryptoKey;
use starekrow\Lockbox\Secret;
use starekrow\Lockbox\Vault;
```

To encrypt some data:

```
// CryptoKey defaults to AES-128-CBC encryption with a random key
$key = new CryptoKey();
$message = "You can't see me.";
$ciphertext = $key->Lock( $message );

file_put_contents( "key.txt", $key->Export() );
file_put_contents( "cipher.txt", $ciphertext );
```

To decrypt some encrypted data:

```
$key = CryptoKey::Import( file_get_contents( "key.txt" ) );
$ciphertext = file_get_contents( "cipher.txt" );
$message = $key->Unlock( $ciphertext );
echo $message; 			// "You can't see me."
```

To use a specified key and a different cipher:

```
$key = new CryptoKey( "ILikeCheese", null, "AES-256-ECB" );
$no_see_um = $key->Lock( "This text is safe." );
$see_um = $key->Unlock( $no_see_um );
```

> Note that if your key is not the expected length for the given cipher, PHP's `openssl` extension will apply some default padding or cropping to your key data. For interoperability with non-PHP crypto systems, be sure to specify the key at the proper length for your chosen cipher.

To encrypt some data (even structured data) so that it can be decrypted with more than one key:

```
$s = new Secret( [ "my stuff" => "Sooper seekrit" ] );
$k = new CryptoKey( "correcthorsebatterystaple" );
$k2 = new CryptoKey( "ILikeCheese" );
$s->AddLockbox( $k );
$s->AddLockbox( $k2 );
file_put_contents( "secret.txt", $s->Export() );
file_put_contents( "key.txt", $k->Export() );
file_put_contents( "key2.txt", $k2->Export() );
```

To get that data back:

```
$s = Secret::Import( file_get_contents( "secret.txt" ) );
$k = CryptoKey::Import( file_get_contents( "key.txt" ) );
$s->Unlock( $k );
$val = $s->Read();
echo $val["my stuff"]; 				// "Sooper seekrit"
```

Interestingly, `secret.txt` contains something like:

```
{
    "locks": {
	"17e9c178-7a99-47ac-a422-5ec9a9e0a6e8": "2W2ElRE4S7xu93xxcvIF7dubb+46YhgZKDS3Lnztc7YDL+Had4nNIRqZ03jzW8w1IaZtMAudFTQFLejVYMwDeHnpHotBR5UBo0TZq4jgW2hetGbahLOpni3hhwbU9at8By34Dj53UfK84pXyOe2RH90+b/vL9OLAD51hupsbI2TlKPjCsys8V3EhaIz0a57yCKhAyMarZkyklRKvFYvbKw==",
	"0188b485-0937-4695-a0d6-5f968b286fc9": "Ugq4MuwOfvyKlREhVJDFLuRR8U7O6y0e3KYD2Gllk4QC0EaC2MJDtJ9yCkePF49zsukgmjSpHvhAjg1ZN3yWEOR8DE3kDY8rai9RC1LRRC0iK2nTg7DqCsvUV57nY1mG5MVpW8LXAirjRtCasj2yJu1D1JY0U06hXpSDoVzaLSFqPoRoSAI231SwISgnqhLCUEt7L7LGwIt3voMehH6wxg=="
    },
    "data": "+2uEgQ52VGOVvGu41umPhjurmqhoXHMqhbzoFeQuWs63rFQNVW9HK3dlEddEyZfoe+lXT2M5MElUfdXF1vWZ8mLiorVkN8N+Waz6YeyZ3CePpYPNsZT9yMCWAQNwnTjU"
}
```

And `key.txt` contains:

```
k0|17e9c178-7a99-47ac-a422-5ec9a9e0a6e8|QUVTLTEyOC1DQkM=|Y29ycmVjdGhvcnNlYmF0dGVyeXN0YXBsZQ==

```

Create a vault and put a value into it:

```
$v = new Vault( "./secrets" );
$v->CreateVault( "CorrectHorseBatteryStaple" );
$v->Put( "test1", "This is a test." );
$v->Close();
```

Open an existing vault and read a value from it:

```
$v = new Vault( "./secrets" );
$v->Open( "CorrectHorseBatteryStaple" );
$got = $v->Get( "test1" );
echo $got;						// prints "This is a test."
```

How it Works
------------

[](#how-it-works)

Each tier of the interface adds capabilities:

- `CryptoKey` handles basic encryption and decryption, and packages both the keys and the ciphertext for output, verification and decryption.
- `Secret` is a managed, encrypted data value with lockbox-style key handling.
- A `Vault` is file-based storage for secrets, with a master key and some additional key management tools.
- `Crypto` is a low-level interface that provides hashing and encryption of raw data.

### CryptoKey

[](#cryptokey)

All of the actual encryption and decryption is done with `CryptoKey` instances. These bundle together the pieces - cipher type and key data, along with a unique key identifier to help with higher-level management - needed to successfully decrypt a previously encrypted message. They also produce representations of themselves and of the encrypted messages in tidy, ASCII-safe strings.

Think of a key as a complete encryption package: You use the key to lock plaintext (producing ciphertext) and to unlock ciphertext (producing plaintext).

A `CryptoKey` can be built with an (optional) passphrase, an (optional) id string and an (optional) cipher specifier. Any parameter that isn't specified is filled with a reasonable default: A 256-bit random key, a 128-bit (well, 123-bit) random ID formatted as a GUID, and an AES-128-CBC cipher.

The output of a `Lock()` operation includes the IV used and an HMAC of the ciphertext, as well as the ciphertext itself. Those are then concatenated and base-64 encoded. The result can be easily verified and decrypted with `Unlock()`.

The keys themselves, along with the exact cipher used and the key identifier, can be converted to a simple printable string representation with `Export()`and read back in with `Import()`.

### Secret

[](#secret)

The `Secret` class provides a more extensive interface to handling a value that needs to be protected. Each secret consists of three parts:

- The value itself is a binary string. Serialization from and to other data types is automatic.
- A random 256-bit *internal key* is used to encrypt the value.
- One or more *lockboxes* is attached.

The secret is created with any value, and can be locked (or unlocked) with one or more different keys, using a virtual lockbox model. In this model, the secret's value is encrypted with the internal key. However, the internal key is never saved directly, but is itself encrypted by the various lockbox keys you supply. This arrangement has the following interesting properties:

- The value can be decrypted with multiple, independent passphrases.
- The value can be updated by anyone with a valid lockbox key. Other key-holders will then see the updated value.
- A lockbox can be removed *without* decrypting the value.
- A lockbox can only be added by a valid key-holder.
- A lockbox key cannot be used to learn anything about the other lockbox keys (except their public ID, which is in the clear anyway).

Like keys, secrets are rendered in an ASCII-safe printable package (in this case, a JSON wrapper around some base-64 strings) with `Export()` and can be reconstituted with `Import()`. `AddLockbox()` takes a key you supply and encrypts the internal key with it, adding the resulting virtual lockbox to the secret. Additional management can be done with `RemoveLockbox()`, `HasLockbox()` and `ListLockboxes()`.

`Unlock()` takes a key matching any lockbox and decrypts the internal key from the lockbox. `Lock()` just discards any saved copies of the internal key and decrypted value.

If the secret has been unlocked, you can use `Read()` to get the value out of it, and `Update()` to change it.

### Vault

[](#vault)

A `Vault` uses the properties of the `Secret` class to provide an encrypted key-value store on disk that is as robust to interruption as the underlying file system.

You supply the name of a directory for the vault, and the secrets are stored in individual files in that directory. A random *master key* is generated and used to encrypt each one. That master key is itself encrypted with a passphrase, an arrangement that allows the passphrase to be changed without changing the master key, and allows the master key itself to be rotated in stages, no matter the size of the vault.

When using a vault, all the key and secret management is handled for you. Use `CreateVault()` to set up a new vault (this will fail if a vault already exists in the chosen directory) or `Open()` to open an existing one. `VaultExists()` and `DestroyVault()` round out the vault management suite. `Close()` forgets all keys and cached secrets without affecting the vault on disk.

Manage values within the vault with `Put()`, `Get()`, `Has()`, `Remove()` and `PerSecret()`.

You can change the passphrase used to encrypt the master key with `ChangePassphrase()`. This is a comparatively fast and safe operation, affecting only one file. Rotate the master key itself with `RotateMasterKey()`.

### Crypto

[](#crypto)

`Crypto` is a low-level encryption interface. It is designed as a straightforward compatibility layer, to hide some of the differences between the various available cryptography extensions (and PHP versions) from `CryptoKey`.

You should only use `Crypto` directly if you have a pretty good idea of what you're doing.

Exposure Risks
--------------

[](#exposure-risks)

This being PHP, there's no way (barring extensions) to actually scrub the contents of RAM. It might in fact not even be useful to do so anyway, due to other information leaks (swap files) allowed by many OS configurations. In-process damage (e.g. Heartbleed) might also defeat such measures. The following steps are taken to try to minimize the exposure risk:

- Secrets can be loaded without supplying a key at all. This leaves just the encrypted text and the encrypted lockboxes in RAM. So you can prospectively load secrets and only decrypt them if needed. This also allows removing a lockbox from a secret without ever supplying the key.
- Unlocking a secret does not automatically decrypt the value. The internal key *is*, however, stored - in the clear - in RAM after unlocking. This provides for the case where you want to add a lockbox to a secret but do not want to needlessly expose the unencrypted value in RAM.
- Vaults only load secret values from disk as they are requested.
- The passphrase used to decrypt a `Vault` master key is *not* retained by the `Vault` instance. Though, again, the master key itself *is* stored in the clear.
- Both `Secret` and `Vault` provide a `Close()` method that immediately detaches stored keys and plaintext values. `CryptoKey` provides a `Shred()`method that detaches the key data and id.

###  Health Score

28

—

LowBetter than 54% of packages

Maintenance19

Infrequent updates — may be unmaintained

Popularity26

Limited adoption so far

Community17

Small or concentrated contributor base

Maturity44

Maturing project, gaining track record

 Bus Factor2

2 contributors hold 50%+ of commits

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

### Community

Maintainers

![](https://www.gravatar.com/avatar/ede110031e92d8eba8d2d38d7448da28f4cfafcc5a212733d66e008356875b6f?d=identicon)[starekrow](/maintainers/starekrow)

---

Top Contributors

[![starekrow](https://avatars.githubusercontent.com/u/5818442?v=4)](https://github.com/starekrow "starekrow (13 commits)")[![KJLJon](https://avatars.githubusercontent.com/u/2103440?v=4)](https://github.com/KJLJon "KJLJon (8 commits)")[![alexmanno](https://avatars.githubusercontent.com/u/10499850?v=4)](https://github.com/alexmanno "alexmanno (6 commits)")[![ukd1](https://avatars.githubusercontent.com/u/44345?v=4)](https://github.com/ukd1 "ukd1 (1 commits)")

---

Tags

aesencrypted-storeencryptionkey-managementphp

### Embed Badge

![Health badge](/badges/starekrow-lockbox/health.svg)

```
[![Health](https://phpackages.com/badges/starekrow-lockbox/health.svg)](https://phpackages.com/packages/starekrow-lockbox)
```

###  Alternatives

[defuse/php-encryption

Secure PHP Encryption Library

3.9k162.4M214](/packages/defuse-php-encryption)[roave/security-advisories

Prevents installation of composer packages with known security vulnerabilities: no API, simply require it

2.9k97.3M6.4k](/packages/roave-security-advisories)[mews/purifier

Laravel 5/6/7/8/9/10 HtmlPurifier Package

2.0k16.7M113](/packages/mews-purifier)[robrichards/xmlseclibs

A PHP library for XML Security

41278.1M118](/packages/robrichards-xmlseclibs)[bjeavons/zxcvbn-php

Realistic password strength estimation PHP library based on Zxcvbn JS

86917.5M63](/packages/bjeavons-zxcvbn-php)[enlightn/security-checker

A PHP dependency vulnerabilities scanner based on the Security Advisories Database.

33732.2M110](/packages/enlightn-security-checker)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
