Skip to content

Commit e4c1e55

Browse files
committed
Moved files to a new component
1 parent c095c56 commit e4c1e55

31 files changed

+461
-132
lines changed

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
use Symfony\Component\Config\Definition\ConfigurationInterface;
2323
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
2424
use Symfony\Component\DependencyInjection\Exception\LogicException;
25+
use Symfony\Component\Encryption\SymmetricEncryptionInterface;
2526
use Symfony\Component\Form\Form;
2627
use Symfony\Component\HttpClient\HttpClient;
2728
use Symfony\Component\HttpFoundation\Cookie;
@@ -136,6 +137,7 @@ public function getConfigTreeBuilder()
136137
$this->addSecretsSection($rootNode);
137138
$this->addNotifierSection($rootNode);
138139
$this->addRateLimiterSection($rootNode);
140+
$this->addEncryptionSection($rootNode);
139141

140142
return $treeBuilder;
141143
}
@@ -1888,4 +1890,16 @@ private function addRateLimiterSection(ArrayNodeDefinition $rootNode)
18881890
->end()
18891891
;
18901892
}
1893+
1894+
private function addEncryptionSection(ArrayNodeDefinition $rootNode)
1895+
{
1896+
$rootNode
1897+
->children()
1898+
->arrayNode('encryption')
1899+
->info('esi configuration')
1900+
->{!class_exists(FullStack::class) && interface_exists(SymmetricEncryptionInterface::class) ? 'canBeDisabled' : 'canBeEnabled'}()
1901+
->end()
1902+
->end()
1903+
;
1904+
}
18911905
}

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,7 @@ public function load(array $configs, ContainerBuilder $container)
405405
$this->registerAnnotationsConfiguration($config['annotations'], $container, $loader);
406406
$this->registerPropertyAccessConfiguration($config['property_access'], $container, $loader);
407407
$this->registerSecretsConfiguration($config['secrets'], $container, $loader);
408+
$this->registerEncryptionConfiguration($config['encryption'], $container, $loader);
408409

