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