欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

RSA加密\解密,数据传输的安全性

程序员文章站 2022-05-12 20:31:39
...
开遍之前,给大家推荐一本书, <图解密码技术(日)结城浩(著)完整版> , 读完该书 , 会对加密算法有一个较为深刻的了解.
如下只是我对RSA和SHA1WITHRSA的笔记和理解,后附上实现的代码,代码仅仅是Android和PHP的,如果有疏忽遗漏,请各位批评指出.
一.RSA
以图来说话:

RSA加密\解密,数据传输的安全性

如何生成对应的公私钥呢? , 详见上一篇文章《RSA公钥和私钥的生成(PHP\Android\iOS),数据传输的安全性》

以下代码为rsa加解密代码,非sha1withrsa代码

以下为Android代码:


/**
 * Android加密和解密 , 请求**
 * Created by xiaojun.lan on 2017/1/22.
 */

import android.util.Base64;
import android.util.Log;

import com.lxj.ucapp.common.utils.LogUtils;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.Cipher;

/**
 * 注意:
 * 本文件是对用户需要加密信息进行加密的文件,请确保本文件安全性,注意反编译读取公私钥
 */
public class Rsa2 {

    //加密 , 公钥 , 保密 , API加密使用,内容已经打乱,请重新生成,rsa_public_key.pem的内容
    //这个公钥和下面的私钥并不对应,这个公钥的私钥保存在服务器
    private static final String RSA_PUBLICE =
            "MIGSDFSDFUAA4GNADCBiQKBgQCbxDvCxOwLNJnBBBBBU6YTpuEFjKEuW\n" +
                    "MKze56Zs0OgRj9FU6K9w3OSDFASDFuELOQgh4Soy84CQy0h7Ep3zBBBBjQ5i+dPksn\n" +
                    "cMQ0q9aAN/x69BSSDFGSDFGDFGCY5974hldSDFEEtm0opzbblJ+x7AS2Uu5hhBBB1X8oLHf1E\n" +
                    "8A8Cylf5LWkiJkVvRTGSDFjQIDAADFAJK,BNJFK";

    //解密 , 私钥 , 绝密 以下私钥只是一个说明,已经打乱其内容,请重新生成,pkcs8_private_key.pem的内容
    //这个私钥的公钥和上面并不对应,这个私钥对应的公钥在服务器
    private static final String RSA_PRIVATE = "CVGHJT67UGHMVBNMUY67867CAmEwggJdAgEAAoGBAMBlEwCEkrqdG/EH\n" +
            "sj284Oa04jM5wYTMtcUb2exV9o7mMZJj7iMtR3Yf/1pEAi51IKEH5d6ALrN4WZMF\n" +
            "OB5R3ffuHL8ojFAoOa56fdqIZrpUCP2YnNT8JB1xjPL159foth31IqlO4T6MIaIr\n" +
            "4LC3zsASDFASDWE34567UY78I3421DFGHUIOL878564IY9KkzpUW9EYD5DKBG3ND\n" +
            "VQcnSEwuwRo7cH35i5iNVAIriRn+R7S3qJapYUUIkI6SLrmDe5pf2fI//izv8ohr\n" +
            "EjrOyveQ4nnMZcWEskGtyi96E54HJMCVBSAERTW3435e2OvigGjCOI5kskYzHw9v\n" +
            "4O1asOaLeFqoj8DmHQJBAPHdeViJn7dYuFStbMp28cThz9jGn1f9pn4fUVs5h+5X\n" +
            "OjuPmT0WGo4pCnrPhE7YGJ1pen4/H3LF1OvAWIg60ucCQQDLo3qG88Vp1FP/PKnR\n" +
            "VtQrIEZAd5+v4yz5jni51Q+83n1wcERUeM65w+6SmsypfxYoscXPMffWxhoMtBB3\n" +
            "yzArAkEAwxpHApax0fKtbxEeiwv75zfItDM04oPoRCD7Pb1g23BdtyIVGOO1tCuD\n" +
            "GqI/NmK3KHOnriM5ORpAsZPNVscszQJAVgxtYQsvFyoWmFrc8016eAK6TNF/k8Yu\n" +
            "IgHW98eVT9zAKrv106/8wriNXju1UcYW6fk8ufHGZWXuagHIl6YvYwJBAN+w3TnG\n" +
            "rSvrqO+ZBkXABx23NuIcOWE+30CQkm6a+g9tYBNbbGHJKFTYU899-0T678454567\n" +
            "A1LcWyf6fO236YUJ,KBNKT7UI";

    private static final String RSA = "RSA";

    private static final String TAG = "Rsa";


    /**
     * 使用公钥加密
     *
     * @param content 需要加密数据
     * @return 加密后的结构
     */
    public static String encryptByPublic(String content) {

        try {
            PublicKey pubkey = getPublicKeyFromX509(RSA, RSA_PUBLICE);
            Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            cipher.init(Cipher.ENCRYPT_MODE, pubkey);
            byte plaintext[] = content.getBytes("UTF-8");
            byte[] output = cipher.doFinal(plaintext);
            return new String(Base64.encode(output, Base64.DEFAULT));
        } catch (Exception e) {
            return "";
        }
    }

