RSA C# 加密 Java 解密

发布于 2024-09-03 00:19:55 字数 1596 浏览 2 评论 0原文

在我的程序(服务器端 - Java)中,我使用命令创建了密钥库文件:

keytool -genkey -alias myalias -keyalg RSA -validity 10000 -keystore my.keystore

并使用以下命令导出了相关的 X509 证书:

keytool -export -alias myalias -file cert.cer -keystore my.keystore

在客户端(C#)上保存 cert.cer 后,我编写了此代码:

X509Certificate2 x509 = new X509Certificate2();
byte[] rawData = ReadFile("mycert.cer");
x509.Import(rawData);

RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)x509.PublicKey.Key;
byte[] plainbytes = System.Text.Encoding.ASCII.GetBytes("My Secret");
byte[] cipherbytes = rsa.Encrypt(plainbytes, true);
String cipherHex = convertToHex(cipherContent);
byte[] byteArray = encoding.GetBytes(cipherHex);

....

我在以下位置编写了此 Java 代码 :服务器端:

keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(new FileInputStream("C:\\my.keystore"), "mypass".toCharArray());
Key key = keyStore.getKey("myalias", "mypass".toCharArray());
if (key instanceof PrivateKey) {
    Certificate cert = keyStore.getCertificate("myalias");
    PublicKey pubKey = cert.getPublicKey();
    privKey = (PrivateKey)key;
}
byte[] toDecodeBytes = new BigInteger(encodeMessageHex, 16).toByteArray();
Cipher decCipher = Cipher.getInstance("RSA");
decCipher.init(Cipher.DECRYPT_MODE, privKey);
byte[] decodeMessageBytes = decCipher.doFinal(toDecodeBytes);
String decodeMessageString = new String(decodeMessageBytes);

我收到此错误:

javax.crypto.BadPaddingException: Data must start with zero

你能帮我吗? 谢谢谢谢,

In my program (server side - Java) I've created keystore file, with command:

keytool -genkey -alias myalias -keyalg RSA -validity 10000 -keystore my.keystore

and exported related X509 certificate with:

keytool -export -alias myalias -file cert.cer -keystore my.keystore

After I saved cert.cer on client side (C#) and I write this code:

X509Certificate2 x509 = new X509Certificate2();
byte[] rawData = ReadFile("mycert.cer");
x509.Import(rawData);

RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)x509.PublicKey.Key;
byte[] plainbytes = System.Text.Encoding.ASCII.GetBytes("My Secret");
byte[] cipherbytes = rsa.Encrypt(plainbytes, true);
String cipherHex = convertToHex(cipherContent);
byte[] byteArray = encoding.GetBytes(cipherHex);

....

I write this Java code on server side:

keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(new FileInputStream("C:\\my.keystore"), "mypass".toCharArray());
Key key = keyStore.getKey("myalias", "mypass".toCharArray());
if (key instanceof PrivateKey) {
    Certificate cert = keyStore.getCertificate("myalias");
    PublicKey pubKey = cert.getPublicKey();
    privKey = (PrivateKey)key;
}
byte[] toDecodeBytes = new BigInteger(encodeMessageHex, 16).toByteArray();
Cipher decCipher = Cipher.getInstance("RSA");
decCipher.init(Cipher.DECRYPT_MODE, privKey);
byte[] decodeMessageBytes = decCipher.doFinal(toDecodeBytes);
String decodeMessageString = new String(decodeMessageBytes);

I receive this error:

javax.crypto.BadPaddingException: Data must start with zero

Can you help me, please?
Thanks thanks,

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

一片旧的回忆 2024-09-10 00:19:55

在 Java 中使用 BigInteger 进行十六进制解码的方法大多数时候会产生错误的结果,因为 Java BigInteger 类编码的值的高位字节 >= 128,并且前面有一个额外的零字节。使用 Apache commons 编解码器进行十六进制编码/解码。

编辑:您的 C# 代码不正确。有一个 .NET 类 System.Runtime.Remoting.Metadata.W3cXsd2001.SoapHexBinary 将为您的 C# 代码执行十六进制编码/解码。以下 C# 代码片段应该工作得更好

public static String execute(String content)
{
    ASCIIEncoding encoding = new ASCIIEncoding();
    byte[] plainbytes = System.Text.Encoding.ASCII.GetBytes(content);
    byte[] cipherbytes = rsa.Encrypt(plainbytes, false);
    SoapHexBinary hexBinary = new SoapHexBinary(cipherbytes);
    String cipherHex = hexBinary.ToString();

    // This String is used on java side to decrypt
    Console.WriteLine("CIPHER HEX: " + cipherHex);
    return cipherHex;
}

编辑 2:

似乎 SoapHexBinary 类在 .NET 中的寿命可能很短。对于该问题,有许多好的解决方案 此 msdn 链接

Your method of hex-decoding in Java using BigInteger will produce the wrong result much of the time because the Java BigInteger class encodes a value whose high-order byte is >= 128 with an extra zero byte at the front. Use the Apache commons codec for hex en/de-coding.

