如何将 Java RSA public 密钥移植到 c# 加密功能?

How to porting Java RSA public key to c# encrypt function?

想在 java 中使用生成的 RSA public 密钥,在 c# 函数中加密数据并在 Java 解密函数中解密。

生成的 Java public 密钥已在 c# 的 Modulus 标记中替换:

static string publicKey = "<RSAKeyValue><Modulus>MFwwDQ...wEAAQ==</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";

C# 加密函数:

  static string Encrypt(string text)
    {
        const int PROVIDER_RSA_FULL = 1;
        const string CONTAINER_NAME = "Tracker";

        CspParameters cspParams;
        cspParams = new CspParameters(PROVIDER_RSA_FULL);
        cspParams.KeyContainerName = CONTAINER_NAME;
       
        RSACryptoServiceProvider rsa1 = new RSACryptoServiceProvider(512,cspParams);
        rsa1.FromXmlString(publicKey);

        byte[] textBytes = Encoding.UTF8.GetBytes(text);
        byte[] encryptedOutput = rsa1.Encrypt(textBytes, RSAEncryptionPadding.Pkcs1);
        string outputB64 = Convert.ToBase64String(encryptedOutput);

        return outputB64;
    }

Java解密函数:

static String Decrypt(String encodedString,PrivateKey privKey) {
    try {
        Cipher cipher = Cipher.getInstance(cipherInstancename);
        cipher.init(Cipher.DECRYPT_MODE, privKey);
        byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(encodedString));
        return new String(decrypted, "UTF-8");
    } catch (Exception err) {
        return err.fillInStackTrace().toString();
    }
}

第一个问题:在c#XML字符串中替换Modulus标签中的Javapublic键是否正确?指数标签呢?我使用了 AQAB 值。

第二个问题:为什么在Java解密时出现这个错误:

 javax.crypto.IllegalBlockSizeException: Data must not be longer than 64 bytes

经过一些研究,我发现这是一个一般错误,什么原因会导致这种类型的错误?

First question: Is it correct to replace Java public key in Modulus tag in c# XML string?

没有!密钥与模数不同,但包含模数和指数。因此,在您的情况下,两者都必须根据 Java.

中生成的密钥来确定

一个public键可以以不同的格式给出。例如,在本机 Java 中生成的 public 密钥通常具有 X.509/SPKI 格式,并且可能是 byte[],即 DER 编码。如果 byte[] 是 Base64 编码的(这对应于发布的 MFwwDQ...wEAAQ==)并且 header -----BEGIN PUBLIC KEY---- -和页脚-----END PUBLIC KEY-----是加的(一般在Base64编码的body里面也是每 64 个字符后换行),密钥将采用 PEM 编码。

手动确定模数和指数的最简单方法是在 ASN.1 解析器中加载 PEM 密钥,例如here, or to convert it directly into the XML format on a suitable website, e.g. here.

What about the Exponent tag? I used AQAB value for it.

这个问题已经用前面说的含蓄地回答了。但有一点要注意:对于指数,值 65537(十六进制编码 0x010001 和 Base64 编码 AQAB)是经常选择。但是,并非总是如此。因此,如果现有密钥的指数被 盲目 替换为该值,则它很有可能会起作用,但您不能依赖它,请参见例如here and here.

The Second question: Why on decrypting in Java got this error: javax.crypto.IllegalBlockSizeException: Data must not be longer than 64 bytes?

这已经在 Michael Fehr 的评论中得到了回答,以及其他重要点(例如安全性、性能和混合加密):密钥长度限制了明文的长度,512 位密钥最多 64 字节可以加密。

此外,需要注意的是,不仅密钥的长度,而且使用的填充也限制了明文的长度,例如PKCS#1 v1.5 填充需要 11 个字节,因此 512 位密钥的最大明文长度为 64 - 11 = 53 个字节,here. In the case of OAEP the digest used determines how many bytes the padding requires, see e.g. here。如果不使用填充(tetxbook RSA),则明文的最大长度对应于密钥长度。然而,实际上,出于安全原因,必须始终使用填充


从 .NET Core 3.0 开始,直接 支持导入 X.509/SPKI 密钥(采用 DER 编码)和类似格式,参见例如here and especially RSA.ImportSubjectPublicKey。在早期的 .NET Core 版本和 .NET Framework 中,这些函数不可用,但可以使用 BouncyCastle