java.security.InvalidKeyException:不支持的密钥类型:Sun RSA public 密钥,2048 位

java.security.InvalidKeyException: Unsupported key type: Sun RSA public key, 2048 bits

我想签署我的数据,为此我正在使用 Windows-MY 密钥库和 SunMSAPI 提供程序使用我的证书加密和解密一些文本。但有例外:

InvalidKeyException: Unsupported key type: Sun RSA public key, 2048 bits.

在线

aesCipher1.init(Cipher.DECRYPT_MODE, publicKey);

实际上我想用私钥加密我的数据并用 public 密钥解密。

我的系统配置是:Windows7、64位

如何处理这个问题?

我的代码是这样的:

X509Certificate c = (X509Certificate)keyStore.getCertificate(alias);
String serialNumber = c.getSerialNumber().toString();
Key privateKey = (Key) keyStore.getKey(DSCName, null);
Certificate[] chain = keyStore.getCertificateChain(DSCName);
DataOutputStream fout = new DataOutputStream(outstream);
  Provider p = keyStore.getProvider();
  String myData = "data to encrypt";
  PublicKey publicKey =  c.getPublicKey();

String cipherText = null;                   
final Cipher aesCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding",keyStore.getProvider().getName());
aesCipher.init(Cipher.ENCRYPT_MODE, privateKey);
byte[] byteDataToRate = myData.getBytes();
byte[] byteCipherText = aesCipher.doFinal(byteDataToRate);
cipherText = new BASE64Encoder().encode(byteCipherText);
System.out.println("cipherText:" + cipherText);
// ----------------------------
final Cipher aesCipher1 = Cipher.getInstance("RSA/ECB/PKCS1Padding",keyStore.getProvider().getName());
aesCipher1.init(Cipher.DECRYPT_MODE, public Key);

byte[] byteDecryptedText = aesCipher1.doFinal(byteCipherText);
System.out.println(byteDecryptedText);
String decryptedText = new String(byteDecryptedText);

我的输出是:

cipherText:f8/rPxpIgJXILNLSeESOCv2KYj4tomVIASAA45NLmBzA/iOWEsLJvCLYI9+pAqTwx7N8spWP+9HN
ZgaShxGPDjnVkqnuFlzbmXCZUCLMEbSULwzKQsSYMNIDq2x7J376g+GRm8kBYMdgGdNJtMIx8sXP
qvyWxNSWPdhe1xFna1w0DuqK1mR30/ZdU9lACyCMSeXK22K2FM+V7oDR9MHgbpB0oeHfH66emkk0
lpKqu6Wr9D43QwYmXAo/u/8gD3dwr7qdOwarTopfbCLqWfWn8DuyYTwDY/vbdiZJfPZfGNMrnhzq
/tdHm2ScNreskQ8HiMfeH0Iih8MPoiIVac+FVA==
java.security.InvalidKeyException: Unsupported key type: Sun RSA public key, 2048 bits
  modulus: 23713039584215334199359298536212699709102701257112982501126249760223003496547622902125282473933441681112130016090107773380054108139644420960634826102273499375704409005561487813169118425678603332231931611435818472883984384798084461353789618974581650786153976157396519738737858475541085942135666317196760918526775906883258164847855820472961868914809656826030205995272605151893433820872358865888343062850551910390809733698336903383894285445543225373616943057201233572494941972199152175995644435643142748595739783632001488705350282425460845827015899242784498630928265270728853274152332569674675710858589941739193789787683
  public exponent: 65537
