RSA C#加密Java解密

时间:2010-05-28 15:16:09

标签: c# java client rsa

在我的程序(服务器端 - 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
你能帮助我吗? 谢谢,谢谢,

3 个答案:

答案 0 :(得分:1)

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

HTH 麦克

答案 1 :(得分:1)

使用BigInteger在Java中进行十六进制解码的方法在很多时候会产生错误的结果,因为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中有短暂的寿命。在this msdn link处有很多解决方案的好方法。

答案 2 :(得分:0)

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

C#SIDE (客户端)

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

问题在于C#Side上的Hex-Encryption在Java端完全不同。谢谢GregS,你是最好的;)