PHPackages                             filiprigoir/pswkey - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. filiprigoir/pswkey

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

filiprigoir/pswkey
==================

A deterministic base converter using shuffled alphabets derived from salt and optional pepper, with streamkey and one-time-pad support.

1.0.0(2w ago)01MITPHPPHP ^8.2CI passing

Since May 20Pushed 1w agoCompare

[ Source](https://github.com/filiprigoir/PswKey-php)[ Packagist](https://packagist.org/packages/filiprigoir/pswkey)[ RSS](/packages/filiprigoir-pswkey/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependencies (1)Versions (2)Used By (0)

PswKey-php
==========

[](#pswkey-php)

The conversion layer operates on derived shuffled alphabets.

How to install
--------------

[](#how-to-install)

```
composer require filiprigoir/pswkey
```

---

Core idea
---------

[](#core-idea)

Alphabet layouts are automatically derived from a seedphrase (salt) and optional keyphrase (pepper), creating isolated conversion spaces between systems, services and/or users.

This affects compatibility between instances, since alphabet layouts differ per setup.

All inputs are validated before decoding against their base alphabet. If this validation fails, decoding could be rejected by:

- early validation (quick check)
- deep validation (during the process)

For BaseX to Base10, Base100 and Base256 conversions, decoding additionally requires extra normalization into the canonical format.

In these cases, decoding follows a deterministic rejection model:

- invalid symbols are rejected
- incompatible alphabets are rejected
- decoding does not produce valid canonical output when the setup does not match

→ See: [Normalization](/src/Core/Documentation/Pipline/Normalization.md)

---

Design philosophy
-----------------

[](#design-philosophy)

The repository separates:

- key derivation
- stream management
- data normalization before conversion
- transport representation

into independent layers that can be combined when needed.

---

This repository consists of three integrated components:

- `KeyStream()` — standalone stream and derived key provider
- `PswKey()` — deterministic base conversion driven by `KeyStream()`
- `OneTimePad()` — XOR and digit-based OTP for intermediate steps powered by `KeyStream()`

Components:

### KeyStream()

[](#keystream)

Handles stream and derived key generation.

Keys are exposed through callbacks only and are cleared as quickly as possible after use.

Built on Libsodium and intended for encryption-related workflows.

### PswKey()

[](#pswkey)

Provides deterministic base conversion using shuffled alphabets driven by KeyStream().

Supports:

- system-defined alphabets (always shuffled)
- custom-defined alphabets (with optional alphabet shuffling)

PswKey() uses KeyStream() through dependency injection and is intended for deterministic transport representation, not encryption.

### OneTimePad()

[](#onetimepad)

Provides XOR and digit-based OTP operations using derived stream keys.

OneTimePad() also depends on KeyStream() and can be used as a preprocessing step before deterministic transport conversion.

---

Inputs PswKey
-------------

[](#inputs-pswkey)

Base10, Base100 and Base256 represent canonical input formats.

→ See: [Input/output encoding](/src/Core/Documentation/Format/Encoding.md)

These formats are used as the source or target for conversion.

Base32, Base58, Base62 and Base64 represent encoded symbol formats used during decoding.

A typical flow is:

```
->from(100)->to(N)
->from(N)->to(100)
```

→ See: [system-defined](/src/Core/Documentation/Format/System.md)

Note: when used for security reason, do not provide structured or human-readable input. Use high-entropy data or an intermediate transformation step instead.

### Custom-defined

[](#custom-defined)

Custom-defined conversion follows a simple directional model:

- `customTo(x, y, z)` is used for encode
- `customFrom(x, y, z)` is used for decode

A typical flow is:

```
->from(100)->customTo($alfabet, X, true)
->customFrom($alfabet, X, true)->to(100)
```

→ See: [Custom-defined](/src/Core/Documentation/Format/Custom.md)

---

Usage
-----

[](#usage)

### Common Use

[](#common-use)

Convert 100,000 random bytes into a deterministic Base32 representation and decode it back to the original byte sequence.

```
use PswKey\Service\KeyStream;
use PswKey\Service\PswKey;

//Time-based key
$date = new DateTime();
$key = \strtotime($date->format('Y-m-d H:i:s')) . $date->format('u');

//Derived stream provider
$keyStream = new KeyStream("Service=README.md : user=536984 : alias=VisalStudio", $key);

//Deterministic converter
$pswkey = new PswKey($keyStream);

//Generate input bytes
$randomBytes = random_bytes(100_000);

//Conversion to encode
$encode = $pswkey->from(256)->to(32)->convert($randomBytes);

//Encode status
$status = $pswkey->status();

if($status->valid) { //$encode !== null => is also possible

    //Encoded output must differ from the original input
    if($encode !== $randomBytes) {
        echo "RandomBytes is not equal as Encode \n";
    }

    //Conversion to decode
    $decode = $pswkey->from(32)->to(256)->convert($encode);

    //Decode status
    $newStatus = $pswkey->status();
    if($newStatus->valid) {

        //Decoded output must match the original input
        if($decode === $randomBytes) {
            echo "Decode is equal as RandomBytes \n";
        }
    }
    else {
        //Public/client-safe message
        echo $status->clientMessage;
    }
}
else {
    //Internal/dev-only message
    echo $status->internalMessage;
}
```

---

One-time-pad digit stream conversion with reverse flow.

```
use PswKey\Service\KeyStream;
use PswKey\Service\OneTimePad;

//Digit number
$originalDigits = "0931024538975689521014785";

// Example workflow (a possible path):
// - Base100/Base256 → Base10
// - OneTimePad digit transformation
// - Base10 → BaseX conversion
// - Reverse flow for decoding

//Time-based key
$date = new DateTime();
$key = \strtotime($date->format('Y-m-d H:i:s')) . $date->format('u');

//Derived stream provider
$keyStream = new KeyStream("Service=README.md : user=5236947 : alias=VisalStudio", $key);

//OTP instance
$oneTimePad = new OneTimePad($keyStream);

//Using any numeric identifier and 8-byte derivation context
$encode = $oneTimePad->digit($originalDigits, 5236947, "MyDigits");

if($encode !== $originalDigits) {
    echo "Encode is not equal as originalDigits \n";
}

$status = $oneTimePad->status();
if($status->valid) {

    //Decode into orginal digits
    $decode = $oneTimePad->digit($encode, 5236947, "MyDigits");

    if($decode === $originalDigits) {
        echo "Decode is equal as originalDigits \n";
    }
}
else {
    echo $status->internalMessage;
}
```

---

### Advanced Use Case

[](#advanced-use-case)

Create a derived transport key from a user password and store a secure password hash in the database.

```
use PswKey\Service\KeyStream;
use PswKey\Service\PswKey;
use PswKey\Util\Secure\Memezero;

try {
    //User credentials
    $email = "info@pswkey.com";
    $password = "My_PswKeyµ2025!";

    //Derived stream provider
    $keyStream = new KeyStream(
        "Service=README.md | emailadress={$email}" //Seedphrase can be anything related to your service
    );

    //Attach password as custom key
    $keyStream->setCustomKey($password);

    //Generated outputs
    $transportkey = "";
    $passwordHash = "";
    $keyStream->byteStream(
        function($entropyPassword) use (&$transportkey, &$passwordHash, &$keyStream) {

            $pswKey = new PswKey($keyStream);

            //Derived password => transport-safe Base32 representation
            $transportkey = $pswKey->from(256)->to(32)->convert($entropyPassword);

            //Derived password => password hash for database storage
            $passwordHash = password_hash($entropyPassword, PASSWORD_DEFAULT);

            unset($pswKey);
        },
        64, //Entropy password length
        "MySecret" //Your service-specific derivation context (must be 8 bytes)
        );

        echo $transportkey . "\n ";
        echo $passwordHash . "\n ";

        //To validate:
        //regenerate the "derived password" from the incoming password
        //and compare it with the stored database hash

        //Example password hash:
        //$2y$10$WiLT89W8P60h9mZgqU3TweFT9EjFB57iv05kzvMsd1hEJ6R53vBJe

        //Optional "transport key" representation:
        //(cookies, transport identifiers, login flows, etc.)

        //Example transport key:
        //mdvWkllAVlVULqMLBsGWL2BVm4bkz14UgMgUAmUBBZdG7m4kBVGLg4LWRBtsq1Aes4yegyL1WzUggq4lsMbRVveMq
        //MGRgAlKgm2gBBL7sMzWh2Mqnkdk1tUsl4GG
}
finally {
    //Clear sensitive data
    Memezero::overwriteString($password);
    unset($keyStream);
}
```

Validate a transport key by decoding it into its derived password representation and comparing it against the stored password hash.

```
use PswKey\Service\KeyStream;
use PswKey\Service\PswKey;
use PswKey\Util\Secure\Memezero;

try {
    //User credentials
    $email = "info@pswkey.com";

    //Incoming transport key
    $transportKey = "gUi0zrccwPdLL88IvwUwB2eMO2UtP0UvvNcITTgOv8cNl0W0o8lgPwQtoNTTlTgAA8l0P2vBl2WtAU"
        . "twANtOfIpoovpyO2UfOlUTWMUHBNvicA2OfvzfO8UANeoz";

    //Derived stream provider
    $keyStream = new KeyStream("Service=README.md | emailadress={$email}");

    $pswKey = new PswKey($keyStream);

    //Decoded transport key into derived password bytes
    $entropyPsw = $pswKey->from(32)->to(256)->convert($transportKey);

     //Validate transport key conversion
    if($entropyPsw !== null) {

        //Retrieve stored password hash only after successful transport-key validation
        $dbHashed = "\$2y\$10\$RGbITslA7qBNeiJ8/Zk3A.t7sOXpOLHqTgqT5.mtSmrGpIL9c75jG";

        //Compare derived password against stored hash
        if (password_verify($entropyPsw, $dbHashed)) {
            echo 'Password is valid!';
        } else {
            echo 'Invalid password.';
        }
    }
}
finally {
    //Clear sensitive data
    Memezero::overwriteString($entropyPsw);
    unset($keyStream, $pswKey);
}
```

---

Core System Documentation
-------------------------

[](#core-system-documentation)

→ complete: [Technical documentation](/src/Core/Documentation)

###  Health Score

40

—

FairBetter than 86% of packages

Maintenance97

Actively maintained with recent releases

Popularity2

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity46

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

20d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/35e229330858515b923586aff8c5dcf41cd23b187f53631307ae2b2e4865a259?d=identicon)[filiprigoir](/maintainers/filiprigoir)

---

Top Contributors

[![filiprigoir](https://avatars.githubusercontent.com/u/68118471?v=4)](https://github.com/filiprigoir "filiprigoir (46 commits)")

---

Tags

phpencodingcharsetconverterdecodingbasedeterministicsaltshufflederivationtransport keypepperone-time-padstream keyderived key

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/filiprigoir-pswkey/health.svg)

```
[![Health](https://phpackages.com/badges/filiprigoir-pswkey/health.svg)](https://phpackages.com/packages/filiprigoir-pswkey)
```

###  Alternatives

[tomloprod/radiance

A deterministic mesh gradient avatar generator for PHP.

1397.5k](/packages/tomloprod-radiance)[delight-im/base-convert

Conversion of arbitrarily large numbers between any two bases or alphabets

171.2k](/packages/delight-im-base-convert)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
