Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8286977

decrypting fails using certificate's private key coming from Windows-MY on Win

XMLWordPrintable

      ADDITIONAL SYSTEM INFORMATION :
      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)

      A DESCRIPTION OF THE PROBLEM :
      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

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Generate a certificate with keytool, convert it to .p12 format and import into Window's Certificate Manager.
      Use that certificate to do an encryption roundtrip.
      Encrypting with the public key will work,
      but decrypting using the private key fails on Windows Server 2022 (on earlier win versions, it works)

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      enrypt/decrypt round trip works using a certificate's public/private key as loaded from Windows-MY (on Windows Server 2022)
      ACTUAL -
      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

      ---------- BEGIN SOURCE ----------
      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 ());
          }

        }

      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      do not use Windows-MY, but load the certificate from a Java Keystore: .jks file from disk
      or
      use java 18
      or use a windows version lower than windows Server version 2022

      FREQUENCY : always


            weijun Weijun Wang
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated: