ricwein/crypto

基于libsodium的加密库

2.1.1 2021-04-27 12:28 UTC

This package is auto-updated.

Last update: 2024-09-27 20:05:27 UTC


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
}