'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