Since our company's inception in 2015, we've sought to [make the Internet more secure for everyone](https://paragonie.com/blog/2015/12/year-2015-in-review).
Up front, this required doing a lot of the sort of work that benefits society but most companies wouldn't invest time or money in:
* Creating and maintaining open source libraries
* Updating tutorials, sample code, and other developer documentation to promote security best practices
* Designing new APIs and cryptographic protocols to replace error-prone standards
**So why did we?**
We reasoned that, in the long term, simply doing important work that benefits everyone is cheaper than airtime when it comes to advertising a security consulting company.
(*And we were right!* Our clients have been keeping us very busy. Hence, the drop in update frequency for our company blog for the past few years.)
However, we didn't get a lot of practice with marketing or advertising, which means some of the important work we've done over the years went unnoticed. For example: [Sigstore](https://www.sigstore.dev) does 2/3 of what [Gossamer](https://paragonie.com/blog/2022/01/solving-open-source-supply-chain-security-for-php-ecosystem) does, but the Sigstore team hadn't heard about it until a recent Hacker News thread.
To correct this oversight, we thought it would be helpful to provide a recap of some of the projects we've worked on since our inception that are still active today, and most importantly, why they matter for the security of the Internet.
## Contents
* [Open Source PHP Software](#open-source-php)
1. [sodium_compat](#sodium-compat)
2. [Halite](#halite)
3. [EasyDB](#easydb)
4. [Chronicle](#chronicle)
5. [Certainty](#certainty)
6. [CSP-Builder](#csp-builder)
7. [Sapient](#sapient)
8. [Corner](#corner)
9. [Ionizer](#ionizer)
10. [Easy-ECC](#easy-ecc)
* [Contributions and Alternatives to Internet Standards](#internet-standards)
1. [PASETO: Platform Agnostic SEcurity TOkens](#paseto)
2. [PASERK: Platform Agnostic SERialized Keys](#paserk)
* [Open Source Beyond the PHP Ecosystem](#open-source-beyond)
1. [Supply Chain Security](#supply-chain-security)
2. [Other Language Implementations of Our PHP Libraries](#other-languages)
* [Where We're Headed in the Immediate Future](#roadmap)
1. [Secure Key Discovery for Identity Providers](#key-discovery)
2. [Post-Quantum Cryptography](#post-quantum)
Open Source PHP Software
1. sodium_compat
> GitHub: [paragonie/sodium_compat](https://github.com/paragonie/sodium_compat)
sodium_compat is a pure PHP polyfill for the Sodium cryptography library (libsodium), a core extension in PHP 7.2.0+ and otherwise available in PECL.
Before PHP 7.2 was released, PHP developers didn't have a lot of good options available for cryptography.
* Use libmcrypt, which was an objectively terrible library if your goal is to coax developers into writing secure software
* Use OpenSSL, whose PHP bindings were often [subtly insecure due to the type system](https://web.archive.org/web/20210116203937/https://www.ripstech.com/php-security-calendar-2017/) and API design choices
* Install libsodium [from PECL](https://pecl.php.net/package/libsodium), since it wasn't bundled with PHP
The last point was particularly annoying for open source developers: If they wrote software to use libsodium, they were effectively killing adoption of their library since *so many* PHP applications are run by users that do not have the ability (or know-how) to install PHP extensions from PECL. This also meant incumbent open source software that had a lot of market share **couldn't use better cryptography without breaking backwards compatibility**.
To solve this problem, we [wrote an RFC for PHP 7.2 to add ext/sodium](https://wiki.php.net/rfc/libsodium) and then proceeded to re-implement most of libsodium in pure-PHP. We also [documented all of the steps we took to implement cryptography in PHP securely](https://paragonie.com/blog/2017/02/cryptographically-secure-php-development).
Sodium_compat has been installed over 30 Million times through Composer since its creation, and [is included in WordPress to verify the signature for core updates](https://paragonie.com/blog/2019/05/wordpress-5-2-mitigating-supply-chain-attacks-against-33-internet).
Needless to say, sodium_compat played no small part in delivering modern cryptography to the PHP ecosystem.
#### What Does Code That Uses Sodium_Compat Look Like?
It looks exactly like code that uses ext/sodium on PHP 7.2, except it will run on PHP 5.2 as well.
$alice_kp = sodium_crypto_sign_keypair();
$alice_sk = sodium_crypto_sign_secretkey($alice_kp);
$alice_pk = sodium_crypto_sign_publickey($alice_kp);
$message = 'This is a test message.';
$signature = sodium_crypto_sign_detached($message, $alice_sk);
if (sodium_crypto_sign_verify_detached($signature, $message, $alice_pk)) {
echo 'OK', PHP_EOL;
} else {
throw new Exception('Invalid signature');
}
You can see more example code at the [official PHP documentation](https://www.php.net/manual/en/book.sodium.php).
We also published a [quick start guide for developing with libsodium](https://paragonie.com/blog/2017/06/libsodium-quick-reference-quick-comparison-similar-functions-and-which-one-use).
#### Why Does Sodium_Compat Matter?
If you're ever tasked with implementing a cryptographic feature in your application, most security experts will tell you, "Don't roll your own crypto!"
And they're right: You should use libsodium instead. For systems that don't have the PHP extension for libsodium installed, sodium_compat makes your code *just work*.
2. Halite
> GitHub: [paragonie/halite](https://github.com/paragonie/halite)
**Halite** is a high-level cryptography interface that relies on libsodium for all of its underlying cryptography operations.
By high-level, we mean "recommended for non-experts". Halite is designed to be misuse-resistant and secure by default.
#### Halite Key Management
<?php
use ParagonIE\Halite\KeyFactory;
$encKey = KeyFactory::generateEncryptionKey();
KeyFactory::save($encKey, '/path/outside/webroot/encryption.key');
#### Halite Encryption
<?php
use ParagonIE\Halite\KeyFactory;
use ParagonIE\Halite\Symmetric\Crypto as Symmetric;
use ParagonIE\HiddenString\HiddenString;
$encryptionKey = KeyFactory::loadEncryptionKey('/path/outside/webroot/encryption.key');
$message = new HiddenString('This is a confidential message for your eyes only.');
$ciphertext = Symmetric::encrypt($message, $encryptionKey);
$decrypted = Symmetric::decrypt($ciphertext, $encryptionKey);
var_dump($decrypted->getString() === $message->getString());
Note: Any sensitive value (e.g. plaintext) uses our [HiddenString](https://github.com/paragonie/hidden-string) library to prevent it from accidentally leaking in a stack trace.
#### Why Does Halite Matter?
While libsodium (and, by extension, sodium_compat) provides a secure foundation for developing cryptographic software, and far safer than its competitors, it's still a low-level library from a developer's perspective.
With Halite, you don't even have to *know what a nonce is*, let alone generate/manage them securely. Furthermore, cryptography protocol and/or message format migrations are taken care of out-of-the-box.
Want to use human-memorable passwords for cryptography use cases? Halite exposes a dedicated key derivation API, and the encryption methods are strictly-typed to prevent a user from accidentally using `"hunter2"` (or `md5("hunter2")`, or ...) as a cryptography key.
Consequently, if you're doing anything with cryptography in PHP, Halite is *probably* the tool you want for the job. (See below for alternative tools that satisfy other use-cases.)
3. EasyDB
> GitHub: [paragonie/easydb](https://github.com/paragonie/easydb)
Writing insecure PHP code that interacts with a SQL database used to be extremely easy. So easy, in fact, that SQL Injection has spent many years at the top of the OWASP Top 10.
Since PHP 5.1.0, PHP has provided a library for interacting with databases. However, it was demonstrably [not as easy to use](https://paragonie.com/blog/2015/05/preventing-sql-injection-in-php-applications-easy-and-definitive-guide). You couldn't get clever one-liners out of a code snippet with PDO like you could with `mysql_query()` and `mysql_fetch_assoc()`.
To address that, we developed EasyDB, which does all of the following:
1. Provides convenience methods to make talking to a SQL database easier and require less boilerplate.
2. Encourages users to use prepared statements, whether they realize it or not.
3. Configures PDO to use secure defaults (i.e. disables prepared statement emulation, so that no clever input parameter can ever mutate the structure of the prepared statement).
Code that uses EasyDB is simple and easy to understand.
/* You cannot get SQL injection here */
$db->insert('table_name', [
'example' => $_GET['foo']
]);
/* Placeholders become intuitive: */
foreach ($db->run("SELECT * FROM foo WHERE bar = ?", $_GET['bar']) as $row) {
var_dump($row);
}
If you want to securely generate dynamic queries, you can use [EasyStatement](https://github.com/paragonie/easydb#generate-dynamic-query-conditions):
$statement = EasyStatement::open()
->with('last_login IS NOT NULL');
if (str_contains($_POST['search'], '@')) {
// Perform a username search
$statement->orWith('username LIKE ?', '%' . $db->escapeLikeValue($_POST['search']) . '%');
} else {
// Perform an email search
$statement->orWith('email = ?', $_POST['search']);
}
// The statement can compile itself to a string with placeholders:
echo $statement; /* last_login IS NOT NULL OR username LIKE ? */
// All the values passed to the statement are captured and can be used for querying:
$user = $db->single("SELECT * FROM users WHERE $statement", $statement->values());
Until recently, one limitation of EasyDB is that you couldn't call Stored Procedures or SQL functions inside your INSERT/UPDATE queries.
As of version 2.12.0, you can use the new `EasyPlaceholder` class to invoke SQL functions. This feature supports standard `?` PDO placeholders, so you can safely parametrize these function calls.
$db->insert('table_name', [
'foo' => $_GET['bar'],
'timestamp' => new EasyPlaceholder('NOW()'),
'expired' => new EasyPlaceholder('TIMESTAMPADD(HOUR, 2, NOW())'),
'location' => new EasyPlaceholder(
"ST_GeomFromText(CONCAT('POINT(', ?, ' ', ?, ')'))",
$_GET['latitude'],
$_GET['longitude']
),
'sql_injection' => false
]);
We recently released EasyDB version 3.0 which makes use of PHP 8's improved type system and includes [Psalm taint-analysis annotations](https://psalm.dev/docs/security_analysis).
#### Why Does EasyDB Matter?
Developers that are still writing SQL by hand, rather than using an ORM, will appreciate the convenience methods that EasyDB offers after using it for a short time. This is especially true for report generation utilities and CRUD app development (which basically involves mapping user input to database columns inside insert/update/delete queries).
Secretly, EasyDB is also protecting applications from SQL injection by making prepared statements more user-friendly, and encouraging their use.
If you use EasyDB as described in the documentation, you are overwhelmingly more likely to be impervious to SQL injection in your application than if you tried to work with PDO directly—especially if you're in a rush.
If you find yourself using EasyDB to insert/update many rows, you may want to use [EasyDB-Cache](https://github.com/paragonie/easydb-cache) to cache the PDOStatement objects for reuse.
4. Chronicle
> GitHub: [paragonie/chronicle](https://github.com/paragonie/chronicle)
Chronicle is an append-only cryptographic ledger. It consists of a Slim microservice, a SQL database, and a [chain data structure based on the BLAKE2b hash function](https://github.com/paragonie/blakechain).
#### Why Does Chronicle Matter?
If you ever find yourself being told, "We need to use blockchain to solve this problem," look instead at Chronicle.
Chronicle provides the same kind of security that developers expect from blockchains, but without [all of the speculative investment inherent to the cryptocurrency domain](https://www.youtube.com/watch?v=YQ_xWvX1n9g).
The publishing model for Chronicle is simple: **Centralized publishing, decentralized verification.** Not only is this much easier to scale up than peer-to-peer with Global State, but it's faster and better for the environment.
Chronicle is the append-only data structure used by many other of our projects, so while it might not seem immediately useful, it's worth paying attention to.
5. Certainty
> GitHub: [paragonie/certainty](https://github.com/paragonie/certainty)
We wrote [a blog post dedicated to Certainty](https://paragonie.com/blog/2017/10/certainty-automated-cacert-pem-management-for-php-software) in 2017 when we first released it.
Certainty keeps your CACert bundles up-to-date so you don't have to deal with this manually.
<?php
use ParagonIE\Certainty\RemoteFetch;
$fetcher = new RemoteFetch('/path/to/certainty/data');
$latestCACertBundle = $fetcher->getLatestBundle();
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_CAINFO, $latestCACertBundle->getFilePath());
You can learn more about Certainty [here](https://github.com/paragonie/certainty/blob/master/docs/features/RemoteFetch.md).
#### How Certainty Works
Certainty checks a remote source (default: our GitHub repository) every so often (default: every 24 hours) for new CACert files.
If a new file is discovered in our repository, it will do the following:
1. Check that the SHA256 checksum matches the file.
* This SHA256 checksum is identical to the [Mozilla bundle](https://curl.haxx.se/docs/mk-ca-bundle.html), which enables security auditors to perform independent verification.
2. Verify an Ed25519 signature of the file.
* Paragon Initiative Enterprises, LLC manages the corresponding secret key. If a signature is valid, you know it was issued by us.
3. Verifies that the bundle information (including SHA256 checksum and Ed25519 signature) were committed to [the PHP Chronicle](https://php-chronicle.pie-hosted.com/chronicle).
This provides a greater level of assurance than simply trusting us to never misbehave.
#### Why Does Certainty Matter?
Certainty keeps you from accepting certificates in the event of a Certificate Authority compromise. Certainty also allows open source developers to keep strict certificate validation enabled without having to worry about their users' configuration.
There's no excuse for writing eCommerce plugins that are vulnerable to man-in-the-middle attacks despite using SSL/TLS in 2022. Use Certainty instead.
6. CSP-Builder
> GitHub: [paragonie/csp-builder](https://github.com/paragonie/csp-builder)
Did you know that you can send a header in your HTTP responses to mitigate XSS attacks? It's called a [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) (CSP).
Content-Security-Policy headers look like this:
Content-Security-Policy: base-uri 'self'; default-src 'self'; child-src https://www.youtube.com https://www.youtube-nocookie.com; connect-src 'self'; font-src 'self'; form-action 'self' https://example.com; frame-ancestors 'none'; img-src 'self' https://ytimg.com ytimg.com data:; media-src 'none'; object-src 'none'; script-src 'self' https://ajax.googleapis.com https://cdn.mathjax.org https://oss.maxcdn.com https://www.google-analytics.com 'sha256-qznLcsROx4GACP2dm0UCKCzCGHiZ1guq6ZZDob/Tng='; style-src 'self'; report-uri /csp_violation; report-to csp; upgrade-insecure-requests
Did you get all of that? No? Maybe this would be better:
{
"report-only": false,
"report-uri": "/csp_violation",
"report-to": "csp",
"base-uri": {
"self": true
},
"default-src": {
"self": true
},
"child-src": {
"allow": [
"https://www.youtube.com",
"https://www.youtube-nocookie.com"
],
"self": false
},
"connect-src": {
"self": true
},
"font-src": {
"self": true
},
"form-action": {
"allow": [
"https://example.com"
],
"self": true
},
"frame-ancestors": [],
"img-src": {
"allow": [
"https://ytimg.com"
],
"self": true,
"data": true
},
"media-src": [],
"object-src": [],
"plugin-types": [],
"script-src": {
"allow": [
"https://ajax.googleapis.com",
"https://cdn.mathjax.org",
"https://oss.maxcdn.com",
"https://www.google-analytics.com"
],
"hashes": [
{
"sha256": "qznLcsROx4GACP2dm0UCKCzCG-HiZ1guq6ZZDob/Tng="
}
],
"self": true,
"unsafe-inline": false,
"unsafe-eval": false
},
"style-src": {
"self": true
},
"upgrade-insecure-requests": true
}
#### Why Does CSP-Builder Matter?
As an additional layer of defense, CSP Headers are an excellent way to prevent user-generated content from becoming an XSS exploit. However, by themselves, they're a bit unwieldy.
CSP-Builder was created to do two things:
1. Load baseline policies from a JSON file
2. Update policies at runtime (i.e. for supporting `nonce` directives when interfacing with template engines, such as Twig)
CSP-Builder can inject the headers into a PSR-7 HTTP message object or export them to disk (i.e. to an nginx snippet file), or return the generated header directly for you to use in your application.
There's not much more to say about CSP-Builder. It's a simple tool that does its job well. The page you're reading sent a CSP header, generated by CSP-Builder.
7. Sapient
> GitHub: [paragonie/sapient](https://github.com/paragonie/sapient)
Let's assume, for the moment, that a Certificate Authority has been utterly compromised and the attacker is using a mis-issued certificate to launch a man-in-the-middle attack on your application.
That's game over, no? Well, not necessarily.
Sapient lets you introduce application-layer cryptography to your HTTP requests and responses, which means you can do all of the following:
* Sign your HTTP messages, with Ed25519
* Symmetric-encrypt your HTTP messages, with XChaCha20-Poly1305
* MAC your HTTP messages, with HMAC-SHA512 (truncated to 256 bits)
* Asymmetric-encrypt your HTTP messages, with X25519 + BLAKE2b + XChaCha20-Poly1305
Note: Sapient signs the contents (i.e. body) of an HTTP message, not the headers. This allows you to use multiple Sapient features in the same HTTP response; provided the operations are performed in the correct order.
i.e. `seal` -> `sign` must be paired with `verify` -> `unseal`, since the encryption replaces the HTTP body.
#### Why Does Sapient Matter?
In addition to being an additional layer of defense for the most sensitive of server-side requests, Sapient is required for writing to a [Chronicle](#chronicle).
8. Corner
> GitHub: [paragonie/corner](https://github.com/paragonie/corner)
PHP Exceptions and Errors designed to prevent your users from sharp corners. Inspired by [Rust's helpful error messages](https://twitter.com/acfoltzer/status/1074813646625169408).
Corner is mostly useful for open source developers to help their users figure out what's happening without polluting the default Exception message behavior with needless data.
To that end, Corner exposes a separate method: **`getHelpfulMessage()`**, which developers are encouraged to use to expose a more detailed explanation of what went wrong.
To aid developers in producing more helpful messages, the `getSnippet($before = 0, $after = 0, $traceWalk = 0)` API grabs the line of code that produced the error (with optional leading/trailing lines, and an optional number of steps down the stack trace). This is intended to be used inside `getHelpfulMessage()`.
If all else fails, the `getSupportLink()` API allows for bug-specific documentation links to be furnished directly to the user to prevent them from having to search for it.
#### Why Does Corner Matter?
If you maintain open source PHP software, Corner allows you to make troubleshooting less painful. Combined with other features (i.e. [Whoops](https://github.com/filp/whoops)), Corner serves to make PHP development less painful for everyone.
One of our ongoing efforts is to use Corner in more of our libraries. (Polyfill libraries will not be included in this effort, to avoid breaking backwards compatibility; since that's the entire point of a polyfill.)
9. Ionizer
> GitHub: [paragonie/ionizer](https://github.com/paragonie/ionizer)
Ionizer is **strict-typing** for user input.
<?php
use ParagonIE\Ionizer\GeneralFilterContainer;
use ParagonIE\Ionizer\InputFilter;
use ParagonIE\Ionizer\Filter\{
AllowList,
BoolFilter,
IntArrayFilter,
IntFilter,
StringFilter
};
// Define properties to filter:
$ic = new GeneralFilterContainer();
$ic->addFilter(
'username',
(new StringFilter())->setPattern('^[A-Za-z0-9_\-]{3,24}$')
)
->addFilter(
'passphrase',
(new StringFilter())
)
->addFilter(
'dob.day',
(new IntFilter())
->setMinimumValue(1)
->setMaximumValue(31)
)
->addFilter(
'dob.month',
(new IntFilter())
->setMinimumValue(1)
->setMaximumValue(12)
)
->addFilter(
'dob.year',
(new IntFilter())
->setMinimumValue(1900)
->setMaximumValue((int) date('Y'))
)
->addFilter(
'domain',
new AllowList('US-1', 'US-2', 'EU-1', 'EU-2')
)
->addFilter('accept-terms', new BoolFilter())
->addFilter('subscriptions', new IntArrayFilter());
// Invoke the filter container on the array to get the filtered result:
try {
// $post passed all of our filters.
$post = $ic($_POST);
} catch (\TypeError $ex) {
// Invalid data provided.
}
Ionizer doesn't just validate input, it returns the correct types. In this example `$post['dob']['year']` will be an `int`, `$post['dob']['accept-terms']` will be a `bool`, and `$post['dob']['subscriptions']` will be an `array` that only contains integers.
#### Why Does Ionizer Matter?
The trend in professional PHP software has been to move towards stricter typing and static analysis to detect bugs. Ionizer was created to apply the same logic to HTTP request parameters.
A very dumb, yet shockingly effective, way to fuzz PHP software is to add `[]` to HTTP request parameters before the `=` sign.
- /myscript.php?foo=bar
+ /myscript.php?foo[]=bar
This changes the value's type from a string to an array with a string input. The consequences will vary from project to project: Often, it's just an information leak (full path disclosure), but in some cases you can discover [NoSQL Injection vulnerabilities](https://nullsweep.com/a-nosql-injection-primer-with-mongo/).
Normally, when faced with an injection attack risk, security companies will tell developers to "sanitize their inputs" (which is [non sequitur for e.g. MongoDB](https://stackoverflow.com/a/5021598/)). This advice isn't nearly as helpful as [providing better tools and techniques](https://paragonie.com/blog/2015/05/preventing-sql-injection-in-php-applications-easy-and-definitive-guide). So we're not going to tell you to sanitize your inputs.
What we will tell you to do, if you're worried about NoSQL injection, is to ensure HTTP inputs are validated according to some contract. **Ionizer** is precisely the kind of tooling needed to ensure you never accidentally accept an `array` when a `string` was expected.
10. Easy-ECC
> GitHub: [paragonie/easy-ecc](https://github.com/paragonie/easy-ecc)
Our largest contributions to the security of the Internet are cryptography-related; and Easy-ECC is no exception to this rule.
Easy-ECC is our usability wrapper for [PHP-ECC](https://github.com/phpecc/phpecc): It uses the underlying algorithms in the most secure way possible.
<?php
use ParagonIE\EasyECC\EasyECC;
// Generate an instance; defaults to Curve25519
$ecc = new EasyECC();
// Get a keypair
$alice_sk = $ecc->generatePrivateKey();
$alice_pk = $alice_sk->getPublicKey();
// Signing a message (with PEM-formatted signatures):
$message = 'This is extremely simple to use correctly.';
$signature = $ecc->sign($message, $alice_sk);
if (!$ecc->verify($message, $alice_pk, $signature)) {
throw new Exception('Signature validation failed');
}
// Let's do a key exchange:
$bob_sk = $ecc->generatePrivateKey();
$bob_pk = $alice_sk->getPublicKey();
$alice_to_bob = $ecc->keyExchange($alice_sk, $bob_pk, true);
$bob_to_alice = $ecc->keyExchange($bob_sk, $alice_pk, false);
Although its focus is elliptic curve cryptography, Easy-ECC also provides an interface for performing symmetric encryption with an ECDH shared key.
<php
use ParagonIE\EasyECC\EasyECC;
use ParagonIE\EasyECC\Integration\Defuse;
use Mdanter\Ecc\Crypto\Key\{
PublicKeyInterface,
PrivateKeyInterface
};
/**
* @var EasyECC $ecc
* @var PrivateKeyInterface $secretKey
* @var PublicKeyInterface $publicKey
*/
// Let's load the integration (inject your EasyECC instance):
$defuse = new Defuse($ecc);
// You can seal/unseal messages (anonymous public-key encryption):
$superSecret = 'This is a secret message';
$sealed = $defuse->seal($superSecret, $publicKey);
$opened = $defuse->unseal($sealed, $secretKey);
The above sample code integrates with [defuse/php-encryption](https://github.com/defuse/php-encryption). This integration is included with Easy-ECC, but there's nothing prohibiting you from integrating with other symmetric encryption libraries.
#### Why Does Easy-ECC Matter?
While libsodium is a superior choice to Easy-ECC, some users will find themselves bogged down by compliance requirements ([CNSA Suite](https://apps.nsa.gov/iaarchive/programs/iad-initiatives/cnsa-suite.cfm), FIPS 140-2, etc.). Since libsodium doesn't cater to government standards for cryptography, it's a non-starter for any users that service governments.
Easy-ECC fills in the gap by providing an easy-to-use, hard-to-misuse API for elliptic curve cryptography for the NIST curves (P-256, P-384, P-521), the Bitcoin curve (secp256k1), and libsodium (included for completeness and ease-of-use, and the default choice).
Contributions and Alternatives to Internet Standards
1. PASETO: Platform Agnostic SEcurity TOkens
> Specification on GitHub: [paseto-standard/paseto-spec](https://github.com/paseto-standard/paseto-spec)
>
> PHP Implementation on GitHub: [paragonie/paseto](https://github.com/paragonie/paseto)
We announced PASETO in 2018 as a [secure alternative to JSON Web Tokens (JWT)](https://paragonie.com/blog/2018/03/paseto-platform-agnostic-security-tokens-is-secure-alternative-jose-standards-jwt-etc).
The main motivation for PASETO is that JWT is an [error-prone cryptographic design](https://paragonie.com/blog/2017/03/jwt-json-web-tokens-is-bad-standard-that-everyone-should-avoid) that gives library developers too much rope with which to hang themselves, and they in turn pass this risk onto their users. Consequently, there are frequently [alg=none JWT vulnerabilities](https://www.howmanydayssinceajwtalgnonevuln.com/) in real-world systems.
Instead of a free-form `"alg"` field like JWT, PASETO gives you only two knobs, which each have a finite set of possible values.
* Version:
* `v1`
* `v2`
* Purpose:
* `local`: Authenticated symmetric-key encryption
* `public`: Cleartext digital signatures
Each version hard-coded a suite of cryptographic protocols used for each purpose. There is no flexibility; you cannot use RSA with PKCS#1 v1.5 padding with any version of PASETO, even though `v1.public` does support RSA.
Last year, [we updated the cryptographic design](https://paragonie.com/blog/2021/08/paseto-is-even-more-secure-alternative-jose-standards-jwt-etc) to include new versions (`v3`, `v4`). The rationale for the new versions is documented [here](https://github.com/paseto-standard/paseto-spec/blob/master/docs/Rationale-V3-V4.md).
After reviewing feedback from other security experts, we took PASETO three steps further in [promoting misuse-resistance in PASETO library implementations](https://paragonie.com/blog/2021/09/promoting-misuse-resistance-in-paseto-libraries). Insecure cryptographic implementations are ultimately a consequence of insecure cryptographic standards. This also prompted us to expedite the deprecation of the original PASETO versions (`v1`, `v2`).
Today, that means the only four PASETO modes that should be used are: `v3.local`, `v3.public`, `v4.local`, and `v4.public`.
#### Why Does PASETO Matter?
The insecurity inherent to the JOSE family of standards runs deeper than the famous `{"alg": "none"}` header issue, or [the "HS256"/"RS256" algorithm confusion vulnerability](https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/#RSA-or-HMAC-).
Last year, we discovered that a popular PHP implementation of JWT, firebase/php-jwt, allowed users [to accidentally reintroduce the algorithm confusion security risk through the Key ID (`kid`) header](https://github.com/firebase/php-jwt/issues/351).
Every unnecessary security risk baked into the JOSE family of standards (which includes JWT) can be traced back to two causes:
1. Maximizing in-band negotiation (a.k.a. [cipher agility](https://paragonie.com/blog/2019/10/against-agility-in-cryptography-protocols)).
2. A failure to treat cryptographic keys as **both the raw key bytes and their configuration** rather than just the raw bytes
Conversely, PASETO simply doesn't have these security weaknesses. By design.
**Use PASETO, if you can.**
Unfortunately, the JOSE standards have proliferated into a million places (including the W3C and the FIDO Alliance). The only way to prevent the insecurity of JWT in, e.g. OpenID Connect, is to [standardize PASETO with the IETF](https://github.com/paseto-standard/paseto-rfc). This effort is a work in progress.
2. PASERK: Platform Agnostic SERialized Keys
> Specification on GitHub: [paseto-standard/paserk](https://github.com/paseto-standard/paserk)
>
> PHP Implementation on GitHub: [paragonie/paserk-php](https://github.com/paragonie/paserk-php)
PASETO was narrowly scoped to two use-cases:
1. Signed Claims from a third party (e.g. an identity provider): `vX.public`
2. Encrypted, tamper-proof bearer tokens: `vX.local`
It didn't include **asymmetric (public-key) encryption**, key-wrapping, password-based encryption, or even a canonical way to encode PASETO keys as strings.
Rather than pollute PASETO with unnecessary complexity, all of these value-adds were moved into [a separate design which we call a PASETO extension: PASERK](https://paragonie.com/blog/2021/08/introducing-paserk-first-paseto-extension-for-key-wrapping-and-serialization).
#### Why Does PASERK Matter?
PASERK adds features that cover advanced use-cases. For example:
> What if you, as an Identity Provider, want to include an asymmetric-encrypted bundle of information with your signed claim, such that only the intended Service Provider can decrypt the bundle?
PASETO didn't support this use-case, but you can accomplish it with PASERK:
1. Generate an ephemeral (one-time) symmetric key `ek`.
2. Use PASETO to create a `vX.local` token, using `ek`.
3. Use PASERK `kX.seal` to encrypt `ek` against your recipient's public key.
4. Create a `vX.public` signed token that contains both the `vX.local` token and `kX.seal` serialization.
The claims of the outermost (`vX.public`) might look something like this.
{
"wrapped-key": "k4.seal.OPFn-AE[...]RTVc9",
"payload": "v4.local.osy0wY[...]XIXVt",
"exp": "2055-01-01T00:00:00+00:00",
"iat": "2022-06-08T10:00:00-04:00",
"nbf": "2022-06-08T10:00:00-04:00"
}
A composition of PASERKs and PASETOs can be used to cover almost every real-world use-case for cryptographic tokens.
Open Source Beyond the PHP Ecosystem
1. Supply Chain Security for Software Updates
To be terse, we've been working on a scalable solution for supply-chain security for the open source community [since our company's inception in 2015](https://gossamer.tools/page/history). You can learn more about our [current initiative, Gossamer](https://paragonie.com/blog/2022/01/solving-open-source-supply-chain-security-for-php-ecosystem) in our previous blog post.
Once we have succeeded in securing the software supply chain for WordPress and Composer, we will be broadening our scope to include other languages.
To briefly compare with The Update Framework (TUF) and Sigstore:
* TUF doesn't ensure all users see the same updates. The missing property is [important for the security of the update infrastructure](https://defuse.ca/triangle-of-secure-code-delivery.htm).
* Sigstore doesn't include third-party attestations of software updates in the same cryptographic ledger. Gossamer offers this.
Gossamer is also more opinionated about cryptography algorithm choices than both alternatives. Gossamer currently supports Ed25519 with either SHA384 or BLAKE2b.
2. Other Language Implementations of Our PHP Libraries
Some of our PHP libraries above are already re-implemented in another language:
* JavaScript
* [CipherSweet](https://github.com/paragonie/ciphersweet-js)
* [Certainty](https://github.com/paragonie/certainty-js)
We plan to continue this effort, when appropriate, to ensure that developers always have access to the same features they've learned when they migrate to newer programming languages.
This is especially important for [CipherSweet](https://ciphersweet.paragonie.com), since searchable encryption is a surprisingly common problem that developers face, and the alternative solutions aren't great.
Where We're Headed in the Immediate Future
1. Key Discovery for Identity Providers
Key management is annoying and easy to get wrong, as [Ryan Sleevi notes in painstaking detail](https://docs.google.com/document/u/1/d/e/2PACX-1vQQ-FhNjW0ZhZVTnK1VG_87IBNZKBaJmweYZb1VBRdQCMAWXekqKfxdNl8wL6FWFDJ9pxXxpr66-GZp/pub).
> Current federation protocols, such as OpenID Connect (OIDC) and SAML, typically require some out-of-band configuration ceremony. This ceremony involves the Identity Provider (IdP) and Application Provider (AP) negotiating a set of authentication parameters, ranging from display parameters for end users, endpoints for services, or security parameters, such as SAML X.509 certificates or JSON Web Keysets (JWKs) used to authenticate OIDC JSON Web Tokens (JWTs). In some cases, such as SAML, these parameters must be periodically renegotiated, or the entire federation relationship may fail.
...
> Existing federation protocols, such as SAML, are cryptographically secure due to relying on an out-of-band ceremony for both parties to establish acceptable cryptographic parameters. These ceremonies are unspecified, but may be as simple as downloading a certificate from a web page, a form of Trust on First Use (TOFU), to in-person negotiations and exchanges. Once the ceremony has been performed, the relying party (the AP) can trust messages from the IdP, which will be signed with those negotiated keys.
In the future, we will have PASETO and PASERK in our Internet Standards and Gossamer protecting our open source supply chain.
Our plan is to develop a protocol atop Gossamer's foundation for managing and rotating the keys used by various Providers with PASETO and/or PASERK. This will greatly simplify the onboarding of Single Sign-On (and hopefully diminish the [SSO Wall of Shame](https://sso.tax)), thereby improving everybody's security.
2. Post-Quantum Cryptography
All of the cryptography we've worked with above this sentence is only secure until the day a Cryptography-Relevant Quantum Computer (CRQC) is created. Then the house of cards falls and we need **post-quantum** algorithms.
In the United States, NIST is currently working to [standardize algorithms that offer post-quantum secure cryptography](https://csrc.nist.gov/Projects/post-quantum-cryptography). When their portfolio is finalized, we will begin to migrate our projects to use hybrid modes (classical + post-quantum KEMs, classical + post-quantum signatures) where appropriate.
One concern with the currently published candidates is that they mostly fit interactive use-cases (i.e. encryption in transit) but do not deliberately target non-interactive use-cases (i.e. online asymmetric encryption, offline decryption).
This may not be a significant or practical problem from a security or operations perspective, but it does complicate the migration story; especially for a hypothetical `k5.seal` PASERK mode.
## Closing Thoughts
Everything we've described above is work we've done to make a more secure Internet, or plan to do in the immediate future.
If you'd like to join in our efforts, the best thing you can do is simply: Try using our software and designs the next time you encounter a problem they're intended to solve. And then, if you find these tools and techniques valuable, teach others how to use them.
Equally important: If the experience of any of our tools is poor, let us know how we can improve them. We're not perfect, but we always pursue excellence, so any feedback is valuable.