EDIT: Your C# code is not correct. There is a .NET class System.Runtime.Remoting.Metadata.W3cXsd2001.SoapHexBinary that will do the hex en/de-coding for your C# code. The following C# code fragment should work better

public static String execute(String content)
{
    ASCIIEncoding encoding = new ASCIIEncoding();
    byte[] plainbytes = System.Text.Encoding.ASCII.GetBytes(content);
    byte[] cipherbytes = rsa.Encrypt(plainbytes, false);
    SoapHexBinary hexBinary = new SoapHexBinary(cipherbytes);
    String cipherHex = hexBinary.ToString();

    // This String is used on java side to decrypt
    Console.WriteLine("CIPHER HEX: " + cipherHex);
    return cipherHex;
}

EDIT 2:

Seems that SoapHexBinary class might have had a short life in .NET. There are a number of good solutions to the problem at this msdn link.

别把无礼当个性 2024-09-10 00:19:55

嗯,我还没有完全按照你在这里做的事情,我有一个必须做的 DES,但我遇到了同样的错误。诀窍是我必须在两侧获得兼容的 CipherModes 和 PaddingModes。对于我来说,csharp 端是 PaddingMode.PKCS7 和 CipherMode.CBC,而在 java 端我使用了 DESede/CBC/PKCS5Padding xform。


麦克风

Hm, I haven't done exactly what you are here, I had an DES one I had to do, and I was getting the same error. The trick was I had to get compatible CipherModes and PaddingModes on both sides. For mine it was PaddingMode.PKCS7 and CipherMode.CBC on the csharp side, and on the java side I used the DESede/CBC/PKCS5Padding xform.

hth
Mike

红衣飘飘貌似仙 2024-09-10 00:19:55

感谢 GregS 的回答,我找到了问题的解决方案。现在我发布这个。

C# 端(客户端)

X509Certificate2 x509 = new X509Certificate2();
byte[] rawData = ReadFile("mycert.cer");
x509.Import(rawData);

加载 X509Certificate 后,我调用执行方法:

public static String execute(String content)
{
    ASCIIEncoding encoding = new ASCIIEncoding();
    byte[] plainbytes = System.Text.Encoding.ASCII.GetBytes(content);
    byte[] cipherbytes = rsa.Encrypt(plainbytes, false);
    SoapHexBinary hexBinary = new SoapHexBinary(cipherbytes);
    String cipherHex = hexBinary.ToString();

    // This String is used on java side to decrypt
    Console.WriteLine("CIPHER HEX: " + cipherHex);
    return cipherHex;
}

JAVA 端(服务器端)

keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(new FileInputStream("C:\\my.keystore"), "mypass".toCharArray());
Key key = keyStore.getKey("myalias", "mypass".toCharArray());
if (key instanceof PrivateKey) {
    Certificate cert = keyStore.getCertificate("myalias");
    PublicKey pubKey = cert.getPublicKey();
    privKey = (PrivateKey)key;
}
byte[] toDecodeBytes = new BigInteger(encodeMessageHex, 16).toByteArray();
Cipher decCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
decCipher.init(Cipher.DECRYPT_MODE, privKey);
byte[] decodeMessageBytes = decCipher.doFinal(toDecodeBytes);
String decodeMessageString = new String(decodeMessageBytes);

问题出在 C# 端的十六进制加密中, Java 端完全不同。谢谢格雷格,你是最棒的;)

Thanks to GregS answers I found solution of my problem. Now I post this.

C# SIDE (Client-Side)

X509Certificate2 x509 = new X509Certificate2();
byte[] rawData = ReadFile("mycert.cer");
x509.Import(rawData);

After I loads my X509Certificate I call my execute method:

public static String execute(String content)
{
    ASCIIEncoding encoding = new ASCIIEncoding();
    byte[] plainbytes = System.Text.Encoding.ASCII.GetBytes(content);
    byte[] cipherbytes = rsa.Encrypt(plainbytes, false);
    SoapHexBinary hexBinary = new SoapHexBinary(cipherbytes);
    String cipherHex = hexBinary.ToString();

    // This String is used on java side to decrypt
    Console.WriteLine("CIPHER HEX: " + cipherHex);
    return cipherHex;
}

JAVA SIDE (Server-Side)

keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(new FileInputStream("C:\\my.keystore"), "mypass".toCharArray());
Key key = keyStore.getKey("myalias", "mypass".toCharArray());
if (key instanceof PrivateKey) {
    Certificate cert = keyStore.getCertificate("myalias");
    PublicKey pubKey = cert.getPublicKey();
    privKey = (PrivateKey)key;
}
byte[] toDecodeBytes = new BigInteger(encodeMessageHex, 16).toByteArray();
Cipher decCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
decCipher.init(Cipher.DECRYPT_MODE, privKey);
byte[] decodeMessageBytes = decCipher.doFinal(toDecodeBytes);
String decodeMessageString = new String(decodeMessageBytes);

The problem was in Hex-Encryption on C# Side that are completely different on Java side. Thanks GregS, you are the best ;)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文