PHP和Java的RSA加密互通

一、利用OpenSSL生成RSA公私钥
1.生成RSA私钥
openssl genrsa -out rsa_private_key.pem 1024

示例:

-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQC19+3Zkg8ko4S7XeAjGl2ps8dEVGx2prFAAsq9OeNjvI4zbUG2
iw7fvk02VZuilYyspB/MR1nMEWreVj21FdnN/szIlC/stptlNMtmkZ28jv8QVvls
8O2Zp97qDxSWbYwZFT1nmQVK1uSZV7wMEldWTSlFcLuOXoFGGXndO9062QIDAQAB
AoGASoBHkVyLdqS8Izo8GiMhVemVHBS0k5+L0nlSKEcbIiqAze1dii9E17ZCRoym
O9qezdAkdK6BxVscNgt5GDrqAQvS6LmQ1KQfOF2mr3rNeCjz6RLl4ujl9mjwAikG
HRWBev7Dz9q/YjKg4OaFTTT5HcgnuyLzO2DY8rKA1PM3gkECQQDlPtu0N4gZJe2/
BSqEFwLLme+lQP8d1NNoICAP5U+GowUc885AMMWqOObOUVe/PzaSSObyAsRTht2H
OCalqWh/AkEAyzSUXpThSShB6JQxDC52r+SS9342bEa6z3vSJ2gBfIZObxA25jHS
F7pRh/vXpGXzcsV4fzIDGKz6tEPHfh3wpwJBANUwnrs7RWs1taKGWGKcz7Guh4nk
JxyD9tKHxalitJFd+3xQU4eok7pYznQie3rUe5iRCY0Y+6E987gzhOVc5VsCQFNs
4MT75on8ZyKvRHu1z7Bi7RuCy6EkYKmyMhNPldyj3yulwoQ7S//F1Jc5g8zQtmQW
QmQmCjNlQQAlG4/hht0CQByUzQ2Vj9uB/RXMvPWtGimEENaAO5Q2wF5kWnoyfg8U
8DjPPoFe0B9mWxAjPBCnI3UwW3P7B7TZKrAlf+GbtxE=
-----END RSA PRIVATE KEY-----






2.生成RSA公钥
openssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem

示例:
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC19+3Zkg8ko4S7XeAjGl2ps8dE
VGx2prFAAsq9OeNjvI4zbUG2iw7fvk02VZuilYyspB/MR1nMEWreVj21FdnN/szI
lC/stptlNMtmkZ28jv8QVvls8O2Zp97qDxSWbYwZFT1nmQVK1uSZV7wMEldWTSlF
cLuOXoFGGXndO9062QIDAQAB
-----END PUBLIC KEY-----





3.将RSA私钥转换成PKCS8格式
openssl pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM –nocrypt

示例:
-----BEGIN PRIVATE KEY-----
MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALX37dmSDySjhLtd
4CMaXamzx0RUbHamsUACyr0542O8jjNtQbaLDt++TTZVm6KVjKykH8xHWcwRat5W
PbUV2c3+zMiUL+y2m2U0y2aRnbyO/xBW+Wzw7Zmn3uoPFJZtjBkVPWeZBUrW5JlX
vAwSV1ZNKUVwu45egUYZed073TrZAgMBAAECgYBKgEeRXIt2pLwjOjwaIyFV6ZUc
FLSTn4vSeVIoRxsiKoDN7V2KL0TXtkJGjKY72p7N0CR0roHFWxw2C3kYOuoBC9Lo
uZDUpB84Xaaves14KPPpEuXi6OX2aPACKQYdFYF6/sPP2r9iMqDg5oVNNPkdyCe7
IvM7YNjysoDU8zeCQQJBAOU+27Q3iBkl7b8FKoQXAsuZ76VA/x3U02ggIA/lT4aj
BRzzzkAwxao45s5RV78/NpJI5vICxFOG3Yc4JqWpaH8CQQDLNJRelOFJKEHolDEM
Lnav5JL3fjZsRrrPe9InaAF8hk5vEDbmMdIXulGH+9ekZfNyxXh/MgMYrPq0Q8d+
HfCnAkEA1TCeuztFazW1ooZYYpzPsa6HieQnHIP20ofFqWK0kV37fFBTh6iTuljO
dCJ7etR7mJEJjRj7oT3zuDOE5VzlWwJAU2zgxPvmifxnIq9Ee7XPsGLtG4LLoSRg
qbIyE0+V3KPfK6XChDtL/8XUlzmDzNC2ZBZCZCYKM2VBACUbj+GG3QJAHJTNDZWP
24H9Fcy89a0aKYQQ1oA7lDbAXmRaejJ+DxTwOM8+gV7QH2ZbECM8EKcjdTBbc/sH
tNkqsCV/4Zu3EQ==
-----END PRIVATE KEY-----





注:php中使用openssl方法,签名和验签,不需要第三步,Java的私钥需要做第三步。

二、PHP的RSA签名和验签方法
1. 签名方法
openssl_sign($msg, $sign, $ key, OPENSSL_ALGO_SHA1);
$msg:要签名的字符串。
$sign:做好签名字符串。

不可以写成 $sign = openssl_sign($msg, $sign, $ key, OPENSSL_ALGO_SHA1);
$ key:密钥,密钥格式,必须为rsa_private_key.pem的格式。
OPENSSL_ALGO_SHA1:密钥算法,如果与Java等交互,必须相互配对。
2. 验签方法
$result= openssl_verify($msg, $sign, $key);
$msg:签名的原字符串。
$sign:签名字符串。
$ key:密钥,密钥格式,必须为rsa_private_key.pem的格式。
$result:验签结果;为1时,验签正确;其余失败。

