Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Nexus Encryption v2 #8

Draft
wants to merge 10 commits into
base: 1.x
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"replace": {
"nexusphp/clock": "self.version",
"nexusphp/collection": "self.version",
"nexusphp/encryption": "self.version",
"nexusphp/option": "self.version",
"nexusphp/password": "self.version",
"nexusphp/phpstan-nexus": "self.version",
Expand Down
7 changes: 5 additions & 2 deletions infection.json5
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,6 @@
"LogicalOrAllSubExprNegation": true,
"LogicalOrNegation": true,
"LogicalOrSingleSubExprNegation": true,
"MBString": true,
"MatchArmRemoval": true,
"MethodCallRemoval": true,
"MinusEqual": true,
Expand Down Expand Up @@ -143,7 +142,11 @@
"SpreadRemoval": true,
"Ternary": true,
"This": true,
"Throw_": true,
"Throw_": {
"ignore": [
"Nexus\\Encryption\\Key::__unserialize"
]
},
"TrueValue": {
"ignore": [
"Nexus\\Collection\\Collection::generateDiffHashTable"
Expand Down
36 changes: 36 additions & 0 deletions src/Nexus/Encryption/BinaryStr.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

declare(strict_types=1);

/**
* This file is part of the Nexus framework.
*
* (c) John Paul E. Balandan, CPA <[email protected]>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/

namespace Nexus\Encryption;

/**
* Binary string operations wrapping on related `mb_*` functions.
*/
final class BinaryStr
{
/**
* Get the length of a binary string.
*/
public static function strlen(#[\SensitiveParameter] string $string): int
{
return mb_strlen($string, '8bit');
}

/**
* Get a substring of a binary string.
*/
public static function substr(#[\SensitiveParameter] string $string, int $start, ?int $length = null): string
{
return mb_substr($string, $start, $length, '8bit');
}
}
57 changes: 57 additions & 0 deletions src/Nexus/Encryption/Cryptex.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

declare(strict_types=1);

/**
* This file is part of the Nexus framework.
*
* (c) John Paul E. Balandan, CPA <[email protected]>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/

namespace Nexus\Encryption;

use Nexus\Encryption\Exception\InvalidEncodingVariantException;

final readonly class Cryptex
{
/**
* Version tag in the form 'v' + major + minor + patch.
*
* Note: Increment only the major and minor versions when making updates.
*/
public const string HEADER_VERSION = "\x76\x01\x00\x00";

/**
* Length of the version header.
*/
public const int HEADER_VERSION_SIZE = 4;

public const int ENCODE_NONE = 0;
public const int ENCODE_BASE64_ORIGINAL = 1;
public const int ENCODE_BASE64_ORIGINAL_NO_PADDING = 2;
public const int ENCODE_BASE64_URL_SAFE = 3;
public const int ENCODE_BASE64_URL_SAFE_NO_PADDING = 4;
public const int ENCODE_HEX = 5;

/**
* Gets the encoder. If `self::ENCODE_NONE` is chosen, any subsequent encode
* and decode operations will just return the strings as-is.
*
* @throws InvalidEncodingVariantException
*/
public static function encoder(int $variant = self::ENCODE_HEX): Encoding\EncoderInterface
{
return match ($variant) {
self::ENCODE_NONE => new Encoding\NullEncoder(),
self::ENCODE_BASE64_ORIGINAL => new Encoding\Base64OriginalEncoder(),
self::ENCODE_BASE64_ORIGINAL_NO_PADDING => new Encoding\Base64OriginalNoPaddingEncoder(),
self::ENCODE_BASE64_URL_SAFE => new Encoding\Base64UrlSafeEncoder(),
self::ENCODE_BASE64_URL_SAFE_NO_PADDING => new Encoding\Base64UrlSafeNoPaddingEncoder(),
self::ENCODE_HEX => new Encoding\HexEncoder(),
default => throw new InvalidEncodingVariantException(),
};
}
}
32 changes: 32 additions & 0 deletions src/Nexus/Encryption/Encoding/AbstractBase64Encoder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

declare(strict_types=1);

/**
* This file is part of the Nexus framework.
*
* (c) John Paul E. Balandan, CPA <[email protected]>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/

namespace Nexus\Encryption\Encoding;

abstract class AbstractBase64Encoder implements EncoderInterface
{
public function encode(#[\SensitiveParameter] string $binaryString): string
{
return sodium_bin2base64($binaryString, $this->getBase64Variant());
}

public function decode(#[\SensitiveParameter] string $encodedString, string $ignore = ''): string
{
return sodium_base642bin($encodedString, $this->getBase64Variant(), $ignore);
}

/**
* Get the variant of Base64 encoding to use.
*/
abstract protected function getBase64Variant(): int;
}
25 changes: 25 additions & 0 deletions src/Nexus/Encryption/Encoding/Base64OriginalEncoder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

declare(strict_types=1);

/**
* This file is part of the Nexus framework.
*
* (c) John Paul E. Balandan, CPA <[email protected]>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/

namespace Nexus\Encryption\Encoding;

/**
* Standard (A-Za-z0-9/\+) Base64 encoder.
*/
final class Base64OriginalEncoder extends AbstractBase64Encoder
{
protected function getBase64Variant(): int
{
return SODIUM_BASE64_VARIANT_ORIGINAL;
}
}
25 changes: 25 additions & 0 deletions src/Nexus/Encryption/Encoding/Base64OriginalNoPaddingEncoder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

declare(strict_types=1);

/**
* This file is part of the Nexus framework.
*
* (c) John Paul E. Balandan, CPA <[email protected]>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/

namespace Nexus\Encryption\Encoding;

/**
* Standard (A-Za-z0-9/\+) Base64 encoder without `=` padding characters.
*/
final class Base64OriginalNoPaddingEncoder extends AbstractBase64Encoder
{
protected function getBase64Variant(): int
{
return SODIUM_BASE64_VARIANT_ORIGINAL_NO_PADDING;
}
}
25 changes: 25 additions & 0 deletions src/Nexus/Encryption/Encoding/Base64UrlSafeEncoder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

declare(strict_types=1);

/**
* This file is part of the Nexus framework.
*
* (c) John Paul E. Balandan, CPA <[email protected]>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/

namespace Nexus\Encryption\Encoding;

/**
* URL-safe (A-Za-z0-9\-_) Base64 encoder.
*/
final class Base64UrlSafeEncoder extends AbstractBase64Encoder
{
protected function getBase64Variant(): int
{
return SODIUM_BASE64_VARIANT_URLSAFE;
}
}
25 changes: 25 additions & 0 deletions src/Nexus/Encryption/Encoding/Base64UrlSafeNoPaddingEncoder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

declare(strict_types=1);

/**
* This file is part of the Nexus framework.
*
* (c) John Paul E. Balandan, CPA <[email protected]>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/

namespace Nexus\Encryption\Encoding;

/**
* URL-safe (A-Za-z0-9\-_) Base64 encoder, without `=` padding characters.
*/
final class Base64UrlSafeNoPaddingEncoder extends AbstractBase64Encoder
{
protected function getBase64Variant(): int
{
return SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING;
}
}
29 changes: 29 additions & 0 deletions src/Nexus/Encryption/Encoding/EncoderInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

declare(strict_types=1);

/**
* This file is part of the Nexus framework.
*
* (c) John Paul E. Balandan, CPA <[email protected]>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/

namespace Nexus\Encryption\Encoding;

interface EncoderInterface
{
/**
* Encodes a binary string into a readable format without cache-timing attacks.
*/
public function encode(#[\SensitiveParameter] string $binaryString): string;

/**
* Converts an encoded string back to its original binary format without cache-timing attacks.
*
* @param string $ignore Characters to ignore when decoding (e.g. whitespace characters)
*/
public function decode(#[\SensitiveParameter] string $encodedString, string $ignore = ''): string;
}
30 changes: 30 additions & 0 deletions src/Nexus/Encryption/Encoding/HexEncoder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

declare(strict_types=1);

/**
* This file is part of the Nexus framework.
*
* (c) John Paul E. Balandan, CPA <[email protected]>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/

namespace Nexus\Encryption\Encoding;

/**
* Encode/decode binary data to/from hexadecimal strings without any side-channel attacks.
*/
final class HexEncoder implements EncoderInterface
{
public function encode(#[\SensitiveParameter] string $binaryString): string
{
return sodium_bin2hex($binaryString);
}

public function decode(#[\SensitiveParameter] string $encodedString, string $ignore = ''): string
{
return sodium_hex2bin($encodedString, $ignore);
}
}
27 changes: 27 additions & 0 deletions src/Nexus/Encryption/Encoding/NullEncoder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

declare(strict_types=1);

/**
* This file is part of the Nexus framework.
*
* (c) John Paul E. Balandan, CPA <[email protected]>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/

namespace Nexus\Encryption\Encoding;

final class NullEncoder implements EncoderInterface
{
public function encode(#[\SensitiveParameter] string $binaryString): string
{
return $binaryString;
}

public function decode(#[\SensitiveParameter] string $encodedString, string $ignore = ''): string
{
return $encodedString;
}
}
22 changes: 22 additions & 0 deletions src/Nexus/Encryption/Exception/InvalidEncodingVariantException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

declare(strict_types=1);

/**
* This file is part of the Nexus framework.
*
* (c) John Paul E. Balandan, CPA <[email protected]>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/

namespace Nexus\Encryption\Exception;

final class InvalidEncodingVariantException extends \RuntimeException
{
public function __construct()
{
parent::__construct('Unknown variant for encoder.');
}
}
Loading
Loading