Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 12804bb

Browse filesBrowse files
committed
Adding a KeyInterface
1 parent c08912f commit 12804bb
Copy full SHA for 12804bb

File tree

5 files changed

+440
-0
lines changed
Filter options

5 files changed

+440
-0
lines changed
+89Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Encryption;
13+
14+
use Symfony\Component\Encryption\Exception\DecryptionException;
15+
use Symfony\Component\Encryption\Exception\EncryptionException;
16+
17+
/**
18+
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
19+
*
20+
* @experimental in 5.3
21+
*/
22+
interface EncryptionInterface
23+
{
24+
/**
25+
* Generates new a Key to be used with encryption.
26+
*
27+
* Don't lose your private key and make sure to keep it a secret.
28+
*
29+
* @throws EncryptionException
30+
*/
31+
public function generateKey(): KeyInterface;
32+
33+
/**
34+
* Get an encrypted version of the message.
35+
*
36+
* Symmetric encryption uses the same key to encrypt and decrypt a message.
37+
* The key should be kept safe and should not be exposed to the public. Symmetric
38+
* encryption should be used when you are not sending the encrypted message to
39+
* anyone else.
40+
*
41+
* Example: You store a value on disk or in a cookie and don't want anyone else
42+
* to read it.
43+
*
44+
* Symmetric encryption is in theory weaker than asymmetric encryption.
45+
*
46+
* @param string $message plain text version of the message
47+
*
48+
* @return string the output
49+
*
50+
* @throws EncryptionException
51+
*/
52+
public function encrypt(string $message, KeyInterface $myKey): string;
53+
54+
/**
55+
* Get an encrypted version of the message that only the recipient can read.
56+
*
57+
* Asymmetric encryption uses a "key pair" ie a public key and a private key.
58+
* It is safe to share your public key, but the private key should always be
59+
* kept a secret.
60+
*
61+
* When Alice and Bob wants to communicate they share their public keys with
62+
* each other. Alice will encrypt a message with bobs public key. When Bob
63+
* receive the message, he will decrypt it with his private key.
64+
*/
65+
public function encryptFor(string $message, KeyInterface $recipientKey): string;
66+
67+
/**
68+
* Get an encrypted version of the message that only the recipient can read.
69+
* The recipient can also verify who sent the message
70+
*
71+
* Asymmetric encryption uses a "key pair" ie a public key and a private key.
72+
* It is safe to share your public key, but the private key should always be
73+
* kept a secret.
74+
*
75+
* When Alice and Bob wants to communicate they share their public keys with
76+
* each other. Alice will encrypt a message with keypair [ alice_private, bob_public ].
77+
* When Bob receive the message, he will decrypt it with keypair [ bob_private, alice_public ].
78+
*/
79+
public function encryptForAndSign(string $message, KeyInterface $keypair): string;
80+
81+
/**
82+
* Get a plain text version of the encrypted message.
83+
*
84+
* @param string $message encrypted version of the message
85+
*
86+
* @throws DecryptionException
87+
*/
88+
public function decrypt(string $message, KeyInterface $key): string;
89+
}
+27Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Encryption\Exception;
13+
14+
/**
15+
* Thrown when a message cannot be encrypted.
16+
*
17+
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
18+
*
19+
* @experimental in 5.3
20+
*/
21+
class InvalidKeyException extends \RuntimeException implements ExceptionInterface
22+
{
23+
public function __construct($message = null, \Throwable $previous = null)
24+
{
25+
parent::__construct($message ?? 'This key is not valid.', 0, $previous);
26+
}
27+
}
+45Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Encryption;
13+
14+
use Symfony\Component\Encryption\Exception\DecryptionException;
15+
use Symfony\Component\Encryption\Exception\EncryptionException;
16+
17+
/**
18+
* A Key for a specific user and specific Encryption implementation. Keys cannot
19+
* be shared between Encryption implementations.
20+
*
21+
* A Key is always serializable.
22+
*
23+
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
24+
*
25+
* @experimental in 5.3
26+
*/
27+
interface KeyInterface
28+
{
29+
/**
30+
* Returns a string to be stored in a safe place
31+
*/
32+
public function toString(): string;
33+
34+
/**
35+
* Creates a Key from stored data
36+
*/
37+
public function fromString(string $string): self;
38+
39+
/**
40+
* Get the public key from this Key. Not all Keys have a public key.
41+
*
42+
* The public key can be shared.
43+
*/
44+
public function getPublicKey(): ?string;
45+
}
+126Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Encryption\Sodium;
13+
14+
use Symfony\Component\Encryption\AsymmetricEncryptionInterface;
15+
use Symfony\Component\Encryption\EncryptionInterface;
16+
use Symfony\Component\Encryption\Exception\DecryptionException;
17+
use Symfony\Component\Encryption\Exception\EncryptionException;
18+
use Symfony\Component\Encryption\Exception\InvalidArgumentException;
19+
use Symfony\Component\Encryption\Exception\InvalidKeyException;
20+
use Symfony\Component\Encryption\Exception\SignatureVerificationRequiredException;
21+
use Symfony\Component\Encryption\Exception\UnsupportedAlgorithmException;
22+
use Symfony\Component\Encryption\Ciphertext;
23+
use Symfony\Component\Encryption\KeyInterface;
24+
use Symfony\Component\Encryption\SymmetricEncryptionInterface;
25+
26+
/**
27+
* Using the Sodium extension to safely encrypt your data.
28+
*
29+
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
30+
*
31+
* @experimental in 5.3
32+
*/
33+
final class SodiumEncryption implements EncryptionInterface
34+
{
35+
public function generateKey(): KeyInterface
36+
{
37+
return SodiumKey::create(sodium_crypto_secretbox_keygen(), sodium_crypto_box_keypair());
38+
}
39+
40+
public function encrypt(string $message, KeyInterface $myKey): string
41+
{
42+
if (!$myKey instanceof SodiumKey) {
43+
throw new InvalidKeyException();
44+
}
45+
46+
$nonce = random_bytes(\SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
47+
try {
48+
$ciphertext = sodium_crypto_secretbox($message, $nonce, $myKey->getSecret());
49+
} catch (\SodiumException $exception) {
50+
throw new EncryptionException('Failed to encrypt message.', $exception);
51+
}
52+
53+
return Ciphertext::create('sodium_secretbox', $ciphertext, $nonce)->getString();
54+
}
55+
56+
public function encryptFor(string $message, KeyInterface $recipientKey): string
57+
{
58+
if (!$recipientKey instanceof SodiumKey) {
59+
throw new InvalidKeyException();
60+
}
61+
62+
try {
63+
if (null === $publicKey = $recipientKey->getPublicKey()) {
64+
throw new InvalidKeyException('This key does not have a public key. Who should we encrypt this message for?');
65+
}
66+
67+
$ciphertext = sodium_crypto_box_seal($message, $publicKey);
68+
} catch (\SodiumException $exception) {
69+
throw new EncryptionException('Failed to encrypt message.', $exception);
70+
}
71+
72+
return Ciphertext::create('sodium_crypto_box_seal', $ciphertext, random_bytes(\SODIUM_CRYPTO_BOX_NONCEBYTES))->getString();
73+
}
74+
75+
public function encryptForAndSign(string $message, KeyInterface $keypair): string
76+
{
77+
if (!$keypair instanceof SodiumKey) {
78+
throw new InvalidKeyException();
79+
}
80+
81+
try {
82+
if (null === $publicKey = $keypair->getPublicKey()) {
83+
throw new InvalidKeyException('This key does not have a public key. Who should we encrypt this message for?');
84+
}
85+
86+
$nonce = random_bytes(\SODIUM_CRYPTO_BOX_NONCEBYTES);
87+
$ciphertext = sodium_crypto_box($message, $nonce, $keypair->getKeypair());
88+
} catch (\SodiumException $exception) {
89+
throw new EncryptionException('Failed to encrypt message.', $exception);
90+
}
91+
92+
return Ciphertext::create('sodium_crypto_box', $ciphertext, $nonce)->getString();
93+
}
94+
95+
public function decrypt(string $message, KeyInterface $key): string
96+
{
97+
if (!$key instanceof SodiumKey) {
98+
throw new InvalidKeyException();
99+
}
100+
101+
$ciphertext = Ciphertext::parse($message);
102+
$algorithm = $ciphertext->getAlgorithm();
103+
$payload = $ciphertext->getPayload();
104+
$nonce = $ciphertext->getNonce();
105+
106+
try {
107+
if ('sodium_crypto_box_seal' === $algorithm) {
108+
$output = sodium_crypto_box_seal_open($payload, $key->getKeypair());
109+
} elseif ('sodium_crypto_box' === $algorithm) {
110+
$output = sodium_crypto_box_open($payload, $nonce, $key->getKeypair());
111+
} elseif ('sodium_secretbox' === $algorithm) {
112+
$output = sodium_crypto_secretbox_open($payload, $nonce, $key->getSecret());
113+
} else {
114+
throw new UnsupportedAlgorithmException($algorithm);
115+
}
116+
} catch (\SodiumException $exception) {
117+
throw new DecryptionException(sprintf('Failed to decrypt message with algorithm "%s".', $algorithm), $exception);
118+
}
119+
120+
if (false === $output) {
121+
throw new DecryptionException();
122+
}
123+
124+
return $output;
125+
}
126+
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.