PHP Conference Japan 2024

OpenSSL 函数

目录

添加注释

用户贡献注释 24 条注释

dan -AT- NOSPAM danschafer DOT netTT
17 年前
目前,PHP 中定义的所有 OpenSSL 函数仅使用 PEM 格式。使用以下代码在 DER 和 PEM 之间进行转换。

<?php
$pem_data
= file_get_contents($cert_path.$pem_file);
$pem2der = pem2der($pem_data);

$der_data = file_get_contents($cert_path.$der_file);
$der2pem = der2pem($der_data);

function
pem2der($pem_data) {
$begin = "CERTIFICATE-----";
$end = "-----END";
$pem_data = substr($pem_data, strpos($pem_data, $begin)+strlen($begin));
$pem_data = substr($pem_data, 0, strpos($pem_data, $end));
$der = base64_decode($pem_data);
return
$der;
}

function
der2pem($der_data) {
$pem = chunk_split(base64_encode($der_data), 64, "\n");
$pem = "-----BEGIN CERTIFICATE-----\n".$pem."-----END CERTIFICATE-----\n";
return
$pem;
}
?>
skippy zuavra net
20年前
如果您想知道用于 cainfo 的“正确哈希”目录是什么:它只是一个目录,其中包含 PEM/X.509 格式的 CA 公钥证书。您可以从 CA 的网站(他们在显眼位置宣传它)或从您的浏览器获取此类证书。例如,在资源管理器中,您可以单击小黄锁,转到 CA 条目并将其导出。

该目录的唯一技巧是文件名必须采用“hash.#”的形式。“hash”部分是证书的 8 位十六进制哈希值,“#”部分是一个数字,用于区分产生相同哈希值的证书(是的,来自同一 CA 的证书可能会发生这种情况)。通常 # 为 0,但是当有多个具有相同哈希值的证书时,您也可以使用 1、2 等。

为了获取证书的哈希值,您可以使用 openssl 命令行实用程序,如下所示:

openssl x509 -hash -in certfile.cer | head -1
peter dot mescalchin @ geemail dot com
18年前
对于 w32 用户启用 OpenSSL 支持。除了将“libeay32.dll”复制到 windows system32 文件夹外,还需要复制“ssleay32.dll”。上面的文档可能应该更新以注意这一点。

此要求已记录在 libcurl 页面上

http://curl.haxx.se/libcurl/php/install.html#windows
kraven at kraven dot org
11年前
如果您想验证 CSR 是否已通过您的私钥正确生成,您可以执行以下操作:

<?php
$countryName
= "UK";
$stateOrProvinceName = "London";
$localityName = "Blah";
$organizationName = "Blah1";
$organizationalUnitName = "Blah2";
$commonName = "Joe Bloggs";
$emailAddress = "[email protected]";

$dn = array(
"countryName" => $countryName,
"stateOrProvinceName" => $stateOrProvinceName,
"localityName" => $localityName,
"organizationName" => $organizationName,
"organizationalUnitName" => $organizationalUnitName,
"commonName" => $commonName,
"emailAddress" => $emailAddress
);

$badPriv = 'foo';

// 生成错误的 CSR
$badCsr = openssl_csr_new($dn, $badPriv);

// 生成私钥
$priv = openssl_pkey_new();

// 生成 CSR
$csr = openssl_csr_new($dn, $priv);

$badCsrDetails = openssl_pkey_get_details(openssl_csr_get_public_key($badCsr));
$privDetails = openssl_pkey_get_details($priv);
$csrDetails = openssl_pkey_get_details(openssl_csr_get_public_key($csr));

echo
md5($badCsrDetails['rsa']['n']);
echo
"\n不匹配\n";
echo
md5($privDetails['rsa']['n']);
echo
"\n匹配\n";
echo
md5($csrDetails['rsa']['n']);
echo
"\n";
?>

此输出是模数的 md5 哈希值。可以使用 openssl 完成相同的检查
openssl rsa -noout -modulus -in server.key | openssl md5
openssl req -noout -modulus -in server.csr | openssl md5
jts
17 年前
Win32 用户在使 php_openssl 工作时遇到麻烦,应该确保他们用 PHP 中包含的版本替换所有版本的 libeay32.dll 和 ssleay32.dll。在同时使用 Apache2 和 OpenSSL 时尤其如此,因为某些 OpenSSL win32 包包含这些文件的较旧版本。
greensweater
19年前
“您需要安装有效的 openssl.cnf 才能使此函数正常运行”包括大多数 openssl 函数。您可以强制 php 找到您的 openssl.cnf 文件,如下所示:

