A Practical Introduction to encryption in PHP

TYPO3 Developer Days 2022

Frank Berger

A bit about me

  • Frank Berger
  • Head of Engineering at code711.de, a label of B-Factor GmbH, Sudhaus7 and 12bis3.de
  • Started as an Unix Systemadministrator who also develops in 1996
  • Does TYPO3 since 2005

What this talk is not about

How encryption algorithms (like RSA) work

or how hashing algorithms work

or which one is the best

or differences between encryption methods

We just accept that there are hashing algorithms and encryption methods that are proofen to work and we're going to use

What this talk is about

How to start encrypting stuff in PHP

using what PHP gives us

with asymetric encryption (Private and Public Keys)

to give a practical primer how to handle encrypted data

A primer in asynchronous encryption

or Public Key encryption

Public key encrypts

Private Key decrypts

The private key is only known to you, the public part can be printed on a billboard

this essentially is what SSH, SSL, TLS, PGP and many more are doing

2 Major Crypting Libraries native in PHP

(there are more written in PHP itself)

Openssl

Sodium (libsodium)

We need to choose a hashing algorithm

Dozens of encryption algorithms

Which one do we choose?

We're going to use Openssl and use AES256 for now (and SHA256 for hashing)

use
openssl_get_cipher_methods()
to find out which algorithms are available

creating a key (in openssl)


						$keyResource = openssl_pkey_new([
							"digest_alg" => "sha256",
							"private_key_bits" => 4096,
							"private_key_type" => OPENSSL_KEYTYPE_RSA,
						]);
						openssl_pkey_export($keyResource, $privatekey);
						$publickey = openssl_pkey_get_details($keyResource)["key"];
						openssl_free_key($keyResource);
					

to secure the private key with a password export it with one

openssl_pkey_export($keyResource, $privatekey,'secretpassword');

How does such a key look like


-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAvffa64mFV3UKf6G6OLlQ
olZxQZsdCuRtEVFFqXCbtOKSFWsfXuZ+hYqoWFUrTGdApKV5hdGm9aXbcSzs3d8J
PjGF7uZUoiQvoasdCi/9Y16W1nxYeLXZOjLlHxLTzWEee2XGketBjBEpYQ8jSyaH
LeCMHc/cxgfCfJNR6HD/ZzQpt65Ace+0LpkwxZ6Y0Sp3cnO0vdIVK9Fzpgm7Dz9W
FAhq7e+43CyLAT+vAl9LUN3BmSnDD2bbeQ40BnGJ0FlQKTxLjt0DkMswSQDpyyDT
H5Ni/Sq6hh5hXLuPmwGkY1VnW/UE8mHYuDNACtMyHQVBhv1oz7r8dObajm1f71lW
JAMVU95yHfKKtx2cUXr1iah9L8Cxdlh9pPBUWYwEOHBPvsP48IPPpjSdkLPOEqrp
gXs+YREjEeMOZGWIZ+9+0hno8w7nfCnExQtMpA1lkvOpaBKf4J22T+rFeHOyESB8
OwfqhaMzPGbmkAKw8IcKwMB4ba4n+ZQbepK80XWBH5valh6TBH5YYT6zDLgUXgIf
UCiH/toh50xPpJmXf3it3BrsicNnFSpcSLKlFnVVy6NoCa/rY4NbQGbxiNMWrOfT
Cl9i8APoC38mxXOq3ezjJplSnymX9lJDuvGN5mURM7cwFDtylhp5V4+pZZ+eayRF
TADumyJqEo/pxKPqLkkAiJECAwEAAQ==
-----END PUBLIC KEY-----

					

The private key has a different header and footer and is much longer

Simple encryption / decryption


						$iv  = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes256'));
						$pub = openssl_pkey_get_public( $publickey);
						openssl_seal('hallo 123',$sealed,$enckey,[$pub],'aes256',$iv);
						openssl_free_key($pub);

						$private = openssl_pkey_get_private( $privatekey);
						openssl_open($sealed,$opened,$enckey[0],$private,'aes256',$iv);
						openssl_free_key($private);
						echo $opened,"\n";
					

Problem: Only one Person can access the data

Think different actors who need to access a dataset

Solution: we could encrypt the msg multiple times

Problem: large data gets even larger

Problem: multiple recipient channels

Solution

openssl_seal and openssl_open

multiple public keys can be provided

Workflow - Step 1

Workflow - Step 2

						
$public_keys = [
	$pubBob, // openssl_pkey_get_public( $Bob_publickey);
	$pubAlice, // openssl_pkey_get_public( $Alice_publickey);
	$pubPeter // openssl_pkey_get_public( $Peter_publickey);
];

$iv  = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes256'));
openssl_seal(
	'my secret message',
	$sealed,
	$enckey,
	$public_keys,
	'aes256', $iv
);
						
					
						
$private = openssl_pkey_get_private( $Peter_privatekey);
openssl_open(
	$sealed,
	$opened,
	$enckey[2], // we know Peters' was the third key
	$private,
	'aes256',$iv
);
openssl_free_key($private);
echo $opened,"\n"; // my secret message

						
					

Things we need to keep track of:

  1. $sealed - the sealed data
  2. $iv - initialization vector (if the algorithm uses it)
  3. $enckey - the random key that has been created
  4. the encryption method
  5. Which public key belongs to which encrypted key

Lets encrypt

						
openssl_seal(
	'another secret message',
	$sealed,
	$enckey,
	$public_keys, $method, $iv
);

$finalEncKeys = [];
foreach($public_keys as $idx=>$key) {
	$checksumm = sha1(openssl_pkey_get_details($pub)['key']);
	$finalEncKeys[$checksumm]=$enckey[$idx];
}

// $envelope can be stored
$envelope  = base64_encode(serialize([
	$method, $iv, $finalEncKeys, $sealed
]));

						
					

Peter wants to read

						
$private = openssl_pkey_get_private( $peters_privatekey);
$public = openssl_pkey_get_details($private)["key"];

[$method,$iv,$enckey,$sealed] = unserialize(base64_decode($envelope));
openssl_open(
	$sealed,
	$opened,
	$enckey[sha1($public)],
	$private,
	$method, $iv
);
echo $opened;
						
					

So far so good

This was the easy part..

Keymanagement!

Ideas how to store Keys

Create Keys for every User

Secure Private Keys

Secure the Private Key with the users passwort

Summary

This is not the ultimative guide

some encryption is better than no encryption

beware of false Security

In the works

guard7

a TYPO3 extension and framework

Thank you, questions and resources

Twitter: @FoppelFB

https://code711.de/

fberger@code711.de

fberger@sudhaus7.de