Skip to content

Instantly share code, notes, and snippets.

@smuuf
Last active May 30, 2025 23:22
Show Gist options
  • Save smuuf/987c28a89f06db85d42c4551a46193b5 to your computer and use it in GitHub Desktop.
Save smuuf/987c28a89f06db85d42c4551a46193b5 to your computer and use it in GitHub Desktop.
AES-256-GCM encryption/decryption class in PHP
<?php
declare(strict_types=1);
class AesGcmCrypto {
private const CIPHER = 'aes-256-gcm';
/** 96-bit IV is standard for GCM. */
private const IV_LENGTH = 12;
/** Tag with 128-bits. */
private const TAG_LENGTH = 16;
/**
* @param string $key 32-byte (256-bit) secret key.
*/
public function __construct(
private string $key,
) {
if (strlen($this->key) !== 32) {
throw new \InvalidArgumentException(
'Key must be 32 bytes (256 bits)',
);
}
}
/**
* Encrypts plaintext with optional AAD.
*
* @param ?string $aad Optional additional authenticated data.
* @return string Base64-encoded string containing IV + ciphertext + tag.
*/
public function encrypt(string $plaintext, string $aad = ''): string {
$iv = random_bytes(self::IV_LENGTH);
$tag = '';
$ciphertext = openssl_encrypt(
$plaintext,
self::CIPHER,
$this->key,
OPENSSL_RAW_DATA,
$iv,
$tag,
$aad,
self::TAG_LENGTH,
);
if ($ciphertext === false) {
throw new \RuntimeException('Encryption failed');
}
// Combine IV + ciphertext + tag for transmission.
return base64_encode($iv . $ciphertext . $tag);
}
/**
* Decrypts base64-encoded encrypted message with optional AAD.
*
* @param string $encoded Base64-encoded IV + ciphertext + tag.
* @param ?string $aad Optional additional authenticated data.
* @return string Decrypted plaintext.
*/
public function decrypt(string $encoded, string $aad = ''): string {
$data = base64_decode($encoded, true);
if (
$data === false
|| strlen($data) < (self::IV_LENGTH + self::TAG_LENGTH)
) {
throw new \InvalidArgumentException('Invalid encrypted input');
}
$iv = substr($data, 0, self::IV_LENGTH);
$tag = substr($data, -self::TAG_LENGTH);
$ciphertext = substr($data, self::IV_LENGTH, -self::TAG_LENGTH);
$plaintext = openssl_decrypt(
$ciphertext,
self::CIPHER,
$this->key,
OPENSSL_RAW_DATA,
$iv,
$tag,
$aad,
);
if ($plaintext === false) {
throw new \RuntimeException(
'Decryption failed or authentication failed',
);
}
return $plaintext;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment