`
goodjin
  • 浏览: 33190 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

RSA加密算法实现以及C#与java互通加解密

阅读更多

 

一.RSA算法简介

关于RSA加密算法可以参考:http://zh.wikipedia.org/wiki/RSA%E5%8A%A0%E5%AF%86%E6%BC%94%E7%AE%97%E6%B3%95

大体是先生成两个大素数p和q,再生成e,e和(p-1)*(q-1)互素。

取p和q的乘积:n=p*q 为公共模数。

再生成正整数d,满足d*e-1可以被(p-1)*(q-1)整除。

这样d就为私钥,(e,n)为公钥,形成rsa的公私钥对。

其中n的二进制位称为该密钥长度,密钥越长越难破解,也就越安全。

二.填充算法

由于密钥长度有限,一次性加密的数据长度也有限,因此必须对明文进行分块加密,再合并加密结果。

以1024位密钥为例,n为1024位,即128个字节,则明文需要分块成每块长128个字节,不足128位的使用特定格式的数据填充。

所以分块的算法称为填充算法,有不同的标准,如NoPPadding、OAEPPadding、PKCS1Padding等。

本文实现的是PKCS1Padding填充算法,规范文档是这个:http://man.chinaunix.net/develop/rfc/RFC2313.txt

该算法规定的格式如下:

00 || BT || PS || 00 || D

其中BT可选择01和02,01表示私钥加密,02表示公钥加密。如果BT是01则PS需要使用oxFF填充,为02的话则需要使用随机非0填充。D表示分割的明文块。

PS的长度至少为8个字节,因此D至多只能为128-8-2=117个字节长。

三.C#实现

之所以要使用C#实现是因为官方版本只实现了公钥加密且在明文中间增加了一些数字再进行的加密,使用私钥解密出来后需要去除增加的数字。

而要实现私钥加密则只能自己实现了,这里使用到了一个大整数类:BigInteger。我是从这里下载的:http://www.codeproject.com/Articles/2728/C-BigInteger-Class

C#里生成公私钥对可以使用如下代码:

RSACryptoServiceProvider key = new RSACryptoServiceProvider();
RSAParameters param = key.ExportParameters(true);
Console.WriteLine(Convert.ToBase64String(param.Modulus));
Console.WriteLine(Convert.ToBase64String(param.Exponent));
Console.WriteLine(Convert.ToBase64String(param.D));

其中Modulus+Exponent为公钥,D为私钥,C#里是以base64格式保存的。

填充算法实现如下(blockLen为模的字节数,这里为128):

//填充
        private byte[] add_PKCS1_padding(byte[] oText, int blockLen)
        {      
            byte[] result = new byte[blockLen];
            result[0] = 0x00;
            result[1] = 0x01;  
            
            int padLen = blockLen - 3 - oText.Length;                       
            for (int i = 0; i < padLen; i++)
            {
                result[i + 2] = 0xff;
            }

            result[padLen + 2] = 0x00;

            int j = 0;
            for (int i = padLen + 3; i < blockLen; i++)
            {
                result[i] = oText[j++];                
            }
            
            return result;
        }

私钥加密方法如下:

//私钥加密
        private byte[] priEncrypt(byte[] block, RSACryptoServiceProvider key)
        {
            RSAParameters param = key.ExportParameters(true);
            BigInteger d = new BigInteger(param.D);
            BigInteger n = new BigInteger(param.Modulus);
            BigInteger biText = new BigInteger(block);
            BigInteger biEnText = biText.modPow(d, n);
            return biEnText.getBytes();
        }

则整个私钥加密方法可以如下进行:

//私钥加密
        public byte[] encryptByPriKey(String src, RSACryptoServiceProvider key){
            //获得明文字节数组
            byte[] oText = System.Text.Encoding.Default.GetBytes(src);
            //填充
            oText = add_PKCS1_padding(oText, 128);            
            //加密
            byte[] result = priEncrypt(oText, key);            
            return result;
        }  

加密结果为字节数组,可以转化为base64编码的字符串,但是建议转化为十六进制字符串,便于用于web传递。

对于大于128字节的明文,需要分成多段进行加密,使用本文的填充算法实现是大于117字节的明文就需要分段。

为了方便的web环境下的数据交换,可以对明文进行urlencode后再进行加密,这样解密后使用urldecode可以得到明文。

实现如下:

//url编码
            String urlEncode = System.Uri.EscapeDataString(src); 

            //以117个字符为长度分割字符串进行加密
            int index = 0;
            int len = urlEncode.Length;
            String toEncrypt = "";
            while (index < len)
            {
                String temp = "";
                if (index + 117 < len)
                {
                    temp = urlEncode.Substring(index, index + 117);
                }
                else
                {
                    temp = urlEncode.Substring(index);
                }

                //加密           
                byte[] encrypted = encryptByPriKey(temp, r);

                //转化为16进制字符串
                String enc = bytesToHexStr(encrypted);
                toEncrypt += enc;

                index += 117;
            }
            Console.WriteLine(toEncrypt);

对节字数组转化为十六进制字符串可以如下实现:

char[] bcdLookup = { '0', '1', '2', '3', '4', '5',
            '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };

        //字节转化为十六进制字符串
        public String bytesToHexStr(byte[] bcd) {
            String s  ="";

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

            return s;
        }

至此为止,我们便实现了C#的私钥加密算法实现。

C#的签名实现使用官方实现即可与java互通,应该是没有使用填充的原因。

C#签名和验证实现如下:

//明文转化为字节数组
            byte[] srcBytes = System.Text.Encoding.Default.GetBytes(src);

            //签名
            byte[] signed = key.SignData(srcBytes, "sha1");

            //转化为16进制字符串      
            String sign = nr.bytesToHexStr(signed);
            Console.WriteLine(sign);

            //验证
            bool verify = r.VerifyData(srcBytes, "sha1", signed);
            Console.WriteLine(verify);

使用此方法签名的数据可以使用java验证。由于是签名和验证,不需要还原数据,所以可以直接对明文加密,不需要使用urlencode。

 

四.结语

java所实现的算法有完整的一套框架,包括了各种填充算法,可以轻松实现公钥加密和解密,签名和验证等,本文就不再示例。

 

附:公钥解密实现

//公钥解密
        public String decryptByPubKey(String enc, RSACryptoServiceProvider key)
        {
            String result = "";
            int blockLen = 256;
            int i = 0;
            while (i < enc.Length)
            {
                String temp = enc.Substring(i, blockLen);

                byte[] oText = hexToBytes(temp);
                
                //解密
                byte[] dec = pubDecrypt(oText, key);

                //去除填充
                dec = remove_PKCS1_padding(dec);

                result += System.Text.Encoding.Default.GetString(dec);

                i += blockLen;
            }
            return result;
        }

        //公钥解密
        private byte[] pubDecrypt(byte[] block, RSACryptoServiceProvider key)
        {
            RSAParameters param = key.ExportParameters(true);            
            BigInteger e = new BigInteger(param.Exponent);
            BigInteger n = new BigInteger(param.Modulus);
            BigInteger biText = new BigInteger(block);
            BigInteger biEnText = biText.modPow(e, n);
            return biEnText.getBytes();
        }

        //去除填充
        private byte[] remove_PKCS1_padding(byte[] oText)
        {
            int i = 2;
            byte b = (byte)(oText[i] & 0xff);
            while (b != 0)
            {
                i++;
                b = (byte)(oText[i] & 0xff);
            }
            byte[] result = new byte[oText.Length - i];
            int j = 0;
            while (i < oText.Length)
            {
                result[j++] = oText[i++];
            }
            return result;
        }

        //十六进制字符串转化成字节数组
        public byte[] hexToBytes(String s)
        {
            byte[] bytes = new byte[s.Length / 2];

            for (int i = 0; i < bytes.Length; i++)
            {
                bytes[i] = (byte)Convert.ToInt32(s.Substring(2 * i, 2), 16);
            }

            return bytes;
        }
分享到:
评论

相关推荐

    C#RSA加密与JAVA解密,实现相互通信

    "C# RSA加密与JAVA解密,实现相互通信"的主题聚焦于如何利用RSA公钥/私钥加密算法在C#和Java两个不同的编程环境中实现安全的数据交换。RSA是一种非对称加密算法,它使用一对密钥——公钥和私钥,公钥用于加密,私钥...

    C# 实现与JAVA互通 加签/验签,RSA加密/解密

    * RSA加密解密:私钥解密,公钥加密。 * RSA数字签名-俗称加签验签:私钥加签,公钥验签。  * RSA加密解密:私钥解密,公钥加密。 * RSA数字签名-俗称加签验签:私钥加签,公钥验签。  * RSA加密解密:私钥...

    C#和Java实现互通的RSA&DES加解密算法

    C#和Java中都有内置的类库支持RSA加密,如C#的System.Security.Cryptography.RSACryptoServiceProvider和Java的java.security.KeyPairGenerator与java.security.Signature等。 接下来,我们讨论DES(Data ...

    C#与java平台RSA加密解密签名验签互通案例

    本案例聚焦于"C#与Java平台RSA加密解密签名验签互通"的问题,这涉及到两个主要的技术点:RSA加密算法和跨平台兼容性。下面将详细阐述这两个知识点。 首先,RSA是一种非对称加密算法,由Ron Rivest、Adi Shamir和...

    C#Android互通RSA加密解密

    总结来说,"C# Android互通RSA加密解密"涉及了跨平台数据安全传输的核心技术,包括RSA加密算法的原理与应用,以及在C#和Android环境下的具体实现。通过合理的密钥管理,可靠的传输协议,以及详尽的测试,可以实现两...

    RSA-encryption-between-CSharp-and-java.rar_between_rsa_rsa cshar

    根据压缩包内的文件名"RSA加密算法实现以及C#与java互通加解密-ASP.NET-第七城市.pdf",我们可以预期文件会详细解释以下几点: 1. RSA算法的理论基础,包括数学原理和加密过程。 2. C#中实现RSA加密解密的步骤和...

    c/c++与java互通 AES加密解密

    总的来说,"C/C++与Java互通AES加密解密"是一个挑战性的任务,需要对加密算法、数据类型转换、内存管理以及跨平台通信有深入的理解。通过这个实践,开发者可以提升自己的编程技巧,并对数据安全有更深刻的认识。

    RSA算法,C#与java互通demo模块核心代码

    在C#和Java这两种不同的编程语言中实现RSA互通,通常需要处理的关键点包括密钥对的生成、密钥的序列化与反序列化、以及正确的加解密过程。以下是这些关键点的详细说明: 1. **密钥对生成**:RSA算法首先需要生成...

    C#和Java关于RSA非对称加密互通类

    总之,通过理解和实现这些方法,你可以构建一个能够在C#和Java之间无缝工作的RSA加密解密系统。这种互通性对于跨平台的项目尤其重要,它允许不同语言的系统安全地交换加密数据。在实际应用中,还需注意密钥的安全...

    Delphi(delphi7-XE)标准RSA加密,解密,签名.与C,Java,php等通用

    本篇文章将深入探讨Delphi (从delphi7到XE版本)中的RSA实现,以及如何与其他编程语言如C、Java、PHP进行跨平台的加解密和签名操作。 1. RSA原理: RSA基于数论中的大数因子分解难题,由Ron Rivest、Adi Shamir和...

    RSA算法Android C#互通

    它的主要特点是使用一对公钥和私钥进行加解密,其中公钥可以公开,而私钥必须保密。在Android和C#之间进行数据安全传输时,RSA算法常被用于确保数据的机密性和完整性。 在“RSA算法Android C#互通”这个场景下,...

    Java RSA加密 与.net 的密匙转换完整版,java类

    本资源提供的"Java RSA加密与.NET的密匙转换完整版,java类"解决了这个问题,实现了Java RSA密钥对到C#格式的转换,确保了跨平台的互通性。 `RsaHelper.java`是这个解决方案的核心文件,它可能包含了以下关键功能:...

    RSA+AES C# .net版本已经与java,js等语言对接均可以互通

    在给定的标题和描述中,提到了两种主要的加密算法:RSA和AES,并且强调了这些C#实现的加密方法已经与其他编程语言(如Java和JavaScript)实现了互通。下面将详细阐述这两种加密算法以及它们在实际应用中的使用。 ...

    Rsa 私钥加密 公钥解密

    这个压缩包文件的标题和描述提及了“Rsa 私钥加密 公钥解密”,这意味着我们将探讨如何使用RSA算法进行私钥加密和公钥解密的过程,以及在不同编程语言如JAVA、C#、PHP之间的互通性。 首先,RSA加密的基础是大数因子...

    私钥加密公钥解密JAVA、C#、PHP互通

    私钥加密公钥解密是一种基于非对称加密算法的安全通信方法,广泛应用于网络通信、数据保护和身份验证等领域。这种技术的核心在于一对密钥,包括一个私钥和一个公钥,私钥是保密的,只有拥有者知道,而公钥可以公开...

    同时兼容JS和C#的RSA加密解密算法详解(对web提交的数据加密传输)

    前言 我们在Web应用中往往涉及到敏感的数据,由于HTTP协议以明文的形式与服务器进行交互,因此可以通过截获请求的...这个也给贯通前后台的RSA加密解密带来了难度。为了兼容OpenSSL生成的公钥/私钥文件格式,贯通jav

    ICH.BouncyCastle

    语言互通问题(如C#、Java等)(加解密本质上没有语言之分,所以原则上不存在互通性问题) 网上资料版本不一、或不全面 .NET官方库密码算法提供不全面,很难针对其他语言(Java)进行适配 本系列文章主要介绍如何在 ...

Global site tag (gtag.js) - Google Analytics