Skip to content

Commit

Permalink
Initial commit - HPKE for PHP
Browse files Browse the repository at this point in the history
  • Loading branch information
paragonie-security committed Feb 4, 2025
0 parents commit 8176327
Show file tree
Hide file tree
Showing 46 changed files with 3,492 additions and 0 deletions.
30 changes: 30 additions & 0 deletions .github/workflows/psalm.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: Psalm

on: [push]

jobs:
psalm:
name: Psalm on PHP ${{ matrix.php-versions }}
runs-on: ${{ matrix.operating-system }}
strategy:
matrix:
operating-system: ['ubuntu-latest']
php-versions: ['8.3']
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-versions }}
tools: psalm:4
coverage: none

- name: Install Composer dependencies
uses: "ramsey/composer-install@v2"
with:
composer-options: --no-dev

- name: Static Analysis
run: psalm
83 changes: 83 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
name: Tests

on:
push:
pull_request:

jobs:
test-php8:
runs-on: ${{ matrix.operating-system }}
strategy:
matrix:
operating-system: ['ubuntu-22.04']
php-versions: ['8.2', '8.3', '8.4']
phpunit-versions: ['latest']
steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-versions }}
extensions: gmp
coverage: none

- name: Get composer cache directory
id: composer-cache
run: echo "::set-output name=dir::$(composer config cache-files-dir)"

- name: Cache dependencies
uses: actions/cache@v4
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: ${{ runner.os }}-composer-

- name: Install dependencies
run: composer install --prefer-dist

- name: Run tests
run: make phpunit-full-ci

coverage:
runs-on: ${{ matrix.operating-system }}
timeout-minutes: 30
strategy:
matrix:
operating-system: ['ubuntu-22.04']
php-versions: ['8.3']

steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-versions }}
extensions: gmp, xdebug, sodium

- name: Get composer cache directory
id: composer-cache
run: echo "::set-output name=dir::$(composer config cache-files-dir)"

- name: Cache dependencies
uses: actions/cache@v4
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: ${{ runner.os }}-composer-

- name: Install dependencies
run: composer install --prefer-dist

- name: Run tests
run: make phpunit-ci

- name: Upload coverage to Scrutinizer
run: make scrutinizer
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/.idea
/vendor
/composer.lock
/composer.phar
15 changes: 15 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
ISC License

Copyright (c) 2025, Paragon Initiative Enterprises <security at paragonie dot com>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Hybrid Public-Key Encryption (HPKE, RFC 9180) for PHP

[![Build Status](https://github.com/paragonie/hpke-php/actions/workflows/test.yml/badge.svg)](https://github.com/paragonie/hpke-php/actions)
[![Type Safety](https://github.com/paragonie/hpke-php/actions/workflows/psalm.yml/badge.svg)](https://github.com/paragonie/hpke-php/actions)

[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/paragonie/hpke-php/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/paragonie/hpke-php?branch=master)
[![Code Coverage](https://scrutinizer-ci.com/g/paragonie/hpke-php/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/hpke-php/hpke-php/?branch=master)

[![Latest Stable Version](https://poser.pugx.org/paragonie/hpke/v/stable)](https://packagist.org/packages/paragonie/hpke)
[![Total Downloads](https://poser.pugx.org/paragonie/hpke/downloads)](https://packagist.org/packages/paragonie/hpke)
[![Latest Unstable Version](https://poser.pugx.org/paragonie/hpke/v/unstable)](https://packagist.org/packages/paragonie/hpke)
[![License](https://poser.pugx.org/paragonie/hpke/license)](https://packagist.org/packages/paragonie/hpke)

## Installation

```terminal
composer require paragonie/hpke
```

### Usage

TODO

33 changes: 33 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"name": "paragonie/hpke",
"description": "Hybrid Public-Key Encryption (RFC 9180) for PHP",
"authors": [
{
"name": "Paragon Initiative Enterprises",
"email": "[email protected]",
"homepage": "https://paragonie.com"
}
],
"autoload": {
"psr-4": {
"ParagonIE\\HPKE\\": "src"
}
},
"autoload-dev": {
"psr-4": {
"ParagonIE\\HPKE\\Tests\\": "tests"
}
},
"require": {
"php": "^8.2",
"ext-gmp": "*",
"ext-openssl": "*",
"paragonie/sodium_compat": "^2",
"paragonie/easy-ecc": "^1",
"paragonie/ecc": "^2"
},
"require-dev": {
"phpunit/phpunit": "^10",
"vimeo/psalm": "^5"
}
}
26 changes: 26 additions & 0 deletions phpunit.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.5/phpunit.xsd"
bootstrap="vendor/autoload.php"
cacheDirectory=".phpunit.cache"
executionOrder="depends,defects"
requireCoverageMetadata="true"
beStrictAboutCoverageMetadata="true"
beStrictAboutOutputDuringTests="true"
displayDetailsOnPhpunitDeprecations="true"
failOnPhpunitDeprecation="true"
failOnRisky="true"
failOnWarning="true"
>
<testsuites>
<testsuite name="default">
<directory>tests</directory>
</testsuite>
</testsuites>

<source restrictDeprecations="true" restrictNotices="true" restrictWarnings="true">
<include>
<directory>src</directory>
</include>
</source>
</phpunit>
21 changes: 21 additions & 0 deletions psalm.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?xml version="1.0"?>
<psalm
errorLevel="6"
resolveFromConfigFile="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
findUnusedBaselineEntry="true"
findUnusedCode="true"
>
<projectFiles>
<directory name="src" />
<ignoreFiles>
<directory name="vendor" />
</ignoreFiles>
</projectFiles>
<issueHandlers>
<PossiblyUnusedMethod errorLevel="info" />
<UnusedClass errorLevel="info" />
</issueHandlers>
</psalm>
77 changes: 77 additions & 0 deletions src/AEAD/AES128GCM.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?php
declare(strict_types=1);
namespace ParagonIE\HPKE\AEAD;

use ParagonIE\HPKE\HPKEException;
use ParagonIE\HPKE\Interfaces\AEADInterface;
use ParagonIE\HPKE\Interfaces\SymmetricKeyInterface;
use ParagonIE\HPKE\SymmetricKey;

class AES128GCM implements AEADInterface
{
const AEAD_ID = "\x00\x01";

public function getAeadId(): string
{
return self::AEAD_ID;
}

public function keyLength(): int
{
return 16;
}

public function nonceLength(): int
{
return 12;
}

public function tagLength(): int
{
return 16;
}

public function encrypt(
#[\SensitiveParameter] SymmetricKeyInterface $key,
#[\SensitiveParameter] string $plaintext,
string $nonce,
string $aad = ''
): array {
$tag = '';
$ciphertext = openssl_encrypt(
$plaintext,
'aes-128-gcm',
$key->bytes,
OPENSSL_RAW_DATA | OPENSSL_NO_PADDING,
$nonce,
$tag,
$aad
);
return [$ciphertext, $tag];
}

/**
* @throws HPKEException
*/
public function decrypt(
#[\SensitiveParameter] SymmetricKeyInterface $key,
string $ciphertext,
string $tag,
string $nonce,
string $aad = ''
): string {
$result = openssl_decrypt(
$ciphertext,
'aes-128-gcm',
$key->bytes,
OPENSSL_RAW_DATA | OPENSSL_NO_PADDING,
$nonce,
$tag,
$aad
);
if (!is_string($result)) {
throw new HPKEException('Decryption error');
}
return $result;
}
}
77 changes: 77 additions & 0 deletions src/AEAD/AES256GCM.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?php
declare(strict_types=1);
namespace ParagonIE\HPKE\AEAD;

use ParagonIE\HPKE\HPKEException;
use ParagonIE\HPKE\Interfaces\AEADInterface;
use ParagonIE\HPKE\SymmetricKey;

class AES256GCM implements AEADInterface
{
const AEAD_ID = "\x00\x02";

public function getAeadId(): string
{
return self::AEAD_ID;
}

public function keyLength(): int
{
return 32;
}

public function nonceLength(): int
{
return 12;
}

public function tagLength(): int
{
return 16;
}


public function encrypt(
#[\SensitiveParameter] SymmetricKey $key,
#[\SensitiveParameter] string $plaintext,
string $nonce,
string $aad = ''
): array {
$tag = '';
$ciphertext = openssl_encrypt(
$plaintext,
'aes-256-gcm',
$key->bytes,
OPENSSL_RAW_DATA | OPENSSL_NO_PADDING,
$nonce,
$tag,
$aad
);
return [$ciphertext, $tag];
}

/**
* @throws HPKEException
*/
public function decrypt(
#[\SensitiveParameter] SymmetricKey $key,
string $ciphertext,
string $tag,
string $nonce,
string $aad = ''
): string {
$result = openssl_decrypt(
$ciphertext,
'aes-256-gcm',
$key->bytes,
OPENSSL_RAW_DATA | OPENSSL_NO_PADDING,
$nonce,
$tag,
$aad
);
if (!is_string($result)) {
throw new HPKEException('Decryption error');
}
return $result;
}
}
Loading

0 comments on commit 8176327

Please sign in to comment.