C#实现使用Java的RSA公钥加密

        最近工作中,有一个第三方接口,需要对接口参数的部分数据进行RSA加密,接口文档中提供了一个使用Java写的RSA公钥。我也是第一次接触RSA加密算法,在查阅资料中发现,使用RSA加密,同一个数据,加密的结果是不一样的。在使用C#实现RSA加密过程中,一边查资料,一边摸索,也浪费了不少的时间。

 注:本文涉及到的代码非原创代码,从网上收集而来,本文记录下来是为了方便下次碰到时能直接拿去用,同时也非常感谢博客园的博主的分享

C#RSA对接JAVA中RSA方式 - 盛开的雨季 - 博客园

C# RSA 加密 解密 - YuanY - 博客园

        好了,废话就不说了,本文的代码在.net framework 4.0和vs2019中测试通过。

第一版代码(能加密,但接口方无法解密)

public class RSAHelper
{
        public static string publicKey = @"<RSAKeyValue><Modulus>aaaaaaaaaaaaaaaafUwIDAQAB</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";
        public static string RsaEncrypt(string value, bool usePkcs8 = false)
        {
            if (string.IsNullOrEmpty(value)) return value;

            RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(2048);
            rsa.FromXmlString(publicKey);//将公钥导入到RSA对象中,准备加密;
            var buffer = Encoding.UTF8.GetBytes(value);
            buffer = rsa.Encrypt(buffer,false);
            return Convert.ToBase64String(buffer);
        }
}

通过与接口方沟通,拿到了java版的加解密代码,如下:


package com.pkuhit.mobile.pay.alipay.api.sign;

import com.founder.smc.util.Base64Util;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.Cipher;

public class RSA{
	
	public static final String  SIGN_ALGORITHMS = "SHA1WithRSA";
	
	/**
	* RSA签名
	* @param content 待签名数据
	* @param privateKey 商户私钥
	* @param input_charset 编码格式
	* @return 签名值
	*/
	public static String sign(String content, String privateKey, String input_charset)
	{
        try 
        {
        	PKCS8EncodedKeySpec priPKCS8 	= new PKCS8EncodedKeySpec( Base64.decode(privateKey) ); 
        	KeyFactory keyf 				= KeyFactory.getInstance("RSA");
        	PrivateKey priKey 				= keyf.generatePrivate(priPKCS8);

            java.security.Signature signature = java.security.Signature
                .getInstance(SIGN_ALGORITHMS);

            signature.initSign(priKey);
            signature.update( content.getBytes(input_charset) );

            byte[] signed = signature.sign();
            
            return Base64.encode(signed);
        }
        catch (Exception e) 
        {
        	e.printStackTrace();
        }
        
        return null;
    }
	
	/**
	* RSA验签名检查
	* @param content 待签名数据
	* @param sign 签名值
	* @param ali_public_key 支付宝公钥
	* @param input_charset 编码格式
	* @return 布尔值
	*/
	public static boolean verify(String content, String sign, String ali_public_key, String input_charset)
	{
		try 
		{
			KeyFactory keyFactory = KeyFactory.getInstance("RSA");
	        byte[] encodedKey = Base64.decode(ali_public_key);
	        PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));

		
			java.security.Signature signature = java.security.Signature
			.getInstance(SIGN_ALGORITHMS);
		
			signature.initVerify(pubKey);
			signature.update( content.getBytes(input_charset) );
		
			boolean bverify = signature.verify( Base64.decode(sign) );
			return bverify;
			
		} 
		catch (Exception e) 
		{
			e.printStackTrace();
		}
		
		return false;
	}
	
	/**
	* 解密
	* @param content 密文
	* @param private_key 商户私钥
	* @param input_charset 编码格式
	* @return 解密后的字符串
	*/
	public static String decrypt(String content, String private_key, String input_charset) throws Exception {
        PrivateKey prikey = getPrivateKey(private_key);

        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, prikey);

        InputStream ins = new ByteArrayInputStream(Base64.decode(content));
        ByteArrayOutputStream writer = new ByteArrayOutputStream();
        //rsa解密的字节大小最多是128,将需要解密的内容,按128位拆开解密
        byte[] buf = new byte[128];
        int bufl;

        while ((bufl = ins.read(buf)) != -1) {
            byte[] block = null;

            if (buf.length == bufl) {
                block = buf;
            } else {
                block = new byte[bufl];
                for (int i = 0; i < bufl; i++) {
                    block[i] = buf[i];
                }
            }

            writer.write(cipher.doFinal(block));
        }

        return new String(writer.toByteArray(), input_charset);
    }

	
	/**
	* 得到私钥
	* @param key 密钥字符串(经过base64编码)
	* @throws Exception
	*/
	public static PrivateKey getPrivateKey(String key) throws Exception {

		byte[] keyBytes;
		
		keyBytes = Base64.decode(key);
		
		PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
		
		KeyFactory keyFactory = KeyFactory.getInstance("RSA");
		
		PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
		
		return privateKey;
	}

	/**
	 *加密
	 * @param content 明文
	 * @param public_key 公钥
	 * @param input_charset 编码格式(UTF-8)
	 * @return 加密后的字符串
	 * @throws Exception
	 */
	public static String encrypt(String content,String public_key, String input_charset) throws Exception {
		PublicKey publicKey = getPublicKey(public_key);
		Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
		Cipher cipher = Cipher.getInstance("RSA");
		cipher.init(Cipher.ENCRYPT_MODE,publicKey);
		ByteArrayOutputStream writer = new ByteArrayOutputStream();
		//加密最大长度为117b(密钥长度为1024时),超过该长度的进行分块处理
		byte[] encryptData = null;
		byte[] con = content.getBytes("UTF-8");
		byte[] cache;
		int offSet = 0,i=0;
		int dataLength = con.length;
		while(dataLength - offSet > 0){
			if (dataLength - offSet > 117){
				cache = cipher.doFinal(con,offSet,117);
			}else {
				cache = cipher.doFinal(con,offSet,dataLength-offSet);
			}
			writer.write(cache,0,cache.length);
			i++;
			offSet = i*117;
		}
		encryptData = writer.toByteArray();
		writer.close();
		//先用RSA加密再用base64加密
		return Base64Util.encode(encryptData);
	}

	/**
	 * 公钥字符串转PublicKey实例
	 * @param publicKey
	 * @return
	 * @throws Exception
	 */
	public static PublicKey getPublicKey(String publicKey) throws Exception {
		byte[] publicKeyBytes =  Base64Util.decode(publicKey);
		X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
		KeyFactory keyFactory = KeyFactory.getInstance("RSA");
		return keyFactory.generatePublic(keySpec);
	}

	public static void main(String[] args)throws Exception {
		String clientPrivateKey="";
		String clientPublicKey="";
		String context = "老铁";
		String encryptData = encrypt(context,clientPublicKey,"UTF-8");
		System.out.println("encryptData=>"+encryptData);
		String decryptData = decrypt(encryptData,clientPrivateKey,"UTF-8");
		System.out.println("decryptData=>"+decryptData);
	}
}