eXCEPTION::
    at sun.security.mscapi.RSACipher.engineGetKeySize(RSACipher.java:345)
    at javax.crypto.Cipher.b(DashoA13*..)
    at javax.crypto.Cipher.a(DashoA13*..)
    at javax.crypto.Cipher.init(DashoA13*..)
    at javax.crypto.Cipher.init(DashoA13*..)
    at EncryptDecrypt.selectActionPerformed(EncryptDecrypt.java:530)
    at EncryptDecrypt.access(EncryptDecrypt.java:414)
    at EncryptDecrypt.actionPerformed(EncryptDecrypt.java:209)
    at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
    at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
    at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
    at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
    at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
    at java.awt.Component.processMouseEvent(Unknown Source)
    at javax.swing.JComponent.processMouseEvent(Unknown Source)
    at java.awt.Component.processEvent(Unknown Source)
    at java.awt.Container.processEvent(Unknown Source)
    at java.awt.Component.dispatchEventImpl(Unknown Source)
    at java.awt.Container.dispatchEventImpl(Unknown Source)
    at java.awt.Component.dispatchEvent(Unknown Source)
    at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
    at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
    at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
    at java.awt.Container.dispatchEventImpl(Unknown Source)
    at java.awt.Component.dispatchEvent(Unknown Source)
    at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
    at java.awt.EventQueue.access[=15=]0(Unknown Source)
    at java.awt.EventQueue.run(Unknown Source)
    at java.awt.EventQueue.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.AccessControlContext.doIntersectionPrivilege(Unknown Source)
    at java.security.AccessControlContext.doIntersectionPrivilege(Unknown Source)
    at java.awt.EventQueue.run(Unknown Source)
    at java.awt.EventQueue.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.AccessControlContext.doIntersectionPrivilege(Unknown Source)
    at java.awt.EventQueue.dispatchEvent(Unknown Source)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.run(Unknown Source)

虽然签名生成与使用RSA加密时的操作类似,但是Java有不同的类用于生成签名。

// sign
Signature instance = Signature.getInstance("SHA256withRSA");
instance.initSign(privateKey, new SecureRandom());
instance.update(myData.getBytes("UTF-8")); // encoding is important
byte[] signature = instance.sign();

// verify
instance.initVerify(publicKey);
instance.update(myData.getBytes("UTF-8")); // encoding is important
System.out.println(instance.verify(signature));

异常的原因是您正在使用 SunMSCAPI 提供程序进行 public key 操作,即不幸的是不可能。

只需删除这行代码中的 provider 参数即可:

final Cipher aesCipher1 = Cipher.getInstance("RSA/ECB/PKCS1Padding"); //,keyStore.getProvider().getName());
aesCipher1.init(Cipher.DECRYPT_MODE, publicKey);

背景信息:您的 public 密钥是 sun.security.rsa.RSAPublicKeyImpl 的实例,SunMSCAPI 提供程序的密码实现仅接受 sun.security.mscapi.RSAPrivateKey。这意味着您必须使用 SunMSCAPI 提供程序进行私钥操作,并使用 SunJCE 提供程序进行 public 密钥操作。

@Monika Tiwari,我面临同样的问题,我需要签署印度政府提供的数字证书。我已经编写了代码,但没有获取 RSAKey 值。

 KeyStore.PrivateKeyEntry keyEntry = CertUtils.getKeyEntryCertificate(alias);//return private key
x509Certificate = (X509Certificate) keyEntry.getCertificate();  
KeyInfoFactory keyInfoFactory = xmlSignatureFactory.getKeyInfoFactory();
List x509Content = new ArrayList();
x509Content.add(x509Certificate.getSubjectX500Principal().getName());
x509Content.add(x509Certificate);
X509Data x509Data = keyInfoFactory.newX509Data(x509Content);
KeyInfo keyInfo = keyInfoFactory.newKeyInfo(Collections.singletonList(x509Data));
document = documentBuildFactory.newDocumentBuilder().parse(inputFile);
DOMSignContext domSignContext = new DOMSignContext(keyEntry.getPrivateKey(),
document.getDocumentElement());
XMLSignature signature = xmlSignatureFactory.newXMLSignature(signedInfo, keyInfo);
signature.sign(domSignContext);
logger.log(Level.INFO, "Writing output xml file");
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
outputStream = objHttpServerConnection.writeFileFromHttpServer(objParam.getInputFilePath());
transformer.transform(new DOMSource(document), new StreamResult(outputStream));

请检查代码,签名数据中没有keyValue和RSAKeyValue标签的详细信息。在输出签名 xml 文件中只有带有 signatre 标签的 keyInfo 值。