Download the PHP package helppc/encryption-bundle without Composer

On this page you can find all versions of the php package helppc/encryption-bundle. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package encryption-bundle

EncryptionBundle

Symfony bundle exposing a typed encryption facade over spaze/encryption, which uses Halite on top of libsodium.

The bundle implements no cryptography of its own. It contributes configuration, dependency injection, key rotation ergonomics, and interfaces narrow enough that asking a group for something it cannot do — reading a write-only group, binding additional data to a sealed box — fails while the container is compiled rather than on the first request in production. Key material itself is validated when the encryption service is created; see Exceptions.

Requirements

Installation

Register the bundle in config/bundles.php:

Generating keys

The prefix is free-form and makes a leaked credential identifiable — usually an initialism of its purpose, adek for address data encryption key. The command refuses a prefix containing _, because _ separates the prefix from the key and from the optional public/secret role tag, and the command's output would stop being readable in one direction. It is a rule of the command, not a validation of the configuration: a key whose prefix contains _ is accepted at runtime, as long as key_prefix says exactly the same thing.

Put the values in .env.local and reference them with %env()%. A key written literally into a YAML file ends up in plain text in the compiled container under var/cache/, which leaks into backups, deploy artifacts and debug tarballs.

Configuration

Each group becomes one service, encryption.<group>.

Encryption types

type EncryptionType case Who can encrypt Who can decrypt Additional data Can be write-only
symmetric (default) Symmetric anyone with the key anyone with the key yes no
asymmetric Asymmetric holder of the key pair the other party, and you yes no
anonymous_asymmetric AnonymousAsymmetric anyone with the public key holder of the secret key no yes

For anonymous_asymmetric, either every key of the group defines secret_key or none does. A mixed state is rejected: a group that can decrypt has to be able to decrypt data encrypted with its older keys too.

A group goes write-only by leaving secret_key out, not by setting it to an empty string. An explicit secret_key: '' is rejected, because a config generator emitting an empty value would otherwise silently take away the ability to decrypt, and nothing would notice until something asked that group for a Decryptor.

Naming the type through the enum

type is backed by the HelpPC\EncryptionBundle\EncryptionType enum. Plain strings keep working, but both YAML and PHP can name the case instead.

In YAML through Symfony's !php/enum tag:

A typo in the case name is then a parse error naming the enum, instead of a value that silently means nothing.

In PHP configuration the case goes in directly:

Whichever spelling is used, an unknown value is rejected while the configuration is processed:

Usage

The default group is wired to the bare type hints:

Other groups are addressed by name:

#[Target] accepts both partner_inbox and partnerInbox. Alternatively use #[Autowire(service: 'encryption.partner_inbox')].

Interfaces

Interface Methods
Encryptor encrypt, isEncrypted, needsReEncryption
Decryptor decrypt
AdditionalDataEncryptor (extends Encryptor) encryptWithAdditionalData
AdditionalDataDecryptor (extends Decryptor) decryptWithAdditionalData

The split is deliberate. A write-only group is registered as a class that does not implement Decryptor, and no Decryptor alias is created for it, so type-hinting one fails while the container is being compiled. Anonymous asymmetric groups do not implement the AdditionalData* interfaces, because sealed boxes have no such API in Halite.

Additional data

Additional data cryptographically binds a cipher text to a context — a row id, a column name, a tenant id. It is authenticated but not encrypted, so it must not be a secret. It prevents a valid cipher text from being copied from one place to another.

The methods live on the extended interfaces, so those are what a consumer type-hints:

The value must be non-empty and byte identical on both sides, otherwise decryption fails. Not available for anonymous_asymmetric.

Key rotation

Add a new key, make it active, and new data is encrypted with it. Old data stays readable as long as the old key remains configured.

Once nothing reports needsReEncryption() any more, drop the old key.

Both needsReEncryption() and isEncrypted() are structural checks that decrypt nothing. They read the key id and the marker out of the envelope, and neither of them verifies that the key id is one of the configured ones, or that the payload authenticates. A structurally valid value carrying an unknown key id therefore reports needsReEncryption() === true, and only the decrypt() in the snippet above fails on it. Do not read a true as proof that the value belongs to this group.