$config = array('config'=>'/path/to/openssl.cnf');
$pkey = openssl_pkey_new($config);
$csr = openssl_csr_new('MyCSR',$pkey,$config);
rahuul at yours dot com
14年前
要更改证书的序列号,解决方案如下:

<?php
$sscert
= openssl_csr_sign($csr, $cacert, $privkey, $days,$config,$serial);
?>
yabba dabba
18年前
适用于 Windows/IIS 的 php4 发行版有一个 README-SSL.txt,它强烈暗示只需将路径添加到服务器环境变量中的 OPENSLL_CONF 变量中即可。确保也添加文件名和扩展名。

例如:c:\php-4.3.11\openssl\openssl.cnf
web at mburda dot com
16年前
下面 Matt Alexander 的代码有点问题。
公钥和私钥都在内部生成并保存到 OpenSSL 类对象的属性中,但随后只使用私钥。
公钥取自外部文件,如果它与内部存储的公钥不同,OpenSSL 将无法解密文本。
stephen_at_liberty-irm_dot_com
16年前
本笔记主要面向将加密数据存储在 MySQL 中的用户,因为我不熟悉其他数据库的设置。例如,如果您存储用 openssl_public_encrypt 加密后的信用卡号码,则存储该号码的列的数据类型必须为 blob。这是因为“结果可能包含任意字节值”(MySQL 参考手册)。基本上,如果您尝试将其存储在 VARCHAR、LONGTEXT 等类型中,则加密数据的部分内容可能会被丢弃、截断等。这当然会使数据无法解密。希望这对某些人有所帮助,因为它让我困惑了大约一个小时!
karel dot wintersky at gmail dot com
7年前
可能对密码执行速度有用。

<?php
// 需要 PHP 7.0+!
// 查看结果:https://gist.github.com/KarelWintersky/fe29dcad75de515e5a468894e7c070e6

const TEST_COUNT = 100000;
const
SOURCE = '请注意,帖子中不允许使用 HTML 标签,但保留笔记格式。';
const
KEY = "password";

function
TESTER( $testing_function, $argument )
{
$t = microtime(true);

for (
$test_iterator = 0; $test_iterator < TEST_COUNT; $test_iterator++) {
$testing_function( $argument );
}
return
round(microtime(true) - $t, 4);
}

$crypt = function($cipher) {
$ivlen = openssl_cipher_iv_length($cipher);
$iv = openssl_random_pseudo_bytes($ivlen);
openssl_encrypt(SOURCE, $cipher, KEY, $options=0, $iv);
};

$methods = openssl_get_cipher_methods(false);

array_splice( $methods, 0, count($methods) / 2);

$timings = array();

foreach (
$methods as $cypher) {
$time = TESTER( $crypt, $cypher );
$timings[ $cypher ] = $time;
echo
str_pad($cypher, 40, ' ', STR_PAD_LEFT), "耗时 ", str_pad($time, 8, STR_PAD_LEFT), ' 秒。 ', PHP_EOL;
}

uasort($timings, function($a, $b){
return
$a <=> $b;
});

$min_time = round(reset($timings) / TEST_COUNT, 7);
$min_cypher = key($timings);

$max_time = round(end($timings) / TEST_COUNT, 7);
$max_cypher = key($timings);

echo
'-------------', PHP_EOL;
echo
"总测试次数:", count($timings), PHP_EOL;
echo
"最大耗时: "{$max_time} 秒,算法为 `{$max_cypher}`.", PHP_EOL;
echo
"最小耗时: "{$min_time} 秒,算法为 `{$min_cypher}`.", PHP_EOL;

echo
'详情: ', PHP_EOL;

foreach (
$timings as $m => $t) {
echo
'- ', str_pad($t, 8, STR_PAD_LEFT), " 秒,算法为 `{$m}`", PHP_EOL;
}

echo
PHP_EOL;
kurian at net4ideas dot com
17 年前
要在 Windows 平台 IIS Web 服务器上运行 openssl,需要在 php.ini 中启用它,然后将 libeay32.dll 和 ssleay32.dll 复制到 php 文件夹(或 Windows 的 system32 文件夹),并将这两个 dll 的路径添加到 Windows 的 PATH 环境变量中。在我进行了这些更改后,它似乎可以正常工作。
matt at NOSPAMopenflowsPLEASE dot org
19年前
在 Debian 3.0(woody)版本中,openssl 函数被禁用,但从 3.1(sarge)版本开始,它们又可用了。
greensweater
19年前
抱歉,我之前笔记中的代码无法运行……最后一行应该写成

