PHP RSA加密解密

今天我来说下如何使用RSA方式进行加密解密

一、生成公钥和私钥;

使用OpenSSL就可以,一般Linux和mac有自带的;windows的可自行安装;

通过如下命令生成;

注:

RSA非对称加密内容长度有限制,1024位key的最多只能加密127位数据,如果加密字符串过长请使用2048

momodeMBP:~ momo$ openssl genrsa -out rsa_private_key.pem 1024(去掉1024默认生成的是2048位)
Generating RSA private key, 1024 bit long modulus

.....++++++

............................++++++

e is 65537 (0x10001)

momodeMBP:~ momo$ openssl pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM -nocrypt -out private_key.pem

momodeMBP:~ momo$ openssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem

writing RSA key

momodeMBP:~ momo$

第一条命令生成原始 RSA私钥文件 rsa_private_key.pem;

第二条命令将原始 RSA私钥转换为 pkcs8格式;

第三条生成RSA公钥 rsa_public_key.pem;

从上面看出通过私钥能生成对应的公钥,因此我们将私钥private_key.pem用在服务器端,rsa_public_key.pem给客户端ios、Android、外部合作方;

这里我们来说下服务器端的处理方式:

<?php

$private_key=file_get_contents('private_key.pem'); //读取私钥

$public_key=file_get_contents('rsa_public_key.pem'); //读取公钥

$pi_key =  openssl_pkey_get_private($private_key);//这个函数可用来判断私钥是否是可用的,可用返回资源id Resource id

$pu_key = openssl_pkey_get_public($public_key);//这个函数可用来判断公钥是否是可用的

$data = 'method=medicool.user.detail&nonce_str=607673&parameters={"test":"2458"}&partnerid=test';//原始数据

echo "private key encrypt:\n";

openssl_private_encrypt($data,$encrypted,$pi_key);//私钥加密

$encrypted = base64_encode($encrypted);//加密后的内容通常含有特殊字符,需要编码转换下,在网络间通过url传输时要注意base64编码是否是url安全的

$encrypted=urlencode($encrypted);

echo $encrypted,"\n"; //输出私钥加密后的字符串数据

echo "public key decrypt:\n";

openssl_public_decrypt(base64_decode(urldecode($encrypted)),$decrypted,$pu_key);//私钥加密的内容通过公钥可用解密出来

echo $decrypted,"\n"; //通过公钥解密后的字符串数据

echo "---------------------------------------\n";

echo "public key encrypt:\n";

openssl_public_encrypt($data,$encrypted,$pu_key);//公钥加密

$encrypted = (base64_encode($encrypted));

$encrypted=urlencode($encrypted);

echo $encrypted,"\n";//通过公钥加密后的字符串数据

echo "private key decrypt:\n";

openssl_private_decrypt(base64_decode(urldecode($encrypted)),$decrypted,$pi_key);//私钥解密

echo $decrypted,"\n"; //通过私钥解密后的字符串数据

?>

下面是ios的对接demo:

//获得筛选标签
-(void)requesYikuData{

    //随机生成6位数

    int num = (arc4random() % 1000000);

    NSString * randomNumber = [NSString stringWithFormat:@"%.6d", num];

    NSLog(@"%@", randomNumber);

    //遵循约定,生成签名

    //JSON转换之后有回车空格以及中文转义问题 导致签名无法验证

    //文字转义放在客户端执行

    NSString * searchName ="头孢";//搜索名称

    int page = 1;//页码

    NSString *string =[NSString stringWithFormat:@"{\"cpage\":%d,\"keywords\":\"%@\"}",page,searchName];

    //3.未加密签名组成字符串

    NSString * str1 = [NSString stringWithFormat:@"method=medicool.drug.search&nonce_str=%@&parameters=%@&partnerid=test",randomNumber,string];

    //4;对3字符串根据公钥RSA加密;

    NSString *rsaStr = [RSAEncryptor encryptString:[str1 lowercaseString] publicKey:YIKUPUBLICKEY];

    NSLog(@"RSA加密后字符串%@",rsaStr);

    //5;对4结果进行base64_encode

    NSData * encodeData = [rsaStr dataUsingEncoding:NSUTF8StringEncoding];

    //    encodeData = [encodeData base64EncodedDataWithOptions:0];

    NSString *base64Str = [[NSString alloc] initWithData:encodeData encoding:NSUTF8StringEncoding];

    //6;对5结果进行urlencode;

    NSString * signStr =  [RSAEncryptor encodeString:base64Str];

    NSLog(@"urlencode后字符串%@",signStr);

    //请求的url

    NSString * urStr = @"http://extratest.cn/Apidrug/medisearch";


    AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
    manager.responseSerializer.acceptableContentTypes =[NSSet setWithObjects:@"text/html",@"text/plain",@"text/json",@"application/json",nil];

    manager.requestSerializer = [AFHTTPRequestSerializer serializer];

    manager.responseSerializer = [AFHTTPResponseSerializer serializer];

    NSDictionary* URLParameters = @{

           @"cpage":@1,
           @"keywords":@"头孢",
           @"method":@"medicool.drug.search",
           @"nonce_str":randomNumber,
           @"partnerid":@"test",
           @"sign":signStr,
       };

  NSMutableURLRequest* request = [[AFHTTPRequestSerializer serializer] requestWithMethod:@"POST" URLString:urStr parameters:URLParameters error:NULL];
 AFHTTPRequestOperation *operation = [manager HTTPRequestOperationWithRequest:request                                                                 success:^(AFHTTPRequestOperation *operation, id responseObject) {                                                       NSLog(@"HTTP Response Status Code: %ld", [operation.response statusCode]);
                                                                            NSLog(@"HTTP Response Body: %@", responseObject);
                                                                            NSDictionary *tempDictQueryDiamond = [NSJSONSerialization JSONObjectWithData:responseObject options:0 error:nil];
                                                                           NSLog(@"%@",tempDictQueryDiamond);
                                                                         } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
                                                                        NSLog(@"HTTP Request failed: %@", error);
                                                                      }];
    [manager.operationQueue addOperation:operation];
}

Android对接demo:

主项目

package medicool.com.medicool;



import android.support.v7.app.AppCompatActivity;

import android.os.Bundle;

import android.widget.ListView;

import android.widget.SearchView;

import android.widget.TextView;


import java.util.HashMap;



public class MainActivity extends AppCompatActivity {

    private final String url = "http://extratest.meditool.cn/Apidrug/medisearch";

    private final String search_method = "medicool.drug.search";



    private SearchView searchView;

    private TextView textView;


    private int cpage = 1;

    private String sign;

    //POST数据

    HashMap<String, String> args_jsondata = new HashMap<>();

    //签名原数据

    HashMap<String, Object> args_sign = new HashMap<>();



    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);



        /**

         * method 请求方法名

         nonce_str 随机字符串

         partnerid 合作方指定字符串

         sign 签名

         cpage 请求页码

         keywords 搜索关键词

         */

        args_jsondata.put("method", search_method);

        args_jsondata.put("nonce_str", "123456");

        args_jsondata.put("partnerid", Sign.PARTNERID);



        textView = (TextView) findViewById(R.id.textView);

        searchView = (SearchView) findViewById(R.id.searchView);

        searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {

            @Override

            public boolean onQueryTextSubmit(String query) {

                if ("".equals(query)) {

                    return false;

                }



                //这里注意下手动排序,即 医库合作约定

                // 1;将业务请求参数名按照字母升序存入数组

                args_sign.put("cpage", cpage);

                args_sign.put("keywords", query.trim());



                //对args_sign签名

                try {

                    sign = Sign.getSign(MainActivity.this, search_method, "123456", args_sign);

                } catch (Exception e) {

                    e.printStackTrace();

                }



                //参数补全

                args_jsondata.put("sign", sign);

                args_jsondata.put("cpage", cpage + "");

                args_jsondata.put("keywords", query.trim());



                new Thread(new Runnable() {

                    @Override

                    public void run() {

                        final String result = HttpUtils.getData(url, args_jsondata);

                        runOnUiThread(new Runnable() {

                            @Override

                            public void run() {

                                textView.setText(result);

                            }

                        });

                    }

                }).start();



                return false;

            }


            @Override

            public boolean onQueryTextChange(String newText) {

                return false;

            }

        });

    }

}

Sign类:

package medicool.com.medicool;

import android.content.Context;

import android.net.Uri;

import android.util.Base64;

import org.json.JSONException;

import org.json.JSONObject;

import java.util.HashMap;

