zoukankan      html  css  js  c++  java
  • PHP通过OpenSSL生成证书、密钥并且加密解密数据,以及公钥,私钥和数字签名的理解

    一、公钥加密

    假设一下,我找了两个数字,一个是1,一个是2。我喜欢2这个数字,就保留起来,不告诉你们(私钥),然后我告诉大家,1是我的公钥。

    我有一个文件,不能让别人看,我就用1加密了。别人找到了这个文件,但是他不知道2就是解密的私钥啊,所以他解不开,只有我可以用
    数字2,就是我的私钥,来解密。这样我就可以保护数据了。

    我的好朋友x用我的公钥1加密了字符a,加密后成了b,放在网上。别人偷到了这个文件,但是别人解不开,因为别人不知道2就是我的私钥,
    只有我才能解密,解密后就得到a。这样,我们就可以传送加密的数据了。

    二、私钥签名

    如果我用私钥加密一段数据(当然只有我可以用私钥加密,因为只有我知道2是我的私钥),结果所有的人都看到我的内容了,因为他们都知道我的公钥是1,那么这种加密有什么用处呢?

    但是我的好朋友x说有人冒充我给他发信。怎么办呢?我把我要发的信,内容是c,用我的私钥2,加密,加密后的内容是d,发给x,再告诉他
    解密看是不是c。他用我的公钥1解密,发现果然是c。
    这个时候,他会想到,能够用我的公钥解密的数据,必然是用我的私钥加的密。只有我知道我得私钥,因此他就可以确认确实是我发的东西。
    这样我们就能确认发送方身份了。这个过程叫做数字签名。当然具体的过程要稍微复杂一些。用私钥来加密数据,用途就是数字签名

    总结:公钥和私钥是成对的,它们互相解密。

    公钥加密,私钥解密。

    私钥数字签名,公钥验证

    准备工作

    找到php.ini 去掉openssl.dll前面的';'。找到openssl.cnf的位置,我的在D:xamppapacheconf。
    配置apache以支持SSL:打开apache的配置文件conf/httpd.conf
    LoadModule ssl_module modules/mod_ssl.so、Include conf/extra/httpd-ssl.conf

    三、示例代码

     1 $config = array(
     2     "private_key_bits" => 1024,                     //字节数    512 1024  2048   4096 等
     3     "private_key_type" => OPENSSL_KEYTYPE_RSA,     //加密类型
     4     "config" => "D:/phpStudy/PHPTutorial/Apache/conf/openssl.cnf"
     5 );
     6 
     7 $privkeypass = '123456789'; //私钥密码
     8 $numberofdays = 365;     //有效时长
     9 $cerpath = "./test.cer"; //生成证书路径
    10 $pfxpath = "./test.pfx"; //密钥文件路径
    11 
    12 $dn = array(    
    13     "countryName" => "UK",                                  //所在国家
    14     "stateOrProvinceName" => "Somerset",                    //所在省份
    15     "localityName" => "Glastonbury",                        //所在城市
    16     "organizationName" => "The Brain Room Limited",         //注册人姓名
    17     "organizationalUnitName" => "PHP Documentation Team",   //组织名称
    18     "commonName" => "Wez Furlong",                          //公共名称
    19     "emailAddress" => "wez@example.com"                     //邮箱
    20 );
    21 
    22 // 生成公钥私钥资源
    23 $res = openssl_pkey_new($config);
    24 
    25 // 导出私钥 $priKey
    26 openssl_pkey_export($res, $priKey,null,$config);
    27 
    28 //  导出公钥 $pubKey
    29 $pubKey = openssl_pkey_get_details($res);
    30 $pubKey = $pubKey["key"];
    31 //print_r($priKey); 私钥
    32 //print_r($pubKey); 公钥
    33 
    34 //直接测试私钥 公钥
    35 echo '-------------------公私钥加解密-START---------------------','<br>';
    36 $data = '测试公私钥加解密成功!';
    37 // 公钥加密
    38 openssl_public_encrypt($data, $encrypted, $pubKey);
    39 // 私钥解密
    40 openssl_private_decrypt($encrypted, $decrypted, $priKey);
    41 
    42 echo '公钥加密:',base64_encode($encrypted),'私钥解密:','<br>',$decrypted,'<br>';
    43 echo '-------------------公私钥加解密-END---------------------','<br>';
    44 
    45 //生成文件
    46 $csr = openssl_csr_new($dn, $priKey,$config); //基于$dn生成新的 CSR (证书签名请求)
    47 $sscert = openssl_csr_sign($csr, null, $priKey, 365,$config);//根据配置自己对证书进行签名
    48 openssl_x509_export($sscert, $csrkey); //将公钥证书存储到一个变量 $csrkey,由 PEM 编码格式命名。
    49 openssl_pkcs12_export($sscert, $privatekey, $priKey, $privkeypass); //将私钥存储到名为的出 PKCS12 文件格式的字符串。 导出密钥$privatekey
    50 
    51 //生成证书文件
    52 $fp = fopen($cerpath, "w");
    53 fwrite($fp, $csrkey);
    54 fclose($fp);
    55 //生成密钥文件
    56 $fp = fopen($pfxpath, "w");
    57 fwrite($fp, $privatekey);
    58 fclose($fp);
    59 
    60 
    61 echo '<br>','<br>','<br>','<br>';
    62 echo '----------------------自签名验证-START----------------------','<br>';
    63 // 测试私钥 秘钥
    64 $privkeypass = '123456789'; //私钥密码
    65 $pfxpath = "./test.pfx"; //密钥文件路径
    66 $priv_key = file_get_contents($pfxpath); //获取密钥文件内容
    67 $data = "测试数据!"; //加密数据测试test
    68 //私钥加密
    69 openssl_pkcs12_read($priv_key, $certs, $privkeypass); //读取公钥、私钥
    70 $prikeyid = $certs['pkey']; //私钥
    71 openssl_sign($data, $signMsg, $prikeyid,OPENSSL_ALGO_SHA1); //注册生成加密信息
    72 $signMsg = base64_encode($signMsg); //base64转码加密信息
    73 
    74 
    75 //公钥解密
    76 $unsignMsg=base64_decode($signMsg);//base64解码加密信息
    77 openssl_pkcs12_read($priv_key, $certs, $privkeypass); //读取公钥、私钥
    78 $pubkeyid = $certs['cert']; //公钥
    79 $res = openssl_verify($data, $unsignMsg, $pubkeyid); //验证
    80 echo $res?'证书测试成功!':'证书测试失败!';echo '<br>'; //输出验证结果,1:验证成功,0:验证失败
    81 
    82 echo '-----------------------签名验证-END------------------------','<br>';

    openssl_sign 默认signature_alg参数是OPENSSL_ALGO_SHA1

      如果使用DSA加密方式需要使用OPENSSL_ALGO_DSS1参数

      signature_alg 其他参数

      OPENSSL_ALGO_DSS1 (integer)

      OPENSSL_ALGO_SHA1 (integer)

      OPENSSL_ALGO_SHA224 (integer)

      OPENSSL_ALGO_SHA256 (integer)

      OPENSSL_ALGO_SHA384 (integer)

      OPENSSL_ALGO_SHA512 (integer)

      OPENSSL_ALGO_RMD160 (integer)

      OPENSSL_ALGO_MD5 (integer)

      OPENSSL_ALGO_MD4 (integer)

      OPENSSL_ALGO_MD2 (integer)

    过程出现的问题集锦:http://blog.sina.com.cn/s/blog_8da982ac0101lqh1.html

    特别说明:

    x509,公钥证书,只有公钥。
    p7,签名或加密。可以往里面塞x509,同时没有签名或加密内容。
    p12,含有私钥,同时可以有公钥,有口令保护。
    p7的作用就是电子信封。
    X509是基本规范
    P7和P12是两个实现规范,P7是数字信封,P12是带有私钥的证书规范。
    x509是数字证书的规范,P7和P12是两种封装形式。比如说同样的电影,有的是avi格式,有的是mpg,大概就这个意思。

    P7一般是把证书分成两个文件,一个公钥一个私钥,有PEM和DER两种编码方式。PEM比较多见,就是纯文本的,P7一般是分发公钥用,看到的就是一串可见字符串,扩展名经常是.crt,.cer,.key等。DER是二进制编码。
    P12是把证书压成一个文件,.pfx 。主要是考虑分发证书,私钥是要绝对保密的,不能随便以文本方式散播。所以P7格式不适合分发。.pfx中可以加密码保护,所以相对安全些。
    在实践中要中,用户证书都是放在USB Key中分发,服务器证书经常还是以文件方式分发。服务器证书和用户证书,都是X509证书,就是里面的属性有区别。

    X509 是证书规范
    PKCS#7 是消息语法 (常用于数字签名与加密)
    PKCS#12 个人消息交换与打包语法 (如.PFX .P12)打包成带公钥与私钥

  • 相关阅读:
    题目
    先贤祠3
    先贤祠2
    先贤祠1
    论文他引次数及ESI高被引论文查询方法
    [唐诗]古风(其三十一)-李白
    [唐诗]古风(其二十四)-李白
    [唐诗]古风(其十九)-李白
    [唐诗]古风(其十五)-李白
    [唐诗]古风(其三)-李白
  • 原文地址:https://www.cnblogs.com/jinxiblog/p/7905315.html
Copyright © 2011-2022 走看看