使用.NET进行公钥加密,使用Java进行解密

时间:2012-03-12 21:59:55

标签: c# java web-services encryption public-key-encryption

我有一个要求,即Java Web服务公开客户端获取PublickKey(作为PEM字符串)的方法,并将数据提交给由PublicKey加密的Web服务。该服务的客户端是.NET应用程序。在Java端,使用密钥对(RSA 1024位)创建密钥库,如下所示 keytool.exe -genkey -alias abc -keystore sample.ks -storetype jceks -storepass xyz

.NET客户端通过Web服务获取PublicKey,然后使用该公钥加密某些敏感数据,以使用加密数据调用Web服务。 Web服务使用从密钥库可用的私钥解密数据,并将内容存储在DB中。出于客户端兼容性原因,我无法使用任何WS-Security功能。

webservice读取密钥库并将公钥作为PEM字符串返回。 .NET客户端将PublicKey作为PEM字符串获取并使用它创建一个RSACryptoServiceProvider,它可以正常工作。然后它会对数据进行格式化并将其提交回Java Web服务。

Java服务解密数据但我遇到的问题是它打印出垃圾(不是ASCII数据)。我没有任何例外。

我已经附上了代码片段(简化)

.NET客户端

  var registrationService = new RegistrationService();
  var pKey = registrationService.getPublickey();
  //pKey is a PEM String
  X509Certificate2 cert = new X509Certificate2(ASCIIEncoding.ASCII.GetBytes(pKey));

    RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)cert.PublicKey.Key;

    var encryptedMsg = rsa.Encrypt(Encoding.UTF8.GetBytes("Secret Data"), false);
    var encoded_msg = Convert.ToBase64String(encryptedMsg);

    registrationService.submitRegistration(encoded_msg);

Java Side:

   public void submitRegistration(String inputData)
   {
   //Decoding the encoded and encrypted message in the webservice      
   PrivateKey privateKey = getPrivateKeyFromKeyStore("abc");
   //I know I am using JDK proprietary classes, but I can easily replace this
   byte[] dataInBytes = new Base64Decoder().deodeBuffer(inputData)

   Cipher cipher = Cipher.getInstance("RSA/ECB/NoPadding"); 
   cipher.init(Cipher.DECRYPT_MODE, privateKey);
   byte[] decryptedData = cipher.doFinal(dataInBytes);          
   String original = new String(decryptedData, "UTF-8");
   System.out.println("Original Data : " + original);
}
  public String getPublicKey()
  {
    Certificate cert = getKeyStore().getCertificate("abc");
    byte[] encodedCert = cert.getEncoded();
    StringWriter sw = new StringWriter();
    sw.write("-----BEGIN PUBLIC KEY-----");
    sw.write(new Base64Encoder().encode(encodedCert));
    sw.write("-----END PUBLIC KEY-----");
    return sw.toString();
  }

1 个答案:

答案 0 :(得分:2)

有一点需要注意的是,你在Java端使用“NOPADDING”,但.NET正在使用PKCS1Padding。

由于PKCS1填充垫在高位端具有0x00 0x02的明文,这也为解密端提供了一种检查它是否使用正确的私钥的方法。但请注意,错误密钥解密为以0x00 0x02开头的明文的可能性至少为1/65536,因此不能完全依赖此检查来检测不正确的私钥。在您的情况下,您使用了错误的密钥,并且明文未通过此检查,因此您收到了异常。现在,当您指定NOPADDING时,您说所有明文都是有效的,并且您的应用程序将进行任何进一步的检查。