import java.util.Map;



public class Sign {

    //固定

    public static final String PARTNERID = "medicoolgandan2017";



    public static String getSign(Context context, String method, String nonce_str, HashMap<String, Object> parameters) throws Exception {

        String sign;

        JSONObject jsonObject = new JSONObject();

        String j_parameters = "";

        //对parameters进行json_encode处理

        try {

            if (parameters != null && !parameters.isEmpty()) {

                for (Map.Entry<String, Object> entry : parameters.entrySet()) {

                    jsonObject.put(entry.getKey(), entry.getValue());

                }

                j_parameters = jsonObject.toString();

            }

        } catch (JSONException e) {

            e.printStackTrace();

        }



        //拼接参数method=$method&nonce_str=$nonce_str&parameters=$parameters&partnerid=$partnerid

        StringBuffer stringBuffer = new StringBuffer();

        stringBuffer.append("method=").append(method + "&").append("nonce_str=").append(nonce_str + "&").append("parameters=").append(j_parameters + "&").append("partnerid=" + PARTNERID);



        //RSA加密

        byte[] bytes = RsaUtils.encryptData(stringBuffer.toString().getBytes(), context);


        //base64_encodec

        sign = Base64.encodeToString(bytes, Base64.DEFAULT);



        //urlencode

        sign = Uri.encode(sign);


        return sign;

    }


}

RsaUtils类:

package medicool.com.medicool;



import android.content.Context;

import android.util.Base64;



import java.io.InputStream;

import java.security.KeyFactory;

import java.security.PublicKey;

import java.security.spec.X509EncodedKeySpec;



import javax.crypto.Cipher;



public class RsaUtils {

    private static String RSA = "RSA";

    private static final String ECB_PKCS1_PADDING = "RSA/ECB/PKCS1Padding";



    public static byte[] encryptData(byte[] data, Context context) {

        byte[] resultBytes = null;

        try {

            PublicKey publicKey = loadPublicKey(context);

            Cipher cipher = Cipher.getInstance(ECB_PKCS1_PADDING);

            cipher.init(Cipher.ENCRYPT_MODE, publicKey);

            resultBytes = cipher.doFinal(data);

        } catch (Exception e) {

            e.printStackTrace();

        }



        return resultBytes;

    }



    private static PublicKey loadPublicKey(Context context) throws Exception {

        try {

            PublicKey publicKey;

            byte[] keyBytes = Base64.decode(readFile(context, "rsa_public_key.pem"), Base64.DEFAULT);

            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);

            KeyFactory keyFactory = KeyFactory.getInstance(RSA);

            publicKey = keyFactory.generatePublic(keySpec);

            return publicKey;

        } catch (Exception e) {

            throw new Exception("密钥数据读取错误");

        }

    }



    private static String readFile(Context context, String file) {

        int len;

        byte[] buf;

        String grammar = "";

        try {

            InputStream in = context.getAssets().open(file);

            len = in.available();

            buf = new byte[len];

            in.read(buf, 0, len);

            grammar = new String(buf, "utf-8");

        } catch (Exception e) {

            e.printStackTrace();

        }

        return grammar;

    }
}

HttpUtils类:

package medicool.com.medicool;

import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.util.EntityUtils;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

public class HttpUtils {
    public static String getData(String url, HashMap<String, String> params) {

        HttpPost post = new HttpPost(url);

        HttpClient httpclient = new DefaultHttpClient();
httpclient.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 30000);
httpclient.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, 30000);
        ArrayList<NameValuePair> paramPairs = new ArrayList<>();
        if (params != null && !params.isEmpty()) {
            for (Map.Entry<String, String> entry : params.entrySet()) {
                paramPairs.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
            }
        }

        try {
            post.setEntity(new UrlEncodedFormEntity(paramPairs, "UTF-8"));
        } catch (UnsupportedEncodingException e) {
            return "";
        }

        try {
            HttpResponse response;
            response = httpclient.execute(post);
            String inf;
            if (response.getStatusLine().getStatusCode() == 200) {// 判断响应状态码
                inf = EntityUtils.toString(response.getEntity());
                return inf;
            }
        } catch (Exception e) {

            e.printStackTrace();
        }
        return "";
    }
}

猜你喜欢

转载自blog.csdn.net/momo_mutou/article/details/81835170