-
Bug
-
Resolution: Unresolved
-
P4
-
None
-
8
-
x86_64
-
windows
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
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
- relates to
-
JDK-8251134 Unwrapping a key with a Private Key generated by Microsoft CNG fails
-
- Closed
-