409410
if ($this->isConfigEnabled($container, $config['serializer'])) {
410411
if (!class_exists('Symfony\Component\Serializer\Serializer')) {
@@ -597,6 +598,15 @@ private function registerHttpCacheConfiguration(array $config, ContainerBuilder
597598
->replaceArgument(3, $options);
598599
}
599600

601+
private function registerEncryptionConfiguration(array $config, ContainerBuilder $container, PhpFileLoader $loader)
602+
{
603+
if (!$this->isConfigEnabled($container, $config)) {
604+
return;
605+
}
606+
607+
$loader->load('encryption.php');
608+
}
609+
600610
private function registerEsiConfiguration(array $config, ContainerBuilder $container, PhpFileLoader $loader)
601611
{
602612
if (!$this->isConfigEnabled($container, $config)) {
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
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\DependencyInjection\Loader\Configurator;
13+
14+
use phpseclib\Crypt\AES;
15+
use Symfony\Component\Encryption\AsymmetricEncryptionInterface;
16+
use Symfony\Component\Encryption\Provider\PhpseclibEncryption;
17+
use Symfony\Component\Encryption\Provider\SodiumEncryption;
18+
use Symfony\Component\Encryption\SymmetricEncryptionInterface;
19+
20+
return static function (ContainerConfigurator $container) {
21+
$sodiumInstalled = \function_exists('sodium_crypto_box_keypair');
22+
$phpseclibInstalled = class_exists(AES::class);
23+
24+
$container->services()
25+
26+
->set('security.encryption.sodium', SodiumEncryption::class)
27+
->args([
28+
'%kernel.secret%',
29+
])
30+
->set('security.encryption.phpseclib', PhpseclibEncryption::class)
31+
->args([
32+
'%kernel.secret%',
33+
])
34+
->alias(SymmetricEncryptionInterface::class, $phpseclibInstalled && !$sodiumInstalled ? 'security.encryption.phpseclib' : 'security.encryption.sodium')
35+
->alias(AsymmetricEncryptionInterface::class, $phpseclibInstalled && !$sodiumInstalled ? 'security.encryption.phpseclib' : 'security.encryption.sodium')
36+
;
37+
};

src/Symfony/Bundle/SecurityBundle/Resources/config/security.php

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111

1212
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
1313

14-
use phpseclib\Crypt\AES;
1514
use Symfony\Bundle\SecurityBundle\CacheWarmer\ExpressionCacheWarmer;
1615
use Symfony\Bundle\SecurityBundle\EventListener\FirewallEventBubblingListener;
1716
use Symfony\Bundle\SecurityBundle\EventListener\FirewallListener;
@@ -37,10 +36,6 @@
3736
use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface;
3837
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoder;
3938
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
40-
use Symfony\Component\Security\Core\Encryption\AsymmetricEncryptionInterface;
41-
use Symfony\Component\Security\Core\Encryption\PhpseclibEncryption;
42-
use Symfony\Component\Security\Core\Encryption\SodiumEncryption;
43-
use Symfony\Component\Security\Core\Encryption\SymmetricEncryptionInterface;
4439
use Symfony\Component\Security\Core\Role\RoleHierarchy;
4540
use Symfony\Component\Security\Core\Role\RoleHierarchyInterface;
4641
use Symfony\Component\Security\Core\Security;
@@ -63,9 +58,6 @@
6358
->set('security.role_hierarchy.roles', [])
6459
;
6560

66-
$sodiumInstalled = \function_exists('sodium_crypto_box_keypair');
67-
$phpseclibInstalled = class_exists(AES::class);
68-
6961
$container->services()
7062
->set('security.authorization_checker', AuthorizationChecker::class)
7163
->public()
@@ -104,17 +96,6 @@
10496
])
10597
->tag('controller.argument_value_resolver', ['priority' => 40])
10698

107-
->set('security.encryption.sodium', SodiumEncryption::class)
108-
->args([
109-
'%kernel.secret%',
110-
])
111-
->set('security.encryption.phpseclib', PhpseclibEncryption::class)
112-
->args([
113-
'%kernel.secret%',
114-
])
115-
->alias(SymmetricEncryptionInterface::class, $phpseclibInstalled && !$sodiumInstalled ? 'security.encryption.phpseclib' : 'security.encryption.sodium')
116-
->alias(AsymmetricEncryptionInterface::class, $phpseclibInstalled && !$sodiumInstalled ? 'security.encryption.phpseclib' : 'security.encryption.sodium')
117-
11899
// Authentication related services
119100
->set('security.authentication.trust_resolver', AuthenticationTrustResolver::class)
120101

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
/.gitignore export-ignore
2+
/phpunit.xml.dist export-ignore
3+
/Tests export-ignore
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
composer.lock
2+
phpunit.xml
3+
vendor/

src/Symfony/Component/Security/Core/Encryption/AsymmetricEncryptionInterface.php renamed to src/Symfony/Component/Encryption/AsymmetricEncryptionInterface.php

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@
99
* file that was distributed with this source code.
1010
*/
1111

12-
namespace Symfony\Component\Security\Core\Encryption;
12+
namespace Symfony\Component\Encryption;
1313

14-
use Symfony\Component\Security\Core\Exception\EncryptionException;
15-
use Symfony\Component\Security\Core\Exception\WrongEncryptionKeyException;
14+
use Symfony\Component\Encryption\Exception\EncryptionException;
15+
use Symfony\Component\Encryption\Exception\SignatureVerificationRequiredException;
16+
use Symfony\Component\Encryption\Exception\UnableToVerifySignatureException;
1617

1718
/**
1819
* Asymmetric encryption uses a "key pair" ie a public key and a private key. It
@@ -35,6 +36,8 @@ interface AsymmetricEncryptionInterface
3536
* Don't lose your private key and make sure to keep it a secret.
3637
*
3738
* @return array{public: string, private: string}
39+
*
40+
* @throws EncryptionException
3841
*/
3942
public function generateKeypair(): array;
4043

@@ -62,7 +65,8 @@ public function encrypt(string $message, string $publicKey, ?string $privateKey
6265
* @param string|null $publicKey Alice's public key. If a public key is provided, Bob will be sure the message comes from Alice.
6366
*
6467
* @throws EncryptionException
65-
* @throws WrongEncryptionKeyException When the keys are valid but did not match the message. Either it was the wrong sender/receiver, or the message was tampered with.
68+
* @throws UnableToVerifySignatureException either it was the wrong sender/receiver, or the message was tampered with
69+
* @throws SignatureVerificationRequiredException thrown when you passed null as public key but the public key is needed
6670
*/
6771
public function decrypt(string $message, string $privateKey, ?string $publicKey = null): string;
6872
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
CHANGELOG
2+
=========
3+
4+
5.3.0
5+
-----
6+
7+
* Introduced the component as experimental
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
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\MalformedCipherException;
15+
16+
/**
17+
* A representation of the encrypted message.
18+
*
19+
* This class is responsible over the payload API.
20+
*
21+
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
22+
*
23+
* @experimental in 5.3
24+
*
25+
* @internal
26+
*/
27+
class Ciphertext
28+
{
29+
private $algorithm;
30+
private $ciphertext;
31+
private $nonce;
32+
33+
public function __construct(string $algorithm, string $ciphertext, string $nonce)
34+
{
35+
$this->algorithm = $algorithm;
36+
$this->ciphertext = $ciphertext;
37+
$this->nonce = $nonce;
38+
}
39+
40+
/**
41+
* Take a string representation of the chiphertext and parse it into an object.
42+
*
43+
* @throws MalformedCipherException
44+
*/
45+
public static function parse(string $ciphertext): self
46+
{
47+
$parts = explode('.', $ciphertext);
48+
if (false === $parts || 3 !== \count($parts)) {
49+
throw new MalformedCipherException();
50+
}
51+
52+
[$cipher, $algorithm, $nonce] = $parts;
53+
$algorithm = base64_decode($algorithm, true);
54+
$ciphertext = base64_decode($cipher, true);
55+
$nonce = base64_decode($nonce, true);
56+
57+
return new self($algorithm, $ciphertext, $nonce);
58+
}
59+
60+
/**
61+
* @return string
62+
*/
63+
public function __toString()
64+
{
65+
return $this->getUrlSafeRepresentation();
66+
}
67+
68+
public function getUrlSafeRepresentation(): string
69+
{
70+
return sprintf('%s.%s.%s', base64_encode($this->ciphertext), base64_encode($this->algorithm), base64_encode($this->nonce));
71+
}
72+
73+
public function getAlgorithm(): string
74+
{
75+
return $this->algorithm;
76+
}
77+
78+
public function getCiphertext(): string
79+
{
80+
return $this->ciphertext;
81+
}
82+
83+
public function getNonce(): string
84+
{
85+
return $this->nonce;
86+
}
87+
}
Lines 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 decrypted.
16+
*
17+
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
18+
*
19+
* @experimental in 5.3
20+
*/
21+
class DecryptionException extends \RuntimeException implements ExceptionInterface
22+
{
23+
public function __construct($message = null, \Throwable $previous = null)
24+
{
25+
parent::__construct($message ?? 'Could not decrypt the ciphertext.', 0, $previous);
26+
}
27+
}

0 commit comments

Comments
 (0)