3. 判断私钥是否是可用
$pi_key =  openssl_pkey_get_private($private_key);
这个函数可用来判断私钥是否是可用的,可用返回

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

5. 私钥加密 
openssl_private_encrypt($data,$encrypted,$pi_key);
$data :要签名的字符串。
$encrypted:签名后的字符串。
$pi_key:私钥。

6.公钥解密
openssl_public_decrypt($encrypted,$decrypted,$pu_key);
$encrypted:签名字符串。
$decrypted:解签后的字符串。
$pu_key:公钥。
注:3,4,5,6需要联合使用,5,6的这种加解密存在原串过长,加密失败的问题,请谨慎使用。所有使用到的key,请保证是原始串的格式。


三、JAVA的RSA签名和验签方法
1.签名方法
PS: 本方法中使用的密钥需要转换成PKCS8格式

/**
	 * 本方法使用SHA1withRSA签名算法产生签名
	 * @param String priKey 签名时使用的私钥(16进制编码)
	 * @param String src	签名的原字符串
	 * @return String 		签名的返回结果(16进制编码)。当产生签名出错的时候,返回null。
	 */
	public static String generateSHA1withRSASigature(String priKey, String src)
	{
		try
		{
			Signature sigEng = Signature.getInstance("SHA1withRSA");
			byte[] pribyte = UtilString.hexStrToBytes(priKey.trim());
			PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(pribyte);
			KeyFactory fac = KeyFactory.getInstance("RSA");
			RSAPrivateKey privateKey = (RSAPrivateKey) fac.generatePrivate(keySpec);
			sigEng.initSign(privateKey);
			sigEng.update(src.getBytes());
			byte[] signature = sigEng.sign();
			return UtilString.bytesToHexStr(signature);
		}
		catch (Exception e)
		{
			e.printStackTrace();
			return null;
		}
	}




2.验签方法

/**
	 * 本方法使用SHA1withRSA签名算法验证签名
	 * @param String pubKey 验证签名时使用的公钥(16进制编码)
	 * @param String sign 	签名结果(16进制编码)
	 * @param String src	签名的原字符串
	 * @return String 		签名的返回结果(16进制编码)
	 */
	public static boolean verifySHA1withRSASigature(String pubKey, String sign, String src)
	{
		try
		{
			Signature sigEng = Signature.getInstance("SHA1withRSA");
			byte[] pubbyte = UtilString.hexStrToBytes(pubKey.trim());
			X509EncodedKeySpec keySpec = new X509EncodedKeySpec(pubbyte);
			KeyFactory fac = KeyFactory.getInstance("RSA");
			RSAPublicKey rsaPubKey = (RSAPublicKey) fac.generatePublic(keySpec);
			sigEng.initVerify(rsaPubKey);
			sigEng.update(src.getBytes());
			byte[] sign1 = UtilString.hexStrToBytes(sign);
			return sigEng.verify(sign1);
		}
		catch (Exception e)
		{
			e.printStackTrace();
			//LogMan.log("[NeteaseSignUtil][verifySHA1withRSASigature]"+e);
			return false;
		}
	}





PS:解签和验签时签名算法(如SHA1withRSA)一定要使用配套的,
JAVA与PHP互通时也一定要用配套的。


十六进制转换方法:

package com.nloan.cmis.pub.utils;


public class UtilString {
	
	
	private static final char[] bcdLookup =
		{ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
	
    
    
	/**
	 * 将字节数组转换为16进制字符串的形式.
	 */
	public static final String bytesToHexStr(byte[] bcd){
		StringBuffer s = new StringBuffer(bcd.length * 2);

		for (int i = 0; i < bcd.length; i++)
		{
			s.append(bcdLookup[(bcd[i] >>> 4) & 0x0f]);
			s.append(bcdLookup[bcd[i] & 0x0f]);
		}

		return s.toString();
	}
    
	
    
	/**
	 * 将16进制字符串还原为字节数组.
	 */
	public static final byte[] hexStrToBytes(String s)	{
		
		byte[] bytes;

		bytes = new byte[s.length() / 2];

		for (int i = 0; i < bytes.length; i++){
			bytes[i] = (byte) Integer.parseInt(s.substring(2 * i, 2 * i + 2), 16);
		}

		return bytes;
	}
	
	public static void main(String[] args) {
		String str = "aa人民";
//		str = URLEncoder.encode(str);
//		byte[] aa = UtilString.hexStrToBytes(str);
//		String nstr =new String(aa);
//		System.out.println(nstr);
//		System.out.println(UtilString.HexToString(nstr));
		
		//字符串先byte 再十六进制,再字符串
		str=bytesToHexStr(str.getBytes());
		System.out.println(str);
		
		//将16进制字符串还原为字节数组.
		byte[] bb=hexStrToBytes(str);
		System.out.println(new String(hexStrToBytes(str)));
		
	}
}







文档包中的key是配套key值,可直接使用,其他的文件有示例方法,可做参考。
网络参考地址:
http://blog.csdn.net/clh604/article/details/20224735
http://blog.csdn.net/chaijunkun/article/details/7275632

你可能感兴趣的:(java,PHP,rsa)