日期:2014-05-18  浏览次数:21098 次

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);
            Bi