ricwein / crypto
基于libsodium的加密库
Requires
- php: >= 8.0
- ext-mbstring: *
- ext-sodium: *
- paragonie/constant_time_encoding: ^2
Requires (Dev)
- overtrue/phplint: ^2.3
- phpunit/phpunit: ^9.5
- ricwein/filesystem: ^4.2
Suggests
- ricwein/filesystem: Support for file-based cryptography
README
此库将PHP的libsodium加密函数包装成一个面向对象的API,允许简单且安全地使用。
此库提供
- 使用XSalsa20进行消息和文件的对称和非对称认证加密/解密
- 加密安全密钥和密钥对生成
- 使用Curve25519(X25519)的Diffie-Hellman密钥交换
- 支持大多数常见编码的密钥和密文导入/导出
安装
composer require ricwein/crypto
所有类都使用根命名空间 ricwein\Crypto
。所有抛出的异常都扩展自 ricwein\Crypto\Exceptions\Exception
。
对称加密
对称加密使用一个秘密(密钥)加密一个给定的消息到一个密文,并使用相同的秘密将密文解密回原始消息。
加密
use ricwein\Crypto\Symmetric\Crypto; use ricwein\Crypto\Symmetric\Key; use ricwein\Crypto\Exceptions\Exception as CryptoException; try { $message = 'asecretmessage'; $key = Key::generate(); // actual encryption $ciphertext = (new Crypto($key))->encrypt($message); // now we can use the resulting key and ciphertext, e.g. safe them to the filesystem file_put_contents(__DIR__ . '/key', $key->getKey()); file_put_contents(__DIR__ . '/message', $ciphertext->getString()); } catch (CryptoException $e) { // something went wrong }
解密
use ricwein\Crypto\Ciphertext; use ricwein\Crypto\Symmetric\Crypto; use ricwein\Crypto\Symmetric\Key; use ricwein\Crypto\Exceptions\Exception as CryptoException; use ricwein\Crypto\Exceptions\MacMismatchException; try { $ciphertext = Ciphertext::fromString(file_get_contents(__DIR__ . '/message')); $key = Key::load(file_get_contents(__DIR__ . '/key')); // actual decryption $plaintext = (new Crypto($key))->decrypt($ciphertext); } catch (MacMismatchException $e) { // unable to decrypt message, invalid HMAC } catch (CryptoException $e) { // something else went wrong }
非对称加密
非对称加密使用一对公钥和私钥来加密和签名消息。
发送:通常,消息使用接收者的公钥加密,并使用发送者的私钥签名。
接收:接收者可以使用发送者的公钥验证消息签名(HMAC),并使用自己的私钥解密消息。
以下示例使用两个密钥对(alice和bob),其中私钥在相同的代码作用域内已知。这样做只是为了理解。在实际情况下,一方只知道自己的私钥(公钥不是必需的)和另一方的公钥。
加密
use ricwein\Crypto\Asymmetric\Crypto; use ricwein\Crypto\Asymmetric\KeyPair; use ricwein\Crypto\Exceptions\Exception as CryptoException; try { $message = 'asecretmessage'; $keyAlice = KeyPair::generate(); $keyBob = KeyPair::generate(); // send message from alice to bob $ciphertext = (new Crypto($keyAlice))->encrypt($message, $keyBob->getKey(KeyPair::PUB_KEY)); // it's enough to store the private-keys of our keypairs, public-keys can be derived later if required file_put_contents(__DIR__ . '/alice.key', $keyAlice->getKey(KeyPair::PRIV_KEY)); file_put_contents(__DIR__ . '/bob.key', $keyBob->getKey(KeyPair::PRIV_KEY)); file_put_contents(__DIR__ . '/message', $ciphertext->getString()); } catch (CryptoException $e) { // something went wrong }
解密
use ricwein\Crypto\Ciphertext; use ricwein\Crypto\Asymmetric\Crypto; use ricwein\Crypto\Asymmetric\KeyPair; use ricwein\Crypto\Exceptions\Exception as CryptoException; use ricwein\Crypto\Exceptions\MacMismatchException; try { $keyAlice = KeyPair::load([ KeyPair::PRIV_KEY => file_get_contents(__DIR__ . '/alice.key') ]); $keyBob = KeyPair::load([ KeyPair::PRIV_KEY => file_get_contents(__DIR__ . '/bob.key') ]); $ciphertext = Ciphertext::fromString(file_get_contents(__DIR__ . '/message')); // verify and decrypt the ciphertext // it's enough to pass alice keypair with only a private key here, // the public key will be dynamically derived to verify the ciphertexts HMAC // BUT you can also directly pass alice public-key $plaintext = (new Crypto($keyBob))->decrypt($ciphertext, $keyAlice); } catch (MacMismatchException $e) { // unable to decrypt message, invalid HMAC for alice } catch (CryptoException $e) { // something else went wrong }
编码
密钥导入/导出和密文导入/导出支持四种编码类型,由 ricwein\Crypto\Encoding
提供。
文件加密
此库还提供使用流加密的内存友好的文件加密/解密。要使用集成文件加密,需要 ricwein/filesystem
库。可以使用以下命令安装
composer require ricwein/filesystem
使用方法与对称/非对称加密/解密方法相同,但不是将字符串加密到密文对象中,而是加密文件,返回新的文件对象。
通常,加密文件并替换其明文为新的密文是有用的。应注意,在此情况下,此库会创建一个临时文件,将源文件加密到新临时文件中,然后替换源文件。
所有文件加密方法都支持自定义目标存储,这可以作为 encryptFile()
和 decryptFile()
的最后一个参数提供。如果提供了存储,则跳过之前描述的通过临时文件进行的加密。
对称加密
加密
use ricwein\Crypto\Symmetric\Crypto; use ricwein\Crypto\Symmetric\Key; use ricwein\Crypto\Exceptions\Exception as CryptoException; use ricwein\FileSystem\Exceptions\Exception as FileException; use ricwein\FileSystem\File; use ricwein\FileSystem\Storage; try { $file = new File(new Storage\Disk(__DIR__, 'file.txt')); $key = Key::generate(); // actual encryption $encryptedFile = (new Crypto($key))->encryptFile($file); file_put_contents(__DIR__ . '/key', $key->getKey()); } catch (FileException $e) { // unable to open, read or write the file } catch (CryptoException $e) { // something went wrong }
解密
use ricwein\Crypto\Symmetric\Crypto; use ricwein\Crypto\Symmetric\Key; use ricwein\Crypto\Exceptions\Exception as CryptoException; use ricwein\Crypto\Exceptions\MacMismatchException; use ricwein\FileSystem\Exceptions\Exception as FileException; use ricwein\FileSystem\File; use ricwein\FileSystem\Storage; try { $encryptedFile = new File(new Storage\Disk(__DIR__, 'file.txt')); $key = Key::load(file_get_contents(__DIR__ . '/key')); // actual decryption $file = (new Crypto($key))->decryptFile($encryptedFile); } catch (MacMismatchException $e) { // unable to decrypt message, invalid HMAC } catch (FileException $e) { // unable to open, read or write the file } catch (CryptoException $e) { // something else went wrong }
非对称加密
以下示例使用两个密钥对(alice和bob),其中私钥在相同的代码作用域内已知。这样做只是为了理解。在实际情况下,一方只知道自己的私钥(公钥不是必需的)和另一方的公钥。
加密
use ricwein\Crypto\Asymmetric\Crypto; use ricwein\Crypto\Asymmetric\KeyPair; use ricwein\Crypto\Exceptions\Exception as CryptoException; use ricwein\FileSystem\Exceptions\Exception as FileException; use ricwein\FileSystem\File; use ricwein\FileSystem\Storage; try { $file = new File(new Storage\Disk(__DIR__, 'file.txt')); $keyAlice = KeyPair::generate(); $keyBob = KeyPair::generate(); $plainTextFile = new File(new Storage\Disk(__DIR__, 'file.txt')); // send message from alice to bob $encryptedFile = (new Crypto($keyAlice))->encryptFile($plainTextFile, null, $keyBob); // it's enough to store the private-keys of our keypairs, public-keys can be derived later if required file_put_contents(__DIR__ . '/alice.key', $keyAlice->getKey(KeyPair::PRIV_KEY)); file_put_contents(__DIR__ . '/bob.key', $keyBob->getKey(KeyPair::PRIV_KEY)); } catch (FileException $e) { // unable to open, read or write the file } catch (CryptoException $e) { // something went wrong }
解密
use ricwein\Crypto\Asymmetric\Crypto; use ricwein\Crypto\Asymmetric\KeyPair; use ricwein\Crypto\Exceptions\Exception as CryptoException; use ricwein\Crypto\Exceptions\MacMismatchException; use ricwein\FileSystem\Exceptions\Exception as FileException; use ricwein\FileSystem\File; use ricwein\FileSystem\Storage; try { $keyAlice = KeyPair::load([ KeyPair::PRIV_KEY => file_get_contents(__DIR__ . '/alice.key') ]); $keyBob = KeyPair::load([ KeyPair::PRIV_KEY => file_get_contents(__DIR__ . '/bob.key') ]); $encryptedFile = new File(new Storage\Disk(__DIR__, 'file.txt')); $file = (new Crypto($keyBob))->decryptFile($encryptedFile, null, $keyAlice); } catch (MacMismatchException $e) { // unable to decrypt message, invalid HMAC for alice } catch (FileException $e) { // unable to open, read or write the file } catch (CryptoException $e) { // something else went wrong }