    /**
     * 通过私钥解密
     *
     * @param content 需要解密的数据
     * @return 解密后的数据
     */
    public static String decryptByPrivate(String content) {
        if (content == null || content.length() < 4) {
            LogUtils.LogError(TAG, "需要解密的数据有误");
            return "";
        }
        try {
            PrivateKey prikey = getPrivateKeyFromPKCS8(RSA, RSA_PRIVATE);
            Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            cipher.init(Cipher.DECRYPT_MODE, prikey);
            byte[] enBytes = Base64.decode(content, Base64.DEFAULT);
            byte[] deBytes = cipher.doFinal(enBytes);
            return new String(deBytes);
        } catch (Exception e) {
            LogUtils.LogError(TAG, "数据解密失败,返回null");
            return "";
        }
    }

    /**
     * 将字符串进行urlencode转换,使得其在网络传输中不会乱码
     * @param str 需要转换的字符串
     * @return 转换后的结果
     */
    public static String rsaUrlEncode(String str) {
        String urlEncode_str = null;
        try {
            urlEncode_str = URLEncoder.encode(str, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            LogUtils.LogError(TAG, str + "参数 url 转码失败");
            e.printStackTrace();
        }
        return urlEncode_str;
    }

    /**
     * 得到公钥
     *
     * @param RSA    "rsa"
     * @param bysKey "公钥字符串"
     * @return 返回公钥
     */
    private static PublicKey getPublicKeyFromX509(String RSA, String bysKey) {
        byte[] decodedKey = Base64.decode(bysKey, Base64.DEFAULT);
        X509EncodedKeySpec x509 = new X509EncodedKeySpec(decodedKey);
        KeyFactory keyFactory;
        PublicKey publicKey = null;
        try {
            keyFactory = KeyFactory.getInstance(RSA);
            publicKey = keyFactory.generatePublic(x509);
        } catch (NoSuchAlgorithmException e) {
            Log.e(TAG, "keyFactory出错");
            e.printStackTrace();
        } catch (InvalidKeySpecException e) {
            Log.e(TAG, "publicKey出错,请检查公钥是否正确");
            e.printStackTrace();
        }
        return publicKey;
    }

    /**
     * 得到私钥
     *
     * @param RSA    "rsa"
     * @param bysKey "私钥字符串"
     * @return 返回私钥
     */
    private static PrivateKey getPrivateKeyFromPKCS8(String RSA, String bysKey) {
        byte[] keyBytes;
        keyBytes = Base64.decode(bysKey, Base64.DEFAULT);
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory;
        PrivateKey privateKey = null;
        try {
            keyFactory = KeyFactory.getInstance(RSA);
            privateKey = keyFactory.generatePrivate(keySpec);
        } catch (NoSuchAlgorithmException e) {
            Log.e(TAG, "keyFactory异常");
        } catch (InvalidKeySpecException e) {
            Log.e(TAG, "privateKey出错,请检查是否是PKCS8格式的私钥");
            e.printStackTrace();
        }
        return privateKey;
    }

}

调用方法:

使用公钥加密:
Rsa.rsaUrlEncode(//将内容进行urlencode处理
    Rsa.encryptByPublic("aaaaaa")//加密
)
使用私钥解密:
Rsa.decryptByPrivate(
    Rsa.rsaUrlEncode("asdfaskdlfjaksdf加密内容")//对内容进行urldecode处理
)//解密

以下为PHP服务器端:

<?php

/**
 * Class Rsa
 * create by xiaojun.lan on 2016.09.12
 */
class Rsa {

    /**
     * 客户端公钥加密
     * 该数据加密后,将发送给客户端,客户端使用本函数使用的公钥对应的私钥进行解密
     * @param string $data
     * @return null|string
     */
    public static function publicEncrypt($data = '') {
        if (! is_string ( $data )) {
            return null;
        }
        return openssl_public_encrypt ( $data, $encrypted, self::getPublicKey () ) ? base64_encode ( $encrypted ) : null;
    }

    /**
     * 解密客户端发送过来的加密数据
     * 私钥解密
     *
     * @param string $encrypted
     * @return null
     */
    public static function privDecrypt($encrypted = '') {
        if (! is_string ( $encrypted )) {
            return null;
        }
        return (openssl_private_decrypt ( base64_decode ( $encrypted ), $decrypted, self::getPrivateKey () )) ? $decrypted : null;
    }

    /**
     * 获取客户端私钥
     * 本私钥对应的公钥向客户端公开,客户端使用公钥加密后,统一使用该私钥进行解密
     * 
     * @return bool|resource
     */
    private static function getPrivateKey() {
        $privKey = file_get_contents("./rsa_private_key.pem");
        return openssl_pkey_get_private ( $privKey );
    }

    /**
     * 获取客户端对应的公钥
     * 该公钥是客户端私钥解密对应的公钥   
     * 
     * @return bool|resource
     */
    private static function getPublicKey() {
        $publicKey = file_get_contents("./rsa_public_key.pem");
        return openssl_pkey_get_public ( $publicKey );
    }

}

调用方法:

//$_POST['name']是移动端传过来的经过urlencode处理的加密串
//$name 是要加密的字符串

Rsa::privDecrypt($_POST['name'])//解密
Rsa::publicEncrypt($name)//加密

由于本人对iOS不是很熟悉,暂时未上iOS代码,如果有可提供的同学,可以提供下

福利:
图解密码技术文档 <图解密码技术(日)结城浩(著)完整版.pdf>
http://download.csdn.net/download/xkjscm/10044301