Skip to content

Commit 7e71ed9

Browse files
authored
Wrap secretbox exceptions (#42)
* test: upgrade test runners * feature: wrap secretbox exceptions closes #10 * feature: wrap secretbox exceptions closes #10
1 parent 1be4334 commit 7e71ed9

9 files changed

Lines changed: 137 additions & 32 deletions

sodium.php

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,48 @@
11
<?php
2+
use Gt\Cipher\EncryptionFailureException;
3+
use Gt\Cipher\Message\DecryptionFailureException;
4+
5+
require("vendor/autoload.php");
6+
27
$messageToTransmit = "Cipher test!";
38
$sharedKey = random_bytes(SODIUM_CRYPTO_SECRETBOX_KEYBYTES);
49
$iv = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
510

6-
$encryptedBytes = sodium_crypto_secretbox(
7-
$messageToTransmit,
8-
$iv,
9-
$sharedKey
10-
);
11+
try {
12+
$encryptedBytes = sodium_crypto_secretbox(
13+
$messageToTransmit,
14+
$iv,
15+
$sharedKey
16+
);
17+
}
18+
catch(Throwable $throwable) {
19+
throw new EncryptionFailureException(
20+
"Error encrypting cipher message",
21+
previous: $throwable,
22+
);
23+
}
1124
$cipher = base64_encode($encryptedBytes);
1225

1326
echo "Shared key: ", base64_encode($sharedKey), PHP_EOL;
1427
echo "IV: ", base64_encode($iv), PHP_EOL;
1528
echo "Cipher: ", base64_encode($cipher), PHP_EOL;
1629

17-
$decrypted = sodium_crypto_secretbox_open(
18-
$encryptedBytes,
19-
$iv,
20-
$sharedKey,
21-
);
30+
try {
31+
$decrypted = sodium_crypto_secretbox_open(
32+
$encryptedBytes,
33+
$iv,
34+
$sharedKey,
35+
);
36+
}
37+
catch(Throwable $throwable) {
38+
throw new DecryptionFailureException(
39+
"Error decrypting cipher message",
40+
previous: $throwable,
41+
);
42+
}
43+
44+
if($decrypted === false) {
45+
throw new DecryptionFailureException("Error decrypting cipher message");
46+
}
2247

2348
echo "Decrypted: $decrypted", PHP_EOL;

src/CipherText.php

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
use Gt\Http\Uri;
55
use Psr\Http\Message\UriInterface;
66
use Stringable;
7+
use Throwable;
78

89
class CipherText implements Stringable {
910
private string $bytes;
@@ -13,12 +14,19 @@ public function __construct(
1314
private InitVector $iv,
1415
private Key $key,
1516
) {
16-
17-
$this->bytes = sodium_crypto_secretbox(
18-
$data,
19-
$this->iv->getBytes(),
20-
$this->key->getBytes(),
21-
);
17+
try {
18+
$this->bytes = sodium_crypto_secretbox(
19+
$data,
20+
$this->iv->getBytes(),
21+
$this->key->getBytes(),
22+
);
23+
}
24+
catch(Throwable $throwable) {
25+
throw new EncryptionFailureException(
26+
"Error encrypting cipher message",
27+
previous: $throwable,
28+
);
29+
}
2230
}
2331

2432
public function __toString():string {

src/EncryptedUri.php

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
<?php
22
namespace Gt\Cipher;
33

4-
use Gt\Cipher\Message\DecryptionFailureException;
54
use Gt\Cipher\Message\PlainTextMessage;
65
use Gt\Http\Uri;
76
use Psr\Http\Message\UriInterface;
7+
use Throwable;
88

99
class EncryptedUri {
1010
private string $encryptedBytes;
@@ -39,13 +39,21 @@ public function __construct(
3939
}
4040

4141
public function decryptMessage(Key $key):PlainTextMessage {
42-
$decrypted = sodium_crypto_secretbox_open(
43-
$this->encryptedBytes,
44-
$this->iv->getBytes(),
45-
$key->getBytes(),
46-
);
42+
try {
43+
$decrypted = sodium_crypto_secretbox_open(
44+
$this->encryptedBytes,
45+
$this->iv->getBytes(),
46+
$key->getBytes(),
47+
);
48+
}
49+
catch(Throwable $throwable) {
50+
throw new UriDecryptionFailureException(
51+
"Error decrypting cipher URI",
52+
previous: $throwable,
53+
);
54+
}
4755
if($decrypted === false) {
48-
throw new DecryptionFailureException("Error decrypting cipher message");
56+
throw new UriDecryptionFailureException("Error decrypting cipher URI");
4957
}
5058
return new PlainTextMessage(
5159
$decrypted,

src/EncryptionFailureException.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<?php
2+
namespace Gt\Cipher;
3+
4+
class EncryptionFailureException extends CipherException {}

src/Message/EncryptedMessage.php

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,23 @@
22
namespace Gt\Cipher\Message;
33

44
use Gt\Cipher\Key;
5+
use Throwable;
56

67
class EncryptedMessage extends AbstractMessage {
78
public function decrypt(Key $key):PlainTextMessage {
8-
$decrypted = sodium_crypto_secretbox_open(
9-
base64_decode($this->data),
10-
$this->iv->getBytes(),
11-
$key->getBytes(),
12-
);
9+
try {
10+
$decrypted = sodium_crypto_secretbox_open(
11+
base64_decode($this->data),
12+
$this->iv->getBytes(),
13+
$key->getBytes(),
14+
);
15+
}
16+
catch(Throwable $throwable) {
17+
throw new DecryptionFailureException(
18+
"Error decrypting cipher message",
19+
previous: $throwable,
20+
);
21+
}
1322
if($decrypted === false) {
1423
throw new DecryptionFailureException("Error decrypting cipher message");
1524
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<?php
2+
namespace Gt\Cipher;
3+
4+
class UriDecryptionFailureException extends CipherException {}

test/phpunit/CipherTextTest.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
namespace Gt\Cipher\Test;
33

44
use Gt\Cipher\CipherText;
5+
use Gt\Cipher\EncryptionFailureException;
56
use Gt\Cipher\InitVector;
67
use Gt\Cipher\Key;
78
use PHPUnit\Framework\TestCase;
@@ -51,4 +52,17 @@ public function testGetUri():void {
5152
self::assertSame($baseUri, $uri->getScheme() . "://" . $uri->getAuthority());
5253
self::assertSame(http_build_query($expectedQueryParts), $uri->getQuery());
5354
}
55+
56+
public function testConstruct_wrapsSodiumFailure():void {
57+
$data = "test data";
58+
$iv = self::createMock(InitVector::class);
59+
$iv->method("getBytes")
60+
->willReturn(str_repeat("0", SODIUM_CRYPTO_SECRETBOX_NONCEBYTES));
61+
$key = self::createMock(Key::class);
62+
$key->method("getBytes")
63+
->willReturn("bad");
64+
65+
self::expectException(EncryptionFailureException::class);
66+
new CipherText($data, $iv, $key);
67+
}
5468
}

test/phpunit/EncryptedUriTest.php

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
use Gt\Cipher\EncryptedUri;
55
use Gt\Cipher\InitVector;
66
use Gt\Cipher\Key;
7-
use Gt\Cipher\Message\DecryptionFailureException;
87
use Gt\Cipher\MissingQueryStringException;
8+
use Gt\Cipher\UriDecryptionFailureException;
99
use PHPUnit\Framework\TestCase;
1010

1111
class EncryptedUriTest extends TestCase {
@@ -38,19 +38,38 @@ public function testConstruct_missingCipherValue():void {
3838
}
3939

4040
public function testDecryptMessage_error():void {
41-
$ivString = base64_encode(str_repeat("0", SODIUM_CRYPTO_SECRETBOX_NONCEBYTES));
41+
$ivString = base64_encode(
42+
str_repeat("0", SODIUM_CRYPTO_SECRETBOX_NONCEBYTES)
43+
);
4244
$uri = "https://example.com/test/?cipher=0000&iv=$ivString";
4345
$sut = new EncryptedUri($uri);
4446

4547
$key = self::createMock(Key::class);
4648
$key->method("getBytes")
4749
->willReturn(str_repeat("0", SODIUM_CRYPTO_SECRETBOX_KEYBYTES));
48-
self::expectException(DecryptionFailureException::class);
50+
self::expectException(UriDecryptionFailureException::class);
51+
$sut->decryptMessage($key);
52+
}
53+
54+
public function testDecryptMessage_wrapsSodiumFailure():void {
55+
$ivString = base64_encode(
56+
str_repeat("0", SODIUM_CRYPTO_SECRETBOX_NONCEBYTES)
57+
);
58+
$uri = "https://example.com/test/?cipher=0000&iv=$ivString";
59+
$sut = new EncryptedUri($uri);
60+
61+
$key = self::createMock(Key::class);
62+
$key->method("getBytes")
63+
->willReturn("bad");
64+
65+
self::expectException(UriDecryptionFailureException::class);
4966
$sut->decryptMessage($key);
5067
}
5168

5269
public function testDecryptMessage():void {
53-
$uri = "https://example.com/?cipher=lmEClve%2FuhmK32ghM0%2BA%2FI%2Btysm00AL37YD6eg%3D%3D&iv=UVunn3laPVnK4CfHZuS2AnvJ1KfsPM1r";
70+
$uri = "https://example.com/"
71+
. "?cipher=lmEClve%2FuhmK32ghM0%2BA%2FI%2Btysm00AL37YD6eg%3D%3D"
72+
. "&iv=UVunn3laPVnK4CfHZuS2AnvJ1KfsPM1r";
5473
$sut = new EncryptedUri($uri);
5574

5675
$key = self::createMock(Key::class);

test/phpunit/Message/EncryptedMessageTest.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,18 @@ public function testDecrypt_failure():void {
4141
self::expectException(DecryptionFailureException::class);
4242
$sut->decrypt($key);
4343
}
44+
45+
public function testDecrypt_wrapsSodiumFailure():void {
46+
$iv = self::createMock(InitVector::class);
47+
$iv->method("getBytes")
48+
->willReturn(str_repeat("0", SODIUM_CRYPTO_SECRETBOX_NONCEBYTES));
49+
$sut = new EncryptedMessage("badly formed data", $iv);
50+
51+
$key = self::createMock(Key::class);
52+
$key->method("getBytes")
53+
->willReturn("bad");
54+
55+
self::expectException(DecryptionFailureException::class);
56+
$sut->decrypt($key);
57+
}
4458
}

0 commit comments

Comments
 (0)