PHP 的 OpenSSL 库

书接上回,在研究 XML 签名之前先研究一下 OpenSSL 库。

签名和原理

PHP 签名的函数原型是:

bool openssl_sign ( string $data , string &$signature , mixed $priv_key_id [, int $signature_alg ] )

大四时学的密码学全忘光了,用 Google CodeSearch 搜了一气 OpenSSL 的源代码才搞明白了签名的原理。

生成签名:

  1. 对 $data 按照 $signature_alg 设置的算法(默认是OPENSSL_ALGO_SHA1)进行 hash 运算
  2. 用私钥加密($priv_key_id)
  3. $signature 就是产生的签名数据,连同 $data 发送给接收方

可用的 hash 算法包括:

  • OPENSSL_ALGO_SHA1
  • OPENSSL_ALGO_MD5
  • OPENSSL_ALGO_MD4
  • OPENSSL_ALGO_MD2

验证:

  1. 用公钥解密签名数据
  2. 解密后的结果是 $data 的 hash 值,接受方再生成 $data 的 hash 值与之对比

签名验证算法

最常见的有两种:基于大数因子分解问题的数字签名(RSA),基于离散对数问题的数字签名(DSA),公私钥分别对应 ~/.ssh/id_rsa & ~/.ssh/id_rsa.pub 和 ~/.ssh/id_dsa & ~/.ssh/id_dsa.pub
二者区别在于 RSA 还可以用于加密,而 DSA 只能用于签名验证,二者签名效率相近,但 RSA 的验证要远快于 DSA。

所以 PHP 中使用 RSA,公私钥可以用 OpenSSL 工具包生成:

openssl genrsa 512 >id_rsa
openssl rsa -pubout id_rsa.pub

我在 .ssh 目录下的 RSA 公私钥是用 ssh-keygen 生成的,但在在这里做试验失败,可能于密钥长度有关系。

验证函数原型:

int openssl_verify  (  string $data  ,  string $signature  ,  mixed $pub_key_id  [,  int $signature_alg = OPENSSL_ALGO_SHA1  ] )

很好理解,$data 是接受方获取的数据,$signature 是一起发过来的签名,$pub_key_id 是校验用的公钥,$signature_alg 就是前面制定的 hash 算法了。

加密

函数原型:

int openssl_seal  ( string $data  , string &$sealed_data  , array &$env_keys  , array $pub_key_ids  )
  1. 用随机字符串加密 data ( RC4 加密算法)
  2. 用 pub_key_ids 里的公钥对共享密钥进行加密,将结果保存在 env_keys
  3. 将 env_keys 和 sealed_data 发送给接收方

解密

函数原型:

bool openssl_open  ( string $sealed_data  , string &$open_data  , string $env_key  , mixed $priv_key_id  )
  1. 私钥揭开 env_key
  2. 用 env_key 打开加密消息

用 PHP 创建公私钥

function get_key_pair() {
    $ret = array();
    $res = openssl_pkey_new();
    openssl_pkey_export($res, $ret['private_key']);
    $pub_key = openssl_pkey_get_details($res);
    $ret['public_key'] = $pub_key['key'];
    return $ret;
}

One comment to PHP 的 OpenSSL 库

  1. tonny says:

    你好,能不能请教一下,在进行证书验证的时候,出现如下错误error:04091077:rsa routines:INT_RSA_VERIFY:wrong signature length 时什么原因?
    代码如下: $pub_key_id=openssl_get_publickey($pub_key);
    $detail=openssl_pkey_get_details($pub_key_id);

    $verify_result=openssl_verify($data,$sign,$pub_key_id);

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>