在PHP中使用PGP加密文件?

27
我想使用PGP加密来对CSV文件进行加密,我会通过PHP脚本生成该文件,然后通过电子邮件将其发送给客户端。客户将提供给我加密密钥,我需要使用该密钥来加密文件。
我在谷歌上搜索了关于PGP的内容,发现它是“Pretty Good Privacy”的缩写,同时还发现了OpenPGP http://www.openpgp.org/ 和 GnuPG http://www.gnupg.org/ 这两种PGP类型,这两者有什么区别?我应该使用哪一种?
同时,如何使用客户提供的密钥在PHP中使用PGP加密文件呢?
我第一次听到这个术语,有人可以帮助我理解并在PHP中实现吗?
2个回答

51

问题1:关于PGP

  • PGP(Pretty Good Privacy)是Symantec公司的产品和商标(几年前他们收购了它)。
  • OpenPGP是PGP使用的标准。
  • GnuPG(Gnu隐私卫士)是PGP的一个免费且开源的实现。

因此,你想要加密到一个OpenPGP密钥。你的客户端使用哪个OpenPGP实现来解密数据并不重要。在PHP中,通常使用GnuPG,并内置了接口。

问题2:在PHP中使用GnuPG

使用GnuPG接口,这是可以安装到PHP的扩展。

首先,导入密钥,其中$keydata是ASCII装甲公钥:

<?php
$gpg = new gnupg();
$info = $gpg -> import($keydata);
print_r($info);
?>

然后使用这个密钥对数据进行加密,这一次使用客户端密钥的指纹:

<?php
  $gpg = new gnupg();
  $gpg -> addencryptkey("8660281B6051D071D94B5B230549F9DC851566DC");
  $enc = $gpg -> encrypt("just a test");
  echo $enc;
?>
如果你想加密文件,请阅读并将其传递给encrypt()。请确保在引用密钥时使用至少长的密钥ID(例如DEADBEEFDEADBEEF),最好使用指纹(如示例所示);并不要使用短密钥ID(DEADBEEF,因为这些易受碰撞攻击的影响。

这是一个更全面的例子,同时进行了加密和解密操作,由PHP手册中的用户添加。


之后我该如何将它发送到邮件中呢?我应该将$enc变量直接作为邮件正文发送,然后PGP启用的电子邮件软件就能自行读取它了吗?还是说我需要采取其他措施来发送这封邮件呢? - djmzfKnm
我不确定客户是否要求使用PGP加密文件并通过电子邮件发送。 - djmzfKnm
澄清:addencryptkey需要指纹。您可以使用gpg -fingerprint {user_id}获取用户的指纹。 - Matthew
这似乎是一个很好的新问题候选人。确保提供最小的示例(“最短的可重现问题的代码”)。您是否省略了警告和错误消息?该函数应返回一个字符串(或FALSE),但空字符串永远不应发生。 - Jens Erat
如果我使用这段代码只是打印信息,我总是会得到FALSE。我试过使用客户端的公钥作为密钥数据和我的公钥,每次输出都是FALSE。<?php $gpg = new gnupg(); $info = $gpg -> import($keydata); print_r($info); ?> - Asit
显示剩余6条评论

5

我在这里留下一个答案,因为网络上PHP GnuPG的许多示例都非常基础,希望这能为某些人节省一些沮丧。

基本上,它反映了GnuPG命令行工具的工作方式。如果密钥尚未在gpg的密钥环中,则需要导入密钥,然后需要选择用于加密/解密的接收者密钥。

gpg --import recipients-public-key.asc
gpg -r recipient --encrypt test.txt

如果您像我一样将密钥作为收件人传递,那么它不起作用!在GPG手册PHP文档中都不清楚这个字段是什么,它被称为“指纹”。请检查gpg的密钥环,查看您刚导入的密钥。
gpg --list-keys

这将输出类似于以下内容:
pub   rsa2048 2019-04-14 [SC] [expires: 2021-04-14]
      0DAA2C747B1974BE9EB9E6DCF7EE249AD00A46AA
uid           [ultimate] Dean Or
sub   rsa2048 2019-04-14 [E] [expires: 2021-04-14]

这将提供给您每个密钥的UID和指纹。据我所知,您可以使用UID和指纹作为接收者。 因此,您的PHP加密代码可能如下所示:
// Encrypt
$gpg = new gnupg();
$gpg->seterrormode(gnupg::ERROR_EXCEPTION);

// Check key ring for recipient public key, otherwise import it
$keyInfo = $gpg->keyinfo('0DAA2C747B1974BE9EB9E6DCF7EE249AD00A46AA');
if (empty($keyInfo)) {
    $gpg->import('recipients-public-key.asc');
}
$gpg->addencryptkey('0DAA2C747B1974BE9EB9E6DCF7EE249AD00A46AA');
echo $gpg->encrypt('This is a test!');

然后收件人的代码将如下所示:
// Decrypt
$gpg = new gnupg();
$gpg->seterrormode(gnupg::ERROR_EXCEPTION);

// Check key ring for recipient private key, otherwise import it
$keyInfo = $gpg->keyinfo('0DAA2C747B1974BE9EB9E6DCF7EE249AD00A46AA');
if (empty($keyInfo)) {
    $gpg->import('recipients-private-key.asc');
}
$gpg->adddecryptkey('0DAA2C747B1974BE9EB9E6DCF7EE249AD00A46AA', '');
echo $gpg->decrypt($encyptedMessage);

请注意,接收者的公钥和私钥的指纹是相同的。
adddecryptkey 存在一个已知问题,无法输入密码!您需要删除密码或更改您的 GnuPG 版本。

我也尝试过对CSV文件进行加密,但没有找到解决方案。我的要求是将CSV文件加密并放入SFTP中。在PHP中,我们只能进行消息级别的加密。 - Naveen BT

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接