zoukankan      html  css  js  c++  java
  • 用基于openssl产生的密钥实现PHP和.NET端的RSA加解密互通

    用openssl产生密钥对的方法:

    下载openssl进入其中的bin目录,运行openssl.exe,并分别执行以下命令:

    genrsa -out rsa_private_key.pem 1024
    pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM -nocrypt -out private_key.pem
    rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem

    这将会在bin文件夹下生成两个pem文件rsa_private_key.pem和rsa_public_key.pem,这两个文件中分别存放了私钥和公钥。

    PHP端单独实现RSA的方法:

    进入php.ini,将extension=php_openssl.dll前面的分号(注释)去掉,重启wamp(使用的这个),就可以在PHP中使用openssl拓展函数了。

    完整PHP测试代码如下

    <?php
    header("Content-Type: text/html; charset=utf-8");
    $rsaKey = new RSAKey();
    $privateKey = $rsaKey->getPrivateKey();
    $publicKey = $rsaKey->getPublicKey();
    
    $pi_key =  openssl_pkey_get_private("这里填用openssl生成的私钥字符串");
    $pu_key = openssl_pkey_get_public("这里填用openssl生成的公钥字符串");
    
    $data = "一段明文";
    $encrypted = "";
    $decrypted = "";
    
    echo "原始数据:".$data."<BR>";
    
    /**
    私钥加密,公钥解密
    */
    echo "私钥加密:<br>";
    openssl_private_encrypt($data,$encrypted,$pi_key);//私钥加密
    $encrypted = base64_encode($encrypted);//将机密后的字符串用base64转义一下,方便个别特殊字符的传输
    echo $encrypted."<br>";
    
    echo "公钥解密:<br>";
    openssl_public_decrypt(base64_decode($encrypted),$decrypted,$pu_key);//公钥解密
    echo $decrypted."<br>";
    
    
    /**
    公钥加密,私钥解密
    */
    echo "公钥加密:<br>";
    openssl_public_encrypt($data,$encrypted,$pu_key);//公钥加密
    $encrypted = base64_encode($encrypted);
    
    echo "私钥解密:<br>";
    openssl_private_decrypt(base64_decode($encrypted),$decrypted,$pi_key);//私钥解密
    echo $decrypted."<br>";
    ?>
    

    上面的代码是可以成功的,但是在实际中会遇到这样一种情况

    公司A有一个软件外包给公司B做了,那边用的是.net,公司这边运行的是PHP。

    现在A生成了私钥和公钥,并将公钥提供给B,请问B用直接用.net中的rsa加密函数出来的密文,A是不能用php直接解出来的

    这是由于.net中的RSA加解密是根据xml来实现的,也就是说参数的格式不同,要实现两种语言之间的互通,需要先将A提供给B的公钥进行转化下,转成.net可用的RSAParameter

    以下是参考网上的http://www.cnblogs.com/thinhunan/archive/2009/09/10/ConvertPem2048ToRSAParemeters.html,感谢该作者

    using System;
    using System.Text;
    using System.Security.Cryptography;
    using System.Web;
    using System.IO;
    
    namespace Thinhunan.Cnblogs.Com.RSAUtility
    {
        /// <summary>
        /// Author http://thinhunan.cnblogs.com
        /// </summary>
        public class PemConverter
        {
            /// <summary>
            /// 将pem格式公钥(1024 or 2048)转换为RSAParameters
            /// </summary>
            /// <param name="pemFileConent">pem公钥内容</param>
            /// <returns>转换得到的RSAParamenters</returns>
            public static RSAParameters ConvertFromPemPublicKey(string pemFileConent)
            {
                if (string.IsNullOrEmpty(pemFileConent))
                {
                    throw new ArgumentNullException("pemFileConent", "This arg cann't be empty.");
                }
                pemFileConent = pemFileConent.Replace("-----BEGIN PUBLIC KEY-----", "").Replace("-----END PUBLIC KEY-----", "").Replace("
    ", "").Replace("
    ", "");
                byte[] keyData = Convert.FromBase64String(pemFileConent);
                bool keySize1024 = (keyData.Length == 162);
                bool keySize2048 = (keyData.Length == 294);
                if (!( keySize1024 || keySize2048 ))
                {
                    throw new ArgumentException("pem file content is incorrect, Only support the key size is 1024 or 2048");
                }
                byte[] pemModulus = (keySize1024? new byte[128] : new byte[256]);
                byte[] pemPublicExponent = new byte[3];
                Array.Copy(keyData, (keySize1024? 29:33), pemModulus, 0,(keySize1024?  128:256));
                Array.Copy(keyData, (keySize1024? 159:291), pemPublicExponent, 0, 3);
                RSAParameters para = new RSAParameters();
                para.Modulus = pemModulus;
                para.Exponent = pemPublicExponent;
                return para;
            }
    
            /// <summary>
            /// 将pem格式私钥(1024 or 2048)转换为RSAParameters
            /// </summary>
            /// <param name="pemFileConent">pem私钥内容</param>
            /// <returns>转换得到的RSAParamenters</returns>
            public static RSAParameters ConvertFromPemPrivateKey(string pemFileConent)
            {
                if (string.IsNullOrEmpty(pemFileConent))
                {
                    throw new ArgumentNullException("pemFileConent", "This arg cann't be empty.");
                }
                pemFileConent = pemFileConent.Replace("-----BEGIN RSA PRIVATE KEY-----", "").Replace("-----END RSA PRIVATE KEY-----", "").Replace("
    ", "").Replace("
    ","");
                byte[] keyData = Convert.FromBase64String(pemFileConent);
    
                bool keySize1024 = (keyData.Length == 609 || keyData.Length == 610);
                bool keySize2048 = (keyData.Length == 1190 || keyData.Length == 1192);
               
                if (!(keySize1024 || keySize2048))
                {
                    throw new ArgumentException("pem file content is incorrect, Only support the key size is 1024 or 2048");
                }
    
                int index = ( keySize1024 ? 11 : 12);
                byte[] pemModulus =  ( keySize1024 ? new byte[128]:new byte[256]);
                Array.Copy(keyData, index, pemModulus, 0, pemModulus.Length);
    
                index += pemModulus.Length;
                index += 2;
                byte[] pemPublicExponent = new byte[3];
                Array.Copy(keyData, index, pemPublicExponent, 0, 3);
    
                index += 3;
                index += 4;
                if ((int)keyData[index] == 0)
                {
                    index++;
                }
                byte[] pemPrivateExponent = (keySize1024 ? new byte[128] : new byte[256]);
                Array.Copy(keyData, index , pemPrivateExponent, 0, pemPrivateExponent.Length);
    
                index += pemPrivateExponent.Length;
                index += (keySize1024? ((int)keyData[index+1] == 64?2: 3):((int)keyData[index+2] == 128 ?3:4));
                byte[] pemPrime1 = (keySize1024 ? new byte[64] : new byte[128]);
                Array.Copy(keyData, index, pemPrime1, 0, pemPrime1.Length);
    
                index += pemPrime1.Length;
                index += (keySize1024 ? ((int)keyData[index + 1] == 64 ? 2 : 3) : ((int)keyData[index + 2] == 128 ? 3 : 4));
                byte[] pemPrime2 = (keySize1024 ? new byte[64] : new byte[128]);
                Array.Copy(keyData, index , pemPrime2, 0, pemPrime2.Length);
    
                index += pemPrime2.Length;
                index += (keySize1024 ? ((int)keyData[index + 1] == 64 ? 2 : 3) : ((int)keyData[index + 2] == 128 ? 3 : 4));
                byte[] pemExponent1 = (keySize1024 ? new byte[64] : new byte[128]);
                Array.Copy(keyData,index, pemExponent1, 0, pemExponent1.Length);
    
                index += pemExponent1.Length;
                index += (keySize1024 ? ((int)keyData[index + 1] == 64 ? 2 : 3) : ((int)keyData[index + 2] == 128 ? 3 : 4));
                byte[] pemExponent2 = (keySize1024 ? new byte[64] : new byte[128]);
                Array.Copy(keyData, index, pemExponent2, 0, pemExponent2.Length);
    
                index += pemExponent2.Length;
                index += (keySize1024 ? ((int)keyData[index + 1] == 64 ? 2 : 3) : ((int)keyData[index + 2] == 128 ? 3 : 4));
                byte[] pemCoefficient = (keySize1024 ? new byte[64] : new byte[128]);
                Array.Copy(keyData, index, pemCoefficient, 0, pemCoefficient.Length);
    
                RSAParameters para = new RSAParameters();
                para.Modulus = pemModulus;
                para.Exponent = pemPublicExponent;
                para.D = pemPrivateExponent;
                para.P = pemPrime1;
                para.Q = pemPrime2;
                para.DP = pemExponent1;
                para.DQ = pemExponent2;
                para.InverseQ = pemCoefficient;
                return para;
            }
            
        }
    }
    

     用该方法生成的密文可以被PHP使用了

  • 相关阅读:
    java-线程
    List、Map、set的加载因子,默认初始容量和扩容增量
    Mybatis使用generator自动生成映射配置文件信息
    Fiddler手机https抓包
    通知消息与ON_NOTIFY
    ATL实现COM组件
    vs参数配置
    QToolBox
    CTreeCtrl控件
    SQL-INSERT INTO用法
  • 原文地址:https://www.cnblogs.com/datougui/p/3929647.html
Copyright © 2011-2022 走看看