The difference between the two is what happens to a value that is not cipher text of this type at all: needsReEncryption() throws, isEncrypted() returns false and never throws. Use isEncrypted() when scanning a column that still holds a mix of plain and encrypted values.

Always generate a fresh key for a new key id. How well the key id in a stored value is protected depends on the format and the type:

Value Key id and marker
symmetric or asymmetric, written by spaze/encryption 3.0 and later authenticated — they go into what decryption verifies, so editing either makes decryption fail
anonymous_asymmetric, any version not authenticated — a sealed box has nowhere to carry the verification
any type, written before 3.0, without a marker not authenticated

Where they are not authenticated, editing the stored key id only makes decryption reach for a different key, and it fails because that key is a different one. That is the whole reason two ids must never point at the same key: a value moved between them would then decrypt under both. The rule holds for every group, because the anonymous type never gets the protection and pre-3.0 values never had it.

Upgrading to spaze/encryption 3.0

[!WARNING] Upgrade every deployment that reads the data before any of them starts writing it.

Version 3 writes a new cipher text format carrying a marker that says which method created the value, $<keyId>$<marker>$<cipherText>. Versions before it wrote $<keyId>$<cipherText> and cannot read a value that has a marker in it. When several deployments share the same database — a rolling deploy, a worker fleet, a read replica of the same rows — one of them upgrading first and writing a single value is enough to hand the others data they cannot decrypt.

So either upgrade all of them before the first new write, or stop writing for the duration of the upgrade. There is no format flag to turn the marker off.

Nothing is lost the other way round: values written by version 2 keep decrypting, and needsReEncryption() reports them, so the usual re-encryption sweep migrates them to the marked format. Until then, they keep the weaker guarantees of the unmarked format.

Upstream release notes: https://github.com/spaze/encryption/releases/tag/v3.0.0

Exceptions

Exception When
EncryptionException encryption failed; checked
DecryptionException malformed cipher text, unknown key id, wrong format, or failed authentication; checked
InvalidEncryptionConfigurationException a group cannot be built from its configuration; unchecked

InvalidEncryptionConfigurationException is thrown at two different moments, and the difference matters for what a deploy can still discover after a green build:

Fails while the container is compiled Fails when the encryption service is created
the shape of the configuration: a default_group naming a group that does not exist, more than one group and no default, a key missing the component its type needs (key, public_key, secret_key), an anonymous_asymmetric group defining secret_key for some of its keys but not all the key material: a wrong prefix, a value that is not hexadecimal, a key that does not decode to 32 bytes, a secret key where a public one belongs, a public key that does not belong to its secret key, an active_key that is not among the keys

Two more kinds of error fail at compile time without going through this exception. A group with no key_prefix, active_key or keys at all is rejected by Symfony's config component with InvalidConfigurationException, the same way an unknown type is. And a type error — type-hinting Decryptor for a write-only group, or AdditionalDataEncryptor for an anonymous one — cannot be autowired, which is what the narrow interfaces are for.

Key material is deliberately left for later. The keys come from %env()%, and resolving them while the container is compiled would write them into var/cache/ — exactly what Generating keys warns against. So the container builds, boots, and the group throws on the first get() of its service. tests/Integration/ContainerTest.php covers both halves of this: testReadingAWriteOnlyGroupFailsWhileTheContainerIsCompiled() and testMisconfiguredGroupFailsWhenTheServiceIsBuilt().

Development

Before tagging a release, read the breaking change and migration notes of every upstream package that changed, spaze/encryption above all: a new cipher text format there is a coordination problem for everyone deploying this bundle, and it belongs in CHANGELOG.md and in the release notes, not only in the dependency bump.

License

MIT


All versions of encryption-bundle with dependencies

PHP Build Version
Package Version
Requires php Version >=8.4
ext-sodium Version *
spaze/encryption Version ^3.0
symfony/config Version ^7.4 || ^8.0
symfony/console Version ^7.4 || ^8.0
symfony/dependency-injection Version ^7.4 || ^8.0
symfony/http-kernel Version ^7.4 || ^8.0
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package helppc/encryption-bundle contains the following files

Loading the files please wait ...