Java RSA/ECB/NoPadding in C# Python

某客户端中抠出来的代码,实现如下其中e(公钥指数)与n(模)硬编码在坑爹雷的某个客户端中。

public static PublicKey getPublicKey(String paramString1, String paramString2)  
  {
    RSAPublicKeySpec localRSAPublicKeySpec = new RSAPublicKeySpec(new BigInteger(paramString1, 16), new BigInteger(paramString2, 16));
    System.out.println(bytes2hex(localRSAPublicKeySpec.getModulus().toByteArray()));
    //00D6F1CFBF4D...
    System.out.println(bytes2hex(localRSAPublicKeySpec.getPublicExponent().toByteArray()));
    return KeyFactory.getInstance("RSA").generatePublic(localRSAPublicKeySpec);
  }
public static byte[] rsaEncode(PublicKey paramPublicKey, byte[] paramArrayOfByte)  
{
    Cipher localCipher = Cipher.getInstance("RSA/ECB/NoPadding");
    localCipher.init(1, paramPublicKey);
    return localCipher.doFinal(paramArrayOfByte);
}
public static byte[] encodeUseRSA(byte[] paramArrayOfByte, String paramString1, String paramString2)  
{
    byte[] arrayOfByte = rsaEncode(getPublicKey(paramString1, paramString2), paramArrayOfByte);
    return arrayOfByte;
}
String e = "010001";  
String n = "D6F1CFBF4D9F70710527E1B1911635460B1FF9AB7C202294D04A6F135A906E90E2398123C234340A3CEA0E5EFDCB4BCF7C613A5A52B96F59871D8AB9D240ABD4481CCFD758EC3F2FDD54A1D4D56BFFD5C4A95810A8CA25E87FDC752EFA047DF4710C7D67CA025A2DC3EA59B09A9F2E3A41D4A7EFBB31C738B35FFAAA5C6F4E6F";  
byte[] arrayOfByte = Rsa.encodeUseRSA("123456".getBytes(), n, e); 

JAVA中通过这两个参数就能生成localRSAPublicKeySpec对象,也就是RSA加密算法中的公钥,用来加密数据。注意到了他在加密过程使用的是不带填充的RSA/ECB/NoPadding,于是我们很高兴使用OPENSSL在Python写了类似下面的代码。

bnE=m2.hex to bn(e)
bnN=m2.hex to bn(n)
rsa = M2Crypto.RSA.new pub key((m2.bn to mpi(bnE), m2.bn to mpi(bnN)))
passwd = rsa.public encrypt(data='132456', padding=no padding).encode('hex')
好了!那么问题来了,OPENSSL并不支持NoPadding以及任意长度的填充,他要求明文必须与模长度一致。各种百度谷歌感觉没救,有不少遇到一样问题。为什么OPENSSL、.NET框架的加密库、python的第三方库 都没有RSA/ECB/NoPadding对应支持?肯定是有道理的,分析PKCS5(7)之类的填充算法是在Block中生成随机填充内容,这样就可以保证每次加密结果都不一样。既然知道了原理,那自己实现好了。RSA的实现原理其实和大多数非对称原理都一样,核心算法就是取模。乘以一个幂后做乘法。其实很简单。

RSA/ECB/NoPadding Python中的实现
注意这个n用的是JAVA高位多了个0的,为什么JAVA会在传入模前面加一位我就没弄明白了。。这也挺坑的

n = '00D6F1CFBF4D9F70710527E1B1911635460B1FF9AB7C202294D04A6F135A906E90E2398123C234340A3CEA0E5EFDCB4BCF7C613A5A52B96F59871D8AB9D240ABD4481CCFD758EC3F2FDD54A1D4D56BFFD5C4A95810A8CA25E87FDC752EFA047DF4710C7D67CA025A2DC3EA59B09A9F2E3A41D4A7EFBB31C738B35FFAAA5C6F4E6F'  
e = '010001'
import hashlib
def modpow(b, e, m):  
    result = 1
    while (e > 0):
        if e & 1:
            result = (result * b) % m
        e = e >> 1
        b = (b * b) % m
    return result
def str_to_int(string):  
    n = 0
    for i in range(len(string)):
        n = n << 8
        n += ord(string[i])
    return n
def rsa(data):  
    result = modpow(str_to_int(data), long(e, 16), long(n, 16))
    return hex(result).upper()[2:-1]

RSA/ECB/NoPadding C# .NET中顺便也TryTry,这里用了BigInteger也挺好用的,BigInteger的大端在右边需要做个Reverse。

    private void Form1_Load(object sender, EventArgs e)
    {
        byte[] n = new byte[] { 0x00, 0xD6, 0xF1, 0xCF, 0xBF, 0x4D, 0x9F, 0x70, 0x71, 0x05, 0x27, 0xE1, 0xB1, 0x91, 0x16, 0x35, 0x46, 0x0B, 0x1F, 0xF9, 0xAB, 0x7C, 0x20, 0x22, 0x94, 0xD0, 0x4A, 0x6F, 0x13, 0x5A, 0x90, 0x6E, 0x90, 0xE2, 0x39, 0x81, 0x23, 0xC2, 0x34, 0x34, 0x0A, 0x3C, 0xEA, 0x0E, 0x5E, 0xFD, 0xCB, 0x4B, 0xCF, 0x7C, 0x61, 0x3A, 0x5A, 0x52, 0xB9, 0x6F, 0x59, 0x87, 0x1D, 0x8A, 0xB9, 0xD2, 0x40, 0xAB, 0xD4, 0x48, 0x1C, 0xCF, 0xD7, 0x58, 0xEC, 0x3F, 0x2F, 0xDD, 0x54, 0xA1, 0xD4, 0xD5, 0x6B, 0xFF, 0xD5, 0xC4, 0xA9, 0x58, 0x10, 0xA8, 0xCA, 0x25, 0xE8, 0x7F, 0xDC, 0x75, 0x2E, 0xFA, 0x04, 0x7D, 0xF4, 0x71, 0x0C, 0x7D, 0x67, 0xCA, 0x02, 0x5A, 0x2D, 0xC3, 0xEA, 0x59, 0xB0, 0x9A, 0x9F, 0x2E, 0x3A, 0x41, 0xD4, 0xA7, 0xEF, 0xBB, 0x31, 0xC7, 0x38, 0xB3, 0x5F, 0xFA, 0xAA, 0x5C, 0x6F, 0x4E, 0x6F };
        byte[] et = new byte[] { 0x01, 0x00, 0x01 };
        var modulus = new BigInteger(n.Reverse().ToArray());
        var exponent = new BigInteger(et.Reverse().ToArray());
        var data = new BigInteger(Encoding.UTF8.GetBytes("123456").Reverse().ToArray());
        var result = BigInteger.ModPow(data, exponent, modulus);
        return BitConverter.ToString(result.ToByteArray().Reverse().ToArray()).Replace("-", "");
    }
添加新评论