Public Key Cryptography
Public-Key Cryptography is the common name for Asymmetric-Key Algorithms. Where symmetric-key algorithms used a single key for encrypting and decrypting, asymmetric-key algorithms use a pair of keys.
The simplest illustration is to imagine a box which requires two keys to lock it and which requires two keys to unlock it. Neither can unlock the box without the other person’s key. A real-world example of this is bank safety deposit box which require a customer’s key and also a bank employee’s key.
When encrypting data for communication, it is not practical for both the sender and receiver to be present when a message needs to be encrypted or decrypted. A more complex strategy allows the sender and the receiver to each have two keys, one for encrypting and one for decrypting. A software key generation program creates two different keys which are linked together mathematically. One key can be used to lock the data and the other key will unlock it.
The reason it is called “Public-Key Cryptography” is because each person will share one of their keys widely (“public key”) so that anyone can use it. Then they will keep the other key private (“private key”) so that only they can use it.
Alice wants to send an encrypted message to Bob.
- Alice writes a plain text message to Bob
- Alice encrypts the plain text message with Bob’s public key
Then Alice sends the encrypted message to Bob.
- Bob decrypts the encrypted message with his private key
- Bob reads the message
Digital Signatures
Key pairs can also be used to create digital signatures. The message text is put into an algorithm along with the sender’s private key. The result is a digital signature which can be sent along with the message. The recipient can use another algorithm on the message data, the signature, and the sender’s public key to verify: 1) message integrity: the data has not been changed, 2) sender authenticity: that the signature was created using the sender’s private key.
Messages can be encrypted without adding a signature and unencrypted data can be digitally signed. However, typically in public-key cryptography, both are used together. This provides message privacy, integrity, and authenticity.
Alice wants to send an encrypted message to Bob.
- Alice writes a plain text message to Bob
- Alice encrypts the plain text message with Bob’s public key
- Alice creates a digital signature for the encrypted message with her private key
Then Alice sends the encrypted message and signature to Bob.
- Bob verifies the digital signature using the encrypted message and Alice’s public key
- Bob decrypts the encrypted message with his private key
- Bob reads the plain text message
In our example, Bob will know that the message he received is truly from Alice because only Alice should possess the private key which he unlocked with her public key. (This is only true if Bob can trust that the public key he downloaded is really Alice’s public key.)
Public-Key Cryptography Pros and Cons
The primary benefit is that all of the information can be communicated over an open network. There does not need to be a pre-arrangement or a secret channel for the sender to tell the recipient the password to use for decrypting a message. This is ideal for use on the Internet. This is in contrast to symmetric key algorithms which suffer from a “key distribution problem”.
In addition, digital signatures confirm the integrity and authenticity of a message.
Asymmetric algorithms take a relatively long time compared to symmetric algorithms, and they are limited in the amount of data which can be encrypted (for a 2048-bit RSA key with OAEP-SHA1 padding it is about 214 bytes; with the older PKCS#1 v1.5 padding it is 245 bytes). For this reason, public-key cryptography is often used to send small messages, such as to share a symmetric encryption key. Then larger data can be exchanged using faster symmetric key algorithms, using a key which the sender and receiver both share.
Following NIST SP 800-57 Part 1 Rev. 5, Table 2, a 2048-bit RSA key provides roughly 112 bits of security and remains acceptable today, but new keys expected to protect data past 2030 should use at least 3072-bit RSA (128-bit security) — NIST plans to deprecate 112-bit-strength algorithms at the end of 2030 in SP 800-131A Rev. 3 (draft).
Public-Key Cryptography is widely used as part of secure technologies for communicating online, including TLS, S/MIME, and PGP. The exact handshake differs by protocol: PGP and S/MIME encrypt a freshly generated symmetric session key with the recipient’s public key, while TLS 1.3 (RFC 8446, §2) performs an ephemeral Diffie-Hellman exchange to derive a shared session secret and uses the certificate’s keys only to authenticate the handshake — the server signs the handshake transcript with its certificate’s private key, and the client verifies that signature against the public key in the certificate to prove the server’s identity. In every case the slow public-key step is reserved for establishing the session, and the bulk of the conversation is then encrypted with much faster Symmetric Key Algorithms.
Public-Key Cryptography in PHP
Generate keys using PHP’s OpenSSL functions
<?php
// Create a private/public key pair
$config = array(
"digest_alg" => "sha512",
"private_key_bits" => 2048,
"private_key_type" => OPENSSL_KEYTYPE_RSA,
);
$resource = openssl_pkey_new($config);
// Extract private key from the pair
openssl_pkey_export($resource, $private_key);
// Extract public key from the pair
$key_details = openssl_pkey_get_details($resource);
$public_key = $key_details["key"];
$keys = array('private' => $private_key, 'public' => $public_key);
echo $keys['public'];
echo $keys['private'];
?>
Use PHP’s OpenSSL functions to encrypt using the public key. Pass OPENSSL_PKCS1_OAEP_PADDING explicitly — the default OPENSSL_PKCS1_PADDING is PKCS#1 v1.5 padding, which has been vulnerable to Bleichenbacher-style chosen-ciphertext attacks since 1998 and should not be used for new code.
<?php
$plaintext = "I have a secret to tell you.";
openssl_public_encrypt($plaintext, $encrypted, $keys['public'], OPENSSL_PKCS1_OAEP_PADDING);
// Use base64_encode to make contents viewable/sharable
$message = base64_encode($encrypted);
echo $message;
?>
Use PHP’s OpenSSL functions to decrypt using the private key. The padding constant must match the one used during encryption.
<?php
// Decode from base64 to get raw data
$ciphertext = base64_decode($message);
openssl_private_decrypt($ciphertext, $decrypted, $keys['private'], OPENSSL_PKCS1_OAEP_PADDING);
echo $decrypted;
?>
Sign and verify data with private keys in PHP
Use PHP’s OpenSSL functions to sign the data with the private key. Pass OPENSSL_ALGO_SHA256 explicitly — the function’s documented default is OPENSSL_ALGO_SHA1, which is broken as a signature hash (SHA-1 collisions have been demonstrated since 2017) and is also disabled by default in OpenSSL 3.x.
<?php
$data = "I can verify this message is from me.";
openssl_sign($data, $raw_signature, $keys['private'], OPENSSL_ALGO_SHA256);
// Use base64_encode to make contents viewable/sharable
$signature = base64_encode($raw_signature);
?>
Use PHP’s OpenSSL functions to verify using the public key. The signature algorithm must match the one used during signing.
<?php
$raw_signature = base64_decode($signature);
$result = openssl_verify($data, $raw_signature, $keys['public'], OPENSSL_ALGO_SHA256);
echo $result;
// returns 1 if data and signature match
$modified_data = $data . "extra content";
$result = openssl_verify($modified_data, $raw_signature, $keys['public'], OPENSSL_ALGO_SHA256);
echo $result;
// returns 0 if data and signature do not match
?>