Skip to content

Commit

Permalink
Add option to not use base64
Browse files Browse the repository at this point in the history
  • Loading branch information
lucacastelnuovo committed Mar 1, 2024
1 parent 7f25a70 commit 5df3f29
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 18 deletions.
29 changes: 19 additions & 10 deletions src/LaravelAge.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ class LaravelAge
public function __construct(private ?PrivateKey $privateKey = null, private ?PublicKey $publicKey = null)
{
/* If no keys are provided, use the one from .env or create a pair. */
if (! isset($privateKey) && ! isset($publicKey)) {
if (!isset($privateKey) && !isset($publicKey)) {
/** @phpstan-ignore-next-line */
$this->privateKey = new PrivateKey(config('laravel-age.identity'));
$this->publicKey = $this->privateKey->getPublicKey();
}

/* If only the private key is provided, generate the public key. */
if (isset($privateKey) && ! isset($publicKey)) {
if (isset($privateKey) && !isset($publicKey)) {
$this->publicKey = $privateKey->getPublicKey();
}
}
Expand All @@ -30,7 +30,7 @@ public static function generateKeypair(): LaravelAge

public function getPublicKey(): PublicKey
{
if (! isset($this->publicKey)) {
if (!isset($this->publicKey)) {
throw new Exception('Public key not set!');
}

Expand All @@ -39,28 +39,37 @@ public function getPublicKey(): PublicKey

public function getPrivateKey(): PrivateKey
{
if (! isset($this->privateKey)) {
if (!isset($this->privateKey)) {
throw new Exception('Private key not set!');
}

return $this->privateKey;
}

public function encrypt(string $message): string
/**
* Encrypt a message using the public key.
* Returns the base64 encoded encrypted message.
*/
public function encrypt(string $message, bool $base64 = true): string
{
if (! isset($this->publicKey)) {
if (!isset($this->publicKey)) {
throw new Exception('Public key not set!');
}

return $this->publicKey->encrypt($message);
return $this->publicKey->encrypt($message, $base64);
}

public function decrypt(string $message): string

/**
* Decrypt a base64 encoded message using the private key.
* Returns the decrypted message.
*/
public function decrypt(string $message, bool $base64 = true): string
{
if (! isset($this->privateKey)) {
if (!isset($this->privateKey)) {
throw new Exception('Private key not set!');
}

return $this->privateKey->decrypt($message);
return $this->privateKey->decrypt($message, $base64);
}
}
12 changes: 8 additions & 4 deletions src/PrivateKey.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class PrivateKey

public function __construct(string $privateKey = '')
{
if (! $privateKey) {
if (!$privateKey) {
$result = Process::pipe([
'age-keygen',
'grep -E "^AGE-SECRET-KEY-[A-Za-z0-9]{59}$"',
Expand All @@ -28,7 +28,7 @@ public function __construct(string $privateKey = '')

$privateKey = str($privateKey)->trim();

if (! $privateKey->startsWith('AGE-SECRET-KEY-') || $privateKey->length() !== 74) {
if (!$privateKey->startsWith('AGE-SECRET-KEY-') || $privateKey->length() !== 74) {
throw new Exception('Invalid private key provided!');
}

Expand All @@ -51,10 +51,14 @@ public function getPublicKey(): PublicKey
return new PublicKey($result->output());
}

public function decrypt(string $message): string
/**
* Decrypt a base64 encoded message using the private key.
* Returns the decrypted message.
*/
public function decrypt(string $message, bool $base64): string
{
$ulid = Str::ulid();
Storage::put($ulid, base64_decode($message));
Storage::put($ulid, $base64 ? base64_decode($message) : $message);

$path = Storage::path($ulid);
$result = Process::input($this->encode())->run("age -d -i - {$path}");
Expand Down
10 changes: 7 additions & 3 deletions src/PublicKey.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public function __construct(string $publicKey)
{
$publicKey = str($publicKey)->trim();

if (! $publicKey->startsWith('age') || $publicKey->length() !== 62) {
if (!$publicKey->startsWith('age') || $publicKey->length() !== 62) {
throw new Exception('Invalid public key provided!');
}

Expand All @@ -25,14 +25,18 @@ public function encode(): string
return str($this->publicKey)->trim();
}

public function encrypt(string $message): string
/**
* Encrypt a message using the public key.
* Returns the base64 encoded encrypted message.
*/
public function encrypt(string $message, bool $base64): string
{
$result = Process::input($message)->run("age -r {$this->encode()}");

if ($result->failed()) {
throw new Exception('Failed to encrypt message!');
}

return base64_encode($result->output());
return $base64 ? base64_encode($result->output()) : $result->output();
}
}
34 changes: 33 additions & 1 deletion tests/LaravelAgeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
expect($age->encrypt('message'))->toBeString();
});

it('can decrypt with an provided private key', function () {
it('can decrypt with an provided private key (using base64)', function () {
$encodeKey = 'AGE-SECRET-KEY-1TKGRTQP4H79MTNHVDRSA3L0CS7MFSMW0DQX80CWP0JDUFL97RRJSPK9777';
$privateKey = new PrivateKey($encodeKey);
$age = new LaravelAge(privateKey: $privateKey);
Expand All @@ -72,6 +72,18 @@
expect($decrypted)->toBe($message);
});

it('can decrypt with an provided private key (without using base64)', function () {
$encodeKey = 'AGE-SECRET-KEY-1TKGRTQP4H79MTNHVDRSA3L0CS7MFSMW0DQX80CWP0JDUFL97RRJSPK9777';
$privateKey = new PrivateKey($encodeKey);
$age = new LaravelAge(privateKey: $privateKey);

$message = 'Hello, World!';
$encrypted = $age->encrypt($message, false);
$decrypted = $age->decrypt($encrypted, false);

expect($decrypted)->toBe($message);
});

it('cannot decrypt with an provided public key', function () {
$encodeKey = 'age1xqrfpqxz55ersvu6mmhwzcctqk27ppnatms7p9zruclrm8tt4y0q3apxuc';
$publicKey = new PublicKey($encodeKey);
Expand All @@ -82,6 +94,26 @@
$decrypted = $age->decrypt($encrypted);
})->throws(Exception::class);

it('cannot decrypt with an provided private key (using base64 only to encrypt)', function () {
$encodeKey = 'age1xqrfpqxz55ersvu6mmhwzcctqk27ppnatms7p9zruclrm8tt4y0q3apxuc';
$publicKey = new PublicKey($encodeKey);
$age = new LaravelAge(publicKey: $publicKey);

$message = 'Hello, World!';
$encrypted = $age->encrypt($message);
$decrypted = $age->decrypt($encrypted, false);
})->throws(Exception::class);

it('cannot decrypt with an provided private key (using base64 only to decrypt)', function () {
$encodeKey = 'age1xqrfpqxz55ersvu6mmhwzcctqk27ppnatms7p9zruclrm8tt4y0q3apxuc';
$publicKey = new PublicKey($encodeKey);
$age = new LaravelAge(publicKey: $publicKey);

$message = 'Hello, World!';
$encrypted = $age->encrypt($message, false);
$decrypted = $age->decrypt($encrypted);
})->throws(Exception::class);

it('runs usage code from readme', function () {
$message = 'Hello World!';

Expand Down

0 comments on commit 5df3f29

Please sign in to comment.