C# Java间进行RSA加密解密交互

引用:http://blog.csdn.net/dslinmy/article/details/37362661

这里,讲一下RSA算法加解密在C#和Java之间交互的问题,这两天纠结了很久,也看了很多其他人写的文章,颇受裨益,但没能解决我的实际问题,终于,还是被我捣鼓出来了。

首先,介绍一下写这代码的目的:完成webService验证问题,服务器端采用C#开发,客户端采用Java开发。服务器端给客户端提供公钥,已进行数据加密,客户端加密后提数据提交给服务器,服务器用私钥对数据解密,进行验证。

这里遇到的主要问题是C# RSACryptoServiceProvider类产生的公钥、私钥都是xml字符串数据,而java RSA算法要求的 Modulus、Exponent都是BigInteger类型,两者间的转换才是问题所在。

关于Java 和 C#各自独立的进行RSA加密解密,大家可以看整两篇文章,java RSA加密解密实现() 和 C#中RSA加密解密和签名与验证的实现

接下来讲一下实现步骤:

首先由C# RSACryptoServiceProvider类生成公钥、私钥

/// <summary>
       /// 生成公钥、私钥
       /// </summary>
       /// <returns>公钥、私钥,公钥键"PUBLIC",私钥键"PRIVATE"</returns>
       public Dictionary<string, string> createKeyPair()
       {
           Dictionary<string, string> keyPair = new Dictionary<string, string>();
           RSACryptoServiceProvider provider = new RSACryptoServiceProvider(1024);
           keyPair.Add("PUBLIC", provider.ToXmlString(false));
           keyPair.Add("PRIVATE", provider.ToXmlString(true));
           return keyPair;
       }  

如此处生成的公钥为

<RSAKeyValue>
    <Modulus>t+56m5jXXonAJAKC7mgkhAZX5gWJTZojbSloLpLBGEWiebFaM+aUUKALfRx83/HaUV79ZiR3zuLJOLBdALx1cmcPk/b9fdNblLmzqi4cfSnfmMLWh05xf+ZS1pKHSKQtui3dfuu+3XH6Ak+S38dpIZUj/hihQQuKysN6GJ9h+c8=
    </Modulus>
    <Exponent>AQAB</Exponent>
</RSAKeyValue>  

在客户端(Java)对C#提供的公钥提取Modulus和Exponent

/**
     * 返回包含模数modulus和指数exponent的haspMap
     * @return
     * @throws MalformedURLException
     * @throws DocumentException
     */
    public static HashMap<String,String> rsaParameters(String xmlPublicKey) throws MalformedURLException, DocumentException{
        HashMap<String ,String> map = new HashMap<String, String>();
        Document doc = DocumentHelper.parseText(xmlPublicKey);
        String mudulus = (String) doc.getRootElement().element("Modulus").getData();
        String exponent = (String) doc.getRootElement().element("Exponent").getData();
        map.put("mudulus", mudulus);
        map.put("exponent", exponent);
        return map;
    }  

用Modulus和Exponent产生公钥RSAPublicKey(java)

这里有个关键步骤先对Mudolus和Exponent进行Base64解码,这个是由于C#生成的密钥对,其参数已经过Base64编码成String类型,而java RSA参数是未经base64编码的byte[]类型。

至于Base64编码、解码方法,参考这篇文章,java 编码和解码,想详细。

