如何将Java RSA公钥移植到C#加密函数?

huangapple go评论95阅读模式
英文:

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

问题

以下是您要翻译的内容:

想要在 Java 中使用生成的 RSA 公钥,在 C# 函数中加密数据并在 Java 解密函数中解密。

已经将生成的 Java 公钥替换在 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 标签替换 Java 公钥是否正确?那 Exponent 标签呢?我为它使用了 AQAB 值。

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

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

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

英文:

Want to use generated RSA public key in java, in c# function to encrypt data and decrypt it in Java decrypt function.

Generated Java public key has been replaced in Modulus tag in c#:

static string publicKey = &quot;&lt;RSAKeyValue&gt;&lt;Modulus&gt;MFwwDQ...wEAAQ==&lt;/Modulus&gt;&lt;Exponent&gt;AQAB&lt;/Exponent&gt;&lt;/RSAKeyValue&gt;&quot;;

C# Encrypt function:

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

        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 Decrypt function:

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, &quot;UTF-8&quot;);
    } catch (Exception err) {
        return err.fillInStackTrace().toString();
    }
}

First question: Is it correct to replace Java public key in Modulus tag in c# XML string? What about the Exponent tag? I used AQAB value for it.

The Second question: Why on decrypting in Java got this error:

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

After some research I found, it's a general error what cause can make this type of error?

答案1

得分: 4

> 第一个问题:在 C# 的 XML 字符串中替换 Java 公钥中的 Modulus 标签是否正确?

不正确!密钥不仅包含模数(Modulus),还包含指数(Exponent)。因此,在你的情况下,这两者都必须从在 Java 中生成的密钥中确定。

公钥可以有不同的格式。例如,在原生 Java 中生成的公钥通常具有 X.509/SPKI 格式,可能是一个 byte[],即以 DER 编码形式。如果这个 byte[] 经过 Base64 编码(这对应于发布的 MFwwDQ...wEAAQ==),并且添加了头部 -----BEGIN PUBLIC KEY----- 和尾部 -----END PUBLIC KEY-----(通常在经过 Base64 编码的主体每 64 个字符后会有一个换行),那么密钥将以 PEM 编码形式呈现。

手动确定模数和指数的最简单方法是在 ASN.1 解析器中加载 PEM 密钥,例如这里,或者直接在适当的网站上将其转换为 XML 格式,例如这里

> 那 Exponent 标签呢?我使用了 AQAB 的值。

这个问题在前面的回答中已经隐含地得到了解答。但需要注意一点:指数通常选择值 65537(十六进制编码为 0x010001,Base64 编码为 AQAB)。但这并不总是适用的。因此,如果将现有密钥的指数 盲目 替换为这个值,很有可能会起作用,但不能完全依赖它,详见这里这里

> 第二个问题:为什么在 Java 解密时会出现错误:javax.crypto.IllegalBlockSizeException: Data must not be longer than 64 bytes

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

此外,还应注意不仅密钥的长度限制了明文的长度,使用的填充方式也会限制明文的长度,例如 PKCS#1 v1.5 填充需要 11 个字节,因此 512 位密钥的最大明文长度为 64 - 11 = 53 字节,详见这里。在使用 OAEP 时,所使用的摘要决定了填充所需的字节数,详见这里。如果不使用填充(纯文本 RSA),则明文的最大长度等于密钥长度。然而在实际应用中,出于安全原因,始终需要使用填充。


从 .NET Core 3.0 开始,直接支持导入 X.509/SPKI 密钥(以 DER 编码)等类似格式,详见这里,特别是 RSA.ImportSubjectPublicKey。在较早的 .NET Core 版本和 .NET Framework 中,这些函数不可用,但可以使用 BouncyCastle 来代替。

英文:

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

No! The key is not identical to the modulus, but contains the modulus and the exponent. Therefore, in your case both must be determined from the key generated in Java.

A public key can be given in different formats. For example, a public key generated in native Java will usually have the X.509/SPKI format and will probably be a byte[], i.e. in DER encoding. If the byte[] is Base64 encoded (this corresponds to the posted MFwwDQ...wEAAQ==) and the header -----BEGIN PUBLIC KEY----- and the footer -----END PUBLIC KEY----- are added (usually in the Base64 encoded body there is also a line break after every 64 characters), the key will be in PEM encoding.

The easiest way to determine the modulus and exponent manually is to load the PEM key in an ASN.1 parser, e.g. 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.

This question has already been answered implicitly with what was said before. But one remark: For the exponent the value 65537 (hex encoded 0x010001 and Base64 encoded AQAB) is often chosen. But this is not always the case. So if the exponent of an existing key is blindly replaced by this value, there is a high probability that it will work, but you cannot rely on it, see e.g. 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?

This has already been answered in Michael Fehr's comment, among other important points (such as security, performance and hybrid encryption): The key length limits the length of the plaintext, with a 512 bit key a maximum of 64 bytes can be encrypted.

Additionally, it should be noted that not only the length of the key but also the padding used limits the length of the plaintext, e.g. PKCS#1 v1.5 Padding requires 11 bytes, so the maximum plaintext length for a 512 bit key is 64 - 11 = 53 bytes, here. In the case of OAEP the digest used determines how many bytes the padding requires, see e.g. here. If no padding is used (tetxbook RSA), the maximum length of the plaintext corresponds to the key length. In practice, however, padding must always be used for security reasons.


Starting with .NET Core 3.0 the import of an X.509/SPKI key (in DER encoding) and similar formats is directly supported, see e.g. here and especially RSA.ImportSubjectPublicKey. In earlier .NET Core versions and in .NET Framework these functions are not available, but BouncyCastle can be used instead.

huangapple
  • 本文由 发表于 2020年8月29日 05:27:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/63641058.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定