'java.security.KeyException while decrypting using certificate's private key coming from Windows-MY on Windows Server version 10
when trying to do an encrypt/decrypt roundtrip using the public/private keys of a certificate as stored in the Certificate Manager (Windows-MY): this works on most Windows versions, but it fails on Windows Server 2022
OS Name: Microsoft Windows Server 2022 Standard
OS Version: 10.0.20348 N/A Build 20348
using the java version: openjdk version "1.8.0_322"
OpenJDK Runtime Environment (Temurin)(build 1.8.0_322-b06)
OpenJDK 64-Bit Server VM (Temurin)(build 25.322-b06, mixed mode)
see full code below.
On most Windows versions, the code/roundtrip works. However, on Windows Server 2022, encrypting works but when decrypting, I get the following exception:
java.security.ProviderException: java.security.KeyException: The parameter is incorrect.
at sun.security.mscapi.CRSACipher.doFinal(CRSACipher.java:311)
at sun.security.mscapi.CRSACipher.engineDoFinal(CRSACipher.java:335)
at javax.crypto.Cipher.doFinal(Cipher.java:2168)
at com.esko.utl.crypto.ppktest.decrypt(ppktest.java:61)
at com.esko.utl.crypto.ppktest.main(ppktest.java:28)
Caused by: java.security.KeyException: The parameter is incorrect.
at sun.security.mscapi.CRSACipher.encryptDecrypt(Native Method)
at sun.security.mscapi.CRSACipher.doFinal(CRSACipher.java:303)
... 4 more
The certificate is generated using keytool. When saving the certificate in a JKS Keystore, in a file on disk, then when loading the certificate from the JKS keystore from disk, decrypting works also on Windows Server 2022.
Question: why can the certificate no be used for decrypting when it is loaded in java from Certificate Manager when running on Windows Server 2022? How could this be solved?
import static java.nio.charset.StandardCharsets.UTF_8;
import java.io.ByteArrayOutputStream;
import java.util.Base64;
import java.security.KeyPair;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.Security;
import java.security.cert.Certificate;
import javax.crypto.Cipher;
import javax.crypto.CipherOutputStream;
public class ppktest
{
public static void main (String[] args2)
{
String inputArg = "ABCDEFGHI";
String alias = "esko-ae";
String pw = "******";
try
{
String encrypted = encrypt (inputArg, alias, pw.toCharArray ());
System.out.println ("Encrypted:" + encrypted);
String decrypted = decrypt (encrypted, alias, pw.toCharArray ());
System.out.println ("Decrypted:" + decrypted);
boolean b = inputArg.equals (decrypted);
System.out.println ("Roundtrip succeeded:" + b);
}
catch (Throwable t)
{
t.printStackTrace ();
}
}
private static String encrypt (String v, String alias, char[] pw) throws Exception
{
Cipher ec = makeCipher (true, alias, pw);
ByteArrayOutputStream bos = new ByteArrayOutputStream (512);
CipherOutputStream cos = new CipherOutputStream (bos, ec);
cos.write (v.getBytes (UTF_8));
cos.close ();
return Base64.getEncoder().encodeToString (bos.toByteArray ());
}
private static String decrypt (String v, String alias, char[] pw) throws Exception
{
byte[] bytes = Base64.getDecoder ().decode (v);
Cipher dc = makeCipher (false, alias, pw);
return new String (dc.doFinal (bytes), UTF_8);
}
private static Cipher makeCipher (boolean encrypt, String alias, char[] pw) throws Exception
{
KeyPair keyPair = getKeyPairFromKeyStore (alias, pw);
Cipher retval = Cipher.getInstance ("RSA/ECB/PKCS1Padding");
if (encrypt)
retval.init (Cipher.ENCRYPT_MODE, keyPair.getPublic ());
else
{
PrivateKey privKey = keyPair.getPrivate ();
retval.init (Cipher.DECRYPT_MODE, privKey);
}
return retval;
}
private static KeyStore loadKeyStore () throws Exception
{
KeyStore keyStore = KeyStore.getInstance ("Windows-MY");
keyStore.load (null, null);
return keyStore;
}
private static KeyPair getKeyPairFromKeyStore (String alias, char[] pw) throws Exception
{
KeyStore keyStore = loadKeyStore ();
Certificate cert = keyStore.getCertificate (alias);
if (cert == null) throw new Exception ("Alias not found in keystore: " + alias);
KeyStore.PasswordProtection keyPassword = new KeyStore.PasswordProtection (pw);
KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry) keyStore.getEntry (alias, keyPassword);
if (privateKeyEntry == null) throw new Exception ("Private key for " + alias + " could not be obtained.");
return new KeyPair (cert.getPublicKey (), privateKeyEntry.getPrivateKey ());
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