$csr = openssl_csr_new(array('commonName'=>'MyCSR'),$pkey,$config);
匿名
4年前
对第一个注释的改进,此函数在将 PEM 格式转换为 DER 格式时将正确处理证书链。

<?php

function pemToDer(string $pem_data): string
{
$der_data = '';

$begin = "-----BEGIN CERTIFICATE-----";
$end = "-----END CERTIFICATE-----";
while (
strpos($pem_data, $begin) !== false) {
$pem_data = substr($pem_data, strpos($pem_data, $begin) + strlen($begin));
$der_data .= substr($pem_data, 0, strpos($pem_data, $end));
$pem_data = substr($pem_data, strpos($pem_data, $end) + strlen($end));
}

return
base64_decode($der_data);
}
jaz at ensn dot net
20年前
给新手(像我一样)
如果你想在 win32 系统上尝试,你可以学习如何在该网址上安装 apache+ssl:http://tud.at/programm/apache-ssl-win32-howto.php3

提供英文、西班牙文和法文版本。

我刚刚阅读并安装,运行完美。
norman at rasmussen dot org
20年前
Debian维护者已禁用openssl支持,因为它似乎会导致apache在启动时崩溃。(http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=193343http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=165699

- Norman
daevid at daevid dot com
17 年前
这里似乎没有函数可以测试证书是否有效(即不损坏)……这段bash代码应该会有帮助。抱歉,它不是PHP。把它放在system()调用中,或者把它做成bash脚本并那样调用它……

if [ "`openssl x509 -in /etc/certs/my.crt -noout -modulus`" = "`openssl rsa -in /etc/keys/my.key -noout -modulus`" ]; then echo "Match"; else echo "Different"; fi
Richard Ablewhite
18年前
警告Windows用户,您需要在system32目录下放置以下文件:

msvcr71.dll

它必须放在system32目录下,php/dlls目录中的文件不会被自动加载。
ChronoFish
17 年前
下面有一条说明,关于在Win32系统上需要将ssleay32.dll和libeay32.dll都复制到系统PATH环境变量指定的目录下。

这是绝对正确的。还应该注意的是,Windows会在搜索PATH环境变量指定的目录之前搜索Windows系统目录。如果这些目录中已经有同名.dll文件——请重命名(而不是删除,以防您需要撤销更改)它们,然后复制最新版本的这些文件。

关键位置可能包括/i386、/windows/system32和~/apache/…/modules目录。

我还更新了我的~/subversion/bin目录。

-CF
igor dot gorshkov at gmail dot com
17 年前
我这样生成证书:

$config = array("config" => "d:/sslcert/openssl.cnf");
$dn = array(
"countryName" => "RU",
"stateOrProvinceName" => "Russia",
"localityName" => "Saint-Petersburg",
"organizationName" => "temp",
"organizationalUnitName" => "temp",
"commonName" => "temp",
"emailAddress" => "[email protected]"
);
$privkey_enc = openssl_pkey_new($config);
$csr = openssl_csr_new($dn, $privkey_enc, $config);
$sscert = openssl_csr_sign($csr, null, $privkey_enc, 365);
openssl_x509_export_to_file($sscert, "d:/cert_enc.crt");
openssl_pkey_export_to_file($privkey_enc, "d:/privkey_enc.pem");

结果所有生成的证书都有相同的序列号(00)。但这不应该发生!如何避免这种情况?
mattalexx at gmail dot com
17 年前
使用此代码进行简单的公钥/私钥加密。

<?php

/**
* 指向你的配置文件
*
*/
define("OPEN_SSL_CONF_PATH", "/usr/share/ssl/openssl.cnf");
/**
* 证书有效期长度(以天为单位)
*
*/
define("OPEN_SSL_CERT_DAYS_VALID", 365);
/**
* 私钥所需的密码
*
*/
define("OPEN_SSL_PASSPHRASE", "lkdfjbjeyrasdfvkajwdeblsolkdkdjfbvzslalsmdbfvksb");
/**
* 在此处输入描述...
*
*/
define("OPEN_SSL_PUBKEY_PATH", "/docs/domains/mywebsite.com/docs/key.pem"); // 公钥路径

/**
* 一个简单的PHP OpenSSL函数子集的包装类。用于公钥加密作业。
*
* <code>
*
* // 配置方法
* // 1. 将OPEN_SSL_CONF_PATH设置为openssl.cnf文件的路径。
* // 2. 将OPEN_SSL_PASSPHRASE设置为任何密码。
* // 3. 使用OpenSSL::do_csr方法生成你的私钥和公钥(见下一节)。
* // 4. 将私钥保存在离线位置,将公钥保存在这台机器上。
* // 5. 将OPEN_SSL_PUBKEY_PATH设置为公钥的路径。
*
* // 生成密钥
* $ossl = new OpenSSL;
* $ossl->do_csr();
* $privatekey = $ossl->privatekey;
* $publickey = $ossl->publickey;
* unset($ossl);
*
* // 加密
* $text = "Secret text";
* $ossl = new OpenSSL;
* $ossl->encrypt($text);
* $encrypted_text = $ossl->crypttext;
* $ekey = $ossl->ekey;
* unset($ossl);
*
* // 解密
* $ossl = new OpenSSL;
* $decrypted_text = $ossl->decrypt($encrypted_text, $privatekey, $ekey);
* unset($ossl);
*
* @author Matt Alexander ([email protected]) [基于Alex Poole ([email protected])的代码]
* @copyright 2007
*
*/
class OpenSSL {

public
$privatekey;
public
$publickey;
public
$csr;
public
$crypttext;
public
$ekey;

public function
encrypt($plain) {

// 将公钥转换为资源
$publickey = openssl_get_publickey(is_file(OPEN_SSL_PUBKEY_PATH)? file_get_contents(OPEN_SSL_PUBKEY_PATH) : OPEN_SSL_PUBKEY_PATH);

// 加密
openssl_seal($plain, $crypttext, $ekey, array($publickey));
openssl_free_key($publickey);

// 设置值
$this->crypttext = $crypttext;
$this->ekey = $ekey[0];
}

public function
decrypt($crypt, $privatekey, $ekey="") {

// 将私钥转换为资源
$privatekey = openssl_get_privatekey((is_file($privatekey)? file_get_contents($privatekey) : $privatekey), OPEN_SSL_PASSPHRASE);

// 解密
openssl_open($crypt, $plaintext, $ekey, $privatekey);
openssl_free_key($privatekey);

// 返回值
return $plaintext;
}

public function
do_csr(
$countryName = "UK",
$stateOrProvinceName = "London",
$localityName = "Blah",
$organizationName = "Blah1",
$organizationalUnitName = "Blah2",
$commonName = "Joe Bloggs",
$emailAddress = "[email protected]"
) {
$dn = array(
"countryName" => $countryName,
"stateOrProvinceName" => $stateOrProvinceName,
"localityName" => $localityName,
"organizationName" => $organizationName,
"organizationalUnitName" => $organizationalUnitName,
"commonName" => $commonName,
"emailAddress" => $emailAddress
);
$config = array(
"config" => OPEN_SSL_CONF_PATH
);
$privkey = openssl_pkey_new();
$csr = openssl_csr_new($dn, $privkey, $config);
$sscert = openssl_csr_sign($csr, null, $privkey, OPEN_SSL_CERT_DAYS_VALID, $config);
openssl_x509_export($sscert, $this->publickey);
openssl_pkey_export($privkey, $this->privatekey, OPEN_SSL_PASSPHRASE, $config);
openssl_csr_export($csr, $this->csr);
}

}

?>
php ~at~ wwwcrm dot komm
19年前
如果您想在不需要了解Open SSL扩展的来龙去脉的情况下使用PHP进行公钥/私钥加密作业,以下内容可能会让您感兴趣:

http://www.karenandalex.com/php_stuff/_class_OpenSSL.phps

这个类在一段时间内不可用(服务器问题),但现在已经恢复了。对于那些点击并得到404错误的用户,我们深表歉意。

希望它对您有用……

Alex
beckman at purplecow dot com
19年前
FreeBSD Ports树php5-openssl使用openssl-0.9.8a。这是一个问题,因为如果您安装这两个端口并尝试在PHP中打开HTTPS URL,它将使用openssl_error_string()返回以下错误:error:140A90A1:SSL routines:func(169):reason(161),即SSL_R_LIBRARY_HAS_NO_CIPHERS或“库没有密码”。

这是因为 openssl 库现在要求您手动加载密码——不会自动为您加载所有密码。

我相信 php5-openssl 模块在打开 SSL 连接之前没有更新过这样做(截至 5.0.5 版本)。

使用 openssl-0.9.7i 似乎有效;将 libcrypto.so.3 符号链接到 libcrypto.so.4 可以防止 php5-openssl 端口尝试安装 openssl-0.9.8a。因此,首先从 ports 安装 openssl-stable (0.9.7i),其次创建符号链接,然后安装 php5-openssl,这样应该就可以了。
To Top