反复看了他们写的代码,也没啥特别的,他们就是解密不了,有点见鬼了,后面查阅资料发现,不能直接使用java的公钥,需要使用插件Portable.BouncyCastle进行转换,使用nuget安装Portable.BouncyCastle,如下图:

最终版代码如下:

public class RSAHelper
    {
        public static string publicKey = @"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDLUXFfPGjolZHxO0fc+e26S0Aq9OyI6jvSFjngLXb4V2dfb1DhCXB4y0wWheCvU4jd9b6lklF2kw9d5sPHDMCqssZPKnfcoGPNzGTtzVFjMJXYHHW7bHvwOhBzO33fGVYlKl2MK+NHyFzByovtQhcCWlTM5SEFBqB96eccg8bfUwIDAQAB";
        public static string RsaEncrypt(string value, bool usePkcs8 = false)
        {
            if (string.IsNullOrEmpty(value)) return value;

            RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(2048);
            rsa.FromXmlString(RSAPublicKeyJava2DotNet(publicKey));//将公钥导入到RSA对象中,准备加密;
            var buffer = Encoding.UTF8.GetBytes(value);
            buffer = rsa.Encrypt(buffer,false);
            return Convert.ToBase64String(buffer);
        }

      /***************以下是java提供的公私钥转成.net公私钥XML的方式*************************************/
        /// <summary> 
        /// RSA公钥格式转换,java->.net
        /// </summary>
        /// <param name="publicKey">java生成的公钥</param>
        /// <returns></returns>
        public static string RSAPublicKeyJava2DotNet(string publicKey)
        {
            RsaKeyParameters publicKeyParam = (RsaKeyParameters)PublicKeyFactory.CreateKey(Convert.FromBase64String(publicKey));
            return string.Format("<RSAKeyValue><Modulus>{0}</Modulus><Exponent>{1}</Exponent></RSAKeyValue>",
            Convert.ToBase64String(publicKeyParam.Modulus.ToByteArrayUnsigned()),
            Convert.ToBase64String(publicKeyParam.Exponent.ToByteArrayUnsigned()));
        }


    }

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
您好!要使用 C# 进行 RSA 加密并带有公钥,您可以按照以下步骤进行操作: 1. 创建 RSA 密钥对:首先,您需要生成 RSA 密钥对,包括公钥和私钥。您可以使用 `RSACryptoServiceProvider` 类来实现这一步骤。示例代码如下: ```csharp using System.Security.Cryptography; // 创建 RSA 密钥对 using (var rsa = new RSACryptoServiceProvider()) { // 获取公钥 string publicKey = rsa.ToXmlString(false); // 获取私钥 string privateKey = rsa.ToXmlString(true); // 将公钥保存在某个位置,以便其他人使用 // 并且在加密时需要使用公钥 } ``` 2. 使用公钥进行加密:一旦您拥有公钥,可以使用它来加密数据。以下是一个例子: ```csharp using System; using System.Security.Cryptography; using System.Text; // 使用公钥进行加密 public static string EncryptWithPublicKey(string publicKey, string data) { using (var rsa = new RSACryptoServiceProvider()) { // 从 XML 格式的公钥字符串导入公钥 rsa.FromXmlString(publicKey); // 将明文数据转换为字节数组 byte[] plainBytes = Encoding.UTF8.GetBytes(data); // 加密数据 byte[] encryptedBytes = rsa.Encrypt(plainBytes, false); // 将加密后的字节数组转换为 Base64 字符串形式 string encryptedData = Convert.ToBase64String(encryptedBytes); return encryptedData; } } ``` 您可以使用上述方法将数据使用公钥进行加密。请注意,`publicKey` 参数是从密钥对生成的公钥字符串。 希望这些代码对您有所帮助!如有任何疑问,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zxy2847225301

测试使用

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值