public static byte[] decodeBase64(String input) throws Exception{
        Class clazz=Class.forName("com.sun.org.apache.xerces.internal.impl.dv.util.Base64");
        Method mainMethod= clazz.getMethod("decode", String.class);
        mainMethod.setAccessible(true);
         Object retObj=mainMethod.invoke(null, input);
         return (byte[])retObj;
    }  

    /**
     * 返回RSA公钥
     * @param modules
     * @param exponent
     * @return
     */
    public static PublicKey getPublicKey(String modulus, String exponent){
        try {
            byte[] m = decodeBase64(modulus);
            byte[] e = decodeBase64(exponent);
            BigInteger b1 = new BigInteger(1,m);
            BigInteger b2 = new BigInteger(1,e);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            RSAPublicKeySpec keySpec = new RSAPublicKeySpec(b1, b2);
            return (RSAPublicKey) keyFactory.generatePublic(keySpec);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }  

获得公钥后就可以进行RSA加密处理了,这里还有一点需要提的是,RSA加密解密都有最大长度限制,加密最大长度为117字节,解密最大长度是128字节,此外,此处加密得到的数据是经过Base64编码处理的

public static String encrypt(byte[] source, PublicKey publicKey) throws Exception   {
        String encryptData ="";
        try {
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            int length = source.length;
            int offset = 0;
            byte[] cache;
            ByteArrayOutputStream outStream = new ByteArrayOutputStream();
            int i = 0;
            while(length - offset > 0){
                if(length - offset > MAXENCRYPTSIZE){
                    cache = cipher.doFinal(source, offset, MAXENCRYPTSIZE);
                }else{
                    cache = cipher.doFinal(source, offset, length - offset);
                }
                outStream.write(cache, 0, cache.length);
                i++;
                offset = i * MAXENCRYPTSIZE;
            }
            return encodeBase64(outStream.toByteArray());
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        }
        return encryptData;
    }  

加密后的数据提交给C#服务器端进行解密,当然,这里也要注意最大长度限制问题

/// <summary>
        /// RSA解密
        /// </summary>
        /// <param name="encryptData">经过Base64编码的密文</param>
        /// <param name="privateKey">私钥</param>
        /// <returns>RSA解密后的数据</returns>
        public static string decrypt(string encryptData, string privateKey)
        {
            string decryptData = "";
            try
            {
                RSACryptoServiceProvider provider = new RSACryptoServiceProvider();
                provider.FromXmlString(privateKey);
                byte[] bEncrypt = Convert.FromBase64String(encryptData);
                int length = bEncrypt.Length;
                int offset = 0;
                string cache ;
                int i = 0;
                while (length - offset > 0)
                {
                    if (length - offset > MAXDECRYPTSIZE)
                    {
                        cache = Encoding.UTF8.GetString(provider.Decrypt(getSplit(bEncrypt, offset, MAXDECRYPTSIZE), false));
                    }
                    else
                    {
                        cache = Encoding.UTF8.GetString(provider.Decrypt(getSplit(bEncrypt, offset, length - offset), false));
                    }
                    decryptData += cache;
                    i++;
                    offset = i*MAXDECRYPTSIZE;
                }
            }
            catch(Exception e)
            {
                throw e;
            }
            return decryptData;
        }  

        /// <summary>
        /// 截取字节数组部分字节
        /// </summary>
        /// <param name="input"></param>
        /// <param name="offset">起始偏移位</param>
        /// <param name="length">截取长度</param>
        /// <returns></returns>
        private static byte[] getSplit(byte[] input, int offset, int length)
        {
            byte[] output = new byte[length];
            for (int i = offset; i < offset + length; i++)
            {
                output[i - offset] = input[i];
            }
            return output;
        }  

这样,就顺利完成了。

经过测试,这样做的确得到了正确的结果。

若是有什么地方有问题,还望大家指正!

时间: 2024-12-13 15:15:56

C# Java间进行RSA加密解密交互的相关文章

C# 与JAVA 的RSA 加密解密交互,互通,C#使用BouncyCastle来实现私钥加密,公钥解密的方法

因为C#的RSA加密解密只有公钥加密,私钥解密,没有私钥加密,公钥解密.在网上查了很久也没有很好的实现.BouncyCastle的文档少之又少.很多人可能会说,C#也是可以的,通过Biginteger开源类来实现,不过那个是有一个文章,不过他加密出来的是16进制结果的.根本不能和JAVA互通.连加密出来的都不和C#原生的加密出来的结果格式一样.所以还是没有好的解决方法. 接下来还是不断的找资料,找方法.找朋友找同事.个个都找.问题是有的,方法也是有的,所以总结各路大神之后写了这个类.实现了私钥加

Java &amp; PHP &amp; Javascript 通用 RSA 加密 解密 (长字符串)

系统与系统的数据交互中,有些敏感数据是不能直接明文传输的,所以在发送数据之前要进行加密,在接收到数据时进行解密处理:然而由于系统与系统之间的开发语言不同. 本次需求是生成二维码是通过java生成,由php来解密.基于这类需求所以选择了RSA进行加解密. 生成RSA公私钥分成三步生成RSA公私钥,第1.2步可以满足php的使用,由于java的私钥要转化为PKCS8格式才能使用,所以执行第3步来实现. 还有一种加密方式参考: DES ECB 模式 JAVA PHP C# 实现 加密 解密 兼容 .

JAVA实现RSA加密解密 非对称算法

首先RSA是一个非对称的加密算法,所以在使用该算法加密解密之前,必须先行生成密钥对,包括公钥和私钥 JDK中提供了生成密钥对的类KeyPairGenerator,实例如下: public static Map<String, Object> genKeyPair() throws Exception { // 获取公钥私钥密钥对的生成器 KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); // 初始化确定密

Java使用RSA加密解密签名及校验

由于项目要用到非对称加密解密签名校验什么的,于是参考<Java加密解密的艺术>写一个RSA进行加密解密签名及校验的Demo,代码很简单,特此分享! RSA加密解密类: package com.ihep; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; imp

RSA加密解密及数字签名Java实现--转

RSA公钥加密算法是1977年由罗纳德·李维斯特(Ron Rivest).阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的.当时他们三人都在麻省理工学院工作.RSA就是他们三人姓氏开头字母拼在一起组成的. RSA是目前最有影响力的公钥加密算法,它能够抵抗到目前为止已知的绝大多数密码攻击,已被ISO推荐为公钥数据加密算法. RSA算法是一种非对称密码算法,所谓非对称,就是指该算法需要一对密钥,使用其中一个加密,则需要用另一个才能解密. 关于RSA算法

C#-java RSA加密解密

using Org.BouncyCastle.Math;using Org.BouncyCastle.Crypto.Parameters;using Org.BouncyCastle.Security;using Org.BouncyCastle.Asn1.X509;using Org.BouncyCastle.X509;using Org.BouncyCastle.Asn1.Pkcs;using Org.BouncyCastle.Pkcs;using System;using System.S

RSA加密解密及数字签名Java实现

RSA公钥加密算法是1977年由罗纳德·李维斯特(Ron Rivest).阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的.当时他们三人都在麻省理工学院工作.RSA就是他们三人姓氏开头字母拼在一起组成的.RSA是目前最有影响力的公钥加密算法,它能够抵抗到目前为止已知的绝大多数密码攻击,已被ISO推荐为公钥数据加密算法.RSA算法是一种非对称密码算法,所谓非对称,就是指该算法需要一对密钥,使用其中一个加密,则需要用另一个才能解密.关于RSA算法的原理

RSA加密解密及RSA加签验签

RSA安全性应用场景说明 在刚接触RSA的时候,会混淆RSA加密解密和RSA加签验签的概念.简单来说加密解密是公钥加密私钥解密,持有公钥(多人持有)可以对数据加密,但是只有持有私钥(一人持有)才可以解密并查看数据:加签验签是私钥加签公钥验签,持有私钥(一人持有)可以加签,持有公钥(多人持有)可以验签. 在金融行业在设计到数据交互传输的时候,需要考虑数据的安全性问题.下文通过介绍RSA的加密和加签两个特性,说明RSA加密技术在保障数据传输过程中的安全性以及实现数据的防篡改和防否机制的应用场景及代码

RSA加密解密(转)

RSA加密解密 对于RSA产生的公钥.私钥,我们可以有两种方式可以对信息进行加密解密.私钥加密-公钥解密 和 公钥加密-私钥解密RSA公钥加密算法是1977年由罗纳德·李维斯特(Ron Rivest).阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的.当时他们三人都在麻省理工学院工作.RSA就是他们三人姓氏开头字母拼在一起组成的. RSA是目前最有影响力的公钥加密算法,它能够抵抗到目前为止已知的绝大多数密码攻击,已被ISO推荐为公钥数据加密算法.