Exit
  • Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
  • 한국 커뮤니티
1

Coldfusion 2023 seems to be missing some JAVA

Explorer ,
Sep 13, 2023 Sep 13, 2023

var keySpec = createObject("java", "javax.crypto.spec.PBEKeySpec").init(arguments.password.toCharArray(), salt, 128, 80);

 

results in error:

java.lang.reflect.InaccessibleObjectException: Unable to make public boolean com.sun.crypto.provider.PBKDF2KeyImpl.equals(java.lang.Object) accessible: module java.base does not "opens com.sun.crypto.provider" to unnamed module @db99785

 

this code works on previous versions of CF/Java. Is there something I should add to the JVM arguments?

TOPICS
Advanced techniques
4.7K
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines

correct answers 2 Correct answers

Community Expert , Sep 18, 2023 Sep 18, 2023

Ah, @dwaynea8754223, nice detective work there. Quite Sherlock Holmsey. 🙂

 

The error message suggests a new idea:

  1.  Open the file /cfusion/bin/jvm.config is a text editor;
  2.  You will see that the property java.args contains a number of attributes of the form --add-opens=java.base/some.package.name=ALL-UNNAMED .
    Add the following attibute to the list:
    --add-opens=java.base/com.sun.crypto.provider=ALL-UNNAMED​
  3.  Save jvm.config and restart ColdFusion.
Translate
Explorer , Apr 02, 2025 Apr 02, 2025

I’m aware of this function, which is in this repository (https://github.com/marcins/cf-google-authenticator/blob/master/authenticator/GoogleAuthenticator.cfc), and as far as I’m concerned, I don’t feel comfortable having to add exceptions to the server that might increase the attack surface by using the configuration

--add-opens=java.base/some.package.name=ALL-UNNAMED


Instead, I changed the function by using ColdFusion’s native functions that do the same thing. Specifically, the GeneratePBKDFKey f

...
Translate
Community Expert ,
Sep 13, 2023 Sep 13, 2023

Before presuming that's the issue (or asking for your values passed into the two args, so we can try to recreate it), can you first just edit the file in any way to force its recompilation?

 

Second, in what version did it work? If that is still around, perhaps someone dropped in a class or jar that was being leveraged, such that putting it into cf2023's same folder could fix things. 


/Charlie (troubleshooter, carehart. org)
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Sep 13, 2023 Sep 13, 2023

thanks for the quick response.

this is a function in a cfc. not sure I understand the path to force recompilation. I don't believe there are any custom classes or jar file. This was working on CF2016. I believe all Java is native. That said, I read a little about modules, or lack there of, and through maybe the JVM arguments may be required to load the crypto class.

 

 

    /**
    * Generates a Base32 encoded secret key for use with the token functions
    *
    * @Param password a password to be used as the seed for the secret key
    * @Param salt a Java byte[16] array containing a salt - if left blank a random salt will be generated (recommended)
    * @Return the Base32 encoded secret key
    */
    remote string function generateKey (required string password, array salt = [])
    {
        if (arrayLen(salt) == 0)
        {
            var secureRandom = createObject("java", "java.security.SecureRandom").init();
            var buffer = createObject("java", "java.nio.ByteBuffer").allocate(16);
            arguments.salt = buffer.array();
            secureRandom.nextBytes(arguments.salt);
        }
        else if(arrayLen(salt) != 16)
        {
            throw(message="Salt must be byte[16]", errorcode="Authenticator.BadSalt");
        }

        var keyFactory = createObject("java", "javax.crypto.SecretKeyFactory").getInstance("PBKDF2WithHmacSHA1");
        var keySpec = createObject("java", "javax.crypto.spec.PBEKeySpec").init(arguments.password.toCharArray(), salt, 128, 80);
        var secretKey = keyFactory.generateSecret(keySpec);
        return Base32encode(secretKey.getEncoded());
    }

 

 

 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Sep 13, 2023 Sep 13, 2023

My suggestion was really as simple as I said: just edit the cfc. Make any change at all. Then call it as before. Doing that should cause cf to recompile it (all cfml is compiled to Java).

 

I'm proposing this because sometimes a file that was "working" before can change to "not working" because of some change that affects low-level Java features. It could be a cf update, a JVM update, or a change in cf config files. Forcing a recompilation can cause cf to create Java code that now "works" works after what was that change. 

 

It's just a guess, and the point is that it's easiest to try. You may want to add some change that you can confirm "seeing", as various factors could prevent that immediate recompilation. 


/Charlie (troubleshooter, carehart. org)
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Sep 14, 2023 Sep 14, 2023

Ahh, I made about ah hundred changes to this file while troubleshooting this issue. I think it comes down to javax.crypto.spec.PBEKeySpec not being accessible. 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Apr 02, 2025 Apr 02, 2025

I’m aware of this function, which is in this repository (https://github.com/marcins/cf-google-authenticator/blob/master/authenticator/GoogleAuthenticator.cfc), and as far as I’m concerned, I don’t feel comfortable having to add exceptions to the server that might increase the attack surface by using the configuration

--add-opens=java.base/some.package.name=ALL-UNNAMED


Instead, I changed the function by using ColdFusion’s native functions that do the same thing. Specifically, the GeneratePBKDFKey function is what we need (https://helpx.adobe.com/coldfusion/cfml-reference/coldfusion-functions/functions-e-g/generatepbkdfke...).

Here’s the code with the changes:

public string function generateKey(required string password, string salt = "", numeric iterationCount = 128, numeric keySizeBits = 80) 
{
    // Se salt non fornito, generiamo 16 byte casuali
    if (Len(arguments.salt) == 0) {
        arguments.salt = generateRandomString();
    }
    else if (Len(salt) != 16) {
        throw(message="Salt must be 16 bytes", errorCode="GoogleAuthenticator.BadSalt");
    }

    var derivedKey = GeneratePBKDFKey("PBKDF2WithHmacSHA1" , arguments.password, arguments.salt, arguments.iterationCount, arguments.keySizeBits);

    return Base32encode(binaryDecode(derivedKey, "base64"));
}


Hope this helps.

Best regards,
Salvatore

Salvatore Cerruto
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Apr 02, 2025 Apr 02, 2025

That sounds like a better solution, if it works. Let us know, thanks!

 

Dave Watts, Eidolon LLC
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Apr 02, 2025 Apr 02, 2025

Sure, I tested it today and worked perfectly 

 

Bests,

Salvatore Cerruto

Salvatore Cerruto
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Apr 02, 2025 Apr 02, 2025

Thanks, @xfreeman89x !

 

Hey, @dwaynea8754223 , I also marked Salvatore's answer as correct. It seemed to work! If you have no objection, you might try this approach instead of creating a jvm.config entry.

 

Dave Watts, Eidolon LLC
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Apr 02, 2025 Apr 02, 2025

I don't have any issue with this...appears like a better solution. My only issue is that the java module was loaded on previous versions of CF. I upgraded to 2023 and my app stopped working. At the very least, the JVM config changes should be documented, and sometimes it's difficult to know exactly what these modules do, so the docs should elaborate sufficiently.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Apr 02, 2025 Apr 02, 2025
LATEST

@dwaynea8754223 Using --add-opens explicitly forces the JVM to open private packages, bypassing the newer security measures. This expands the attack surface (if untrusted code ever runs on your JVM) and breaks encapsulation, meaning future changes to those internal classes could lead to additional problems.

In short, --add-opens is not “dangerous” in the immediate sense, but it’s a temporary patch that circumvents Java’s newer security mechanisms. ColdFusion 2023 runs on a more recent Java, which explains the unexpected error. I agree there should have been clearer documentation on this, but changes in the broader Java ecosystem aren’t always highlighted in CF release notes.

I hope this clarifies why it happens. You can certainly keep using --add-opens, but it’s a workaround that slightly undermines Java’s isolation. If you want to avoid it, consider ColdFusion’s built-in GeneratePBKDFKey (I discovered was included already in ColdFusion 11) function or a third-party provider like BouncyCastle, though that can sometimes involve classpath conflicts in CF.
Hope this can clarify your concerns, often some undocumented changes comes from the underlying Java updates and are really difficult to discover when you are using Java classes in your ColdFusion code with createObject function.

Salvatore

Salvatore Cerruto
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Sep 14, 2023 Sep 14, 2023

ColdFusion 2023 is not missing the Java class, javax.crypto.spec.PBEKeySpec. It is right there. You can confirm this by running the test code:

 

<cfscript>
    testObject= createObject("java","javax.crypto.spec.PBEKeySpec");
    writedump(testObject);
</cfscript>

 

Though ColdFusion is weakly-typed, newer versions get progressively more accurate with regard to type. So CF2023 might not tolerate code which CF2016 accepted. My guess is that that is the issue you now face.

 

Here and there, your code uses Java types as if they are native CFML types. For example, the constructor, createObject("java", "javax.crypto.spec.PBEKeySpec").init(arguments.password.toCharArray(), salt, 128, 80); requires that the argument salt be a Java byte-array. However, your code is passing it as a ColdFusion array. In fact, the code is mixing up byte-array and CFML-array as if they are interchangeable. Thus, salt is initialized as a ColdFusion array, []. Yet the same variable is used to store buffer.array(), which is a Java byte-array. That might be the cause of the issue.

 

Now, on to a possible solution. I shall assume that the argument salt is coming into the function as a ColdFusion array, not as a Java byte array.

 

Then:

  1. Replace 
    remote string function generateKey (required string password, array salt = [])
    {
        if (arrayLen(salt) == 0)​
     with
    remote string function generateKey (required string password, array salt = [])
    {
        // Convert from CFML array to Java byte-array 
        var saltByteArray=javacast("byte[]",arguments.salt);
        if (arrayLen(arguments.salt) == 0)​
  2.  Replace

 

arguments.salt = buffer.array();
secureRandom.nextBytes(arguments.salt);

 

with

 

saltByteArray=buffer.array();
secureRandom.nextBytes(saltByteArray);

 

3. Replace

 

var keySpec = createObject("java", "javax.crypto.spec.PBEKeySpec").init(arguments.password.toCharArray(), salt, 128, 80);

 

with

 

var keySpec = createObject("java", "javax.crypto.spec.PBEKeySpec").init(arguments.password.toCharArray(), saltByteArray, 128, 80);

 

 



Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Sep 14, 2023 Sep 14, 2023

A demo to illustrate:

<cfscript>
cfArray=[];
byteArray=javacast("byte[]",cfArray);

writeOutput("Type of CF array [] is: <strong>#cfArray.getClass().getName()#</strong>");
writeOutput("<p>");
writeOutput("Type of Java Byte array obtained from [] using Javacast is: <strong>#byteArray.getClass().getSimpleName()#</strong>");
</cfscript>

 

Output of the demo:

BKBK_0-1694714173098.png

 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Sep 18, 2023 Sep 18, 2023

Hi - I appreciate your suggestions. In all cases, I'm not passing a salt value. So, the code that creates the salt declares a java byte buffer, fills it and sets the value by using the buffer to array function ".array()".

 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Sep 18, 2023 Sep 18, 2023

Out of curiosity, does the error go away when you apply the suggestions?

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Sep 18, 2023 Sep 18, 2023
var secureRandom = createObject("java", "java.security.SecureRandom").init();
var buffer = createObject("java", "java.nio.ByteBuffer").allocate(16);
arguments.salt = buffer.array();
secureRandom.nextBytes(arguments.salt);

the code already produces a java byte array, so I don't see where I could apply your suggestions.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Sep 18, 2023 Sep 18, 2023
quotethe code already produces a java byte array, so I don't see where I could apply your suggestions.

By @dwaynea8754223

 

Above, I have suggested three places where you can change the code. Again, arguments.salt is a coldFusion.runtime.Array, whereas buffer.array() is a Java byte[]. But your code contains statements such as 

arguments.salt = buffer.array();
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Sep 18, 2023 Sep 18, 2023

I removed the potential for a mismated type and the error persists.

    remote string function generateKey (required string password)
    {
        var secureRandom = createObject("java", "java.security.SecureRandom").init();
        var buffer = createObject("java", "java.nio.ByteBuffer").allocate(16);
        var salt = buffer.array();
        secureRandom.nextBytes(salt);

        var keyFactory = createObject("java", "javax.crypto.SecretKeyFactory").getInstance("PBKDF2WithHmacSHA1");
        var keySpec = createObject("java", "javax.crypto.spec.PBEKeySpec").init(arguments.password.toCharArray(), salt, 128, 80);
        var secretKey = keyFactory.generateSecret(keySpec);
	writeOutput( secretKey.toString());
    }

 java.lang.reflect.InaccessibleObjectException: Unable to make public boolean com.sun.crypto.provider.PBKDF2KeyImpl.equals(java.lang.Object) accessible: module java.base does not "opens com.sun.crypto.provider" to unnamed module @db99785

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Sep 18, 2023 Sep 18, 2023

i also tried to simplify this code

var salt = generateSecretKey(("AES"),128);
var keyFactory = createObject("java", "javax.crypto.SecretKeyFactory").getInstance("PBKDF2WithHmacSHA1");
var keySpec = createObject("java", "javax.crypto.spec.PBEKeySpec").init(arguments.password.toCharArray(), salt.getBytes(), 128, 80);
var secretKey = keyFactory.generateSecret(keySpec);
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Sep 18, 2023 Sep 18, 2023

Ah, @dwaynea8754223, nice detective work there. Quite Sherlock Holmsey. 🙂

 

The error message suggests a new idea:

  1.  Open the file /cfusion/bin/jvm.config is a text editor;
  2.  You will see that the property java.args contains a number of attributes of the form --add-opens=java.base/some.package.name=ALL-UNNAMED .
    Add the following attibute to the list:
    --add-opens=java.base/com.sun.crypto.provider=ALL-UNNAMED​
  3.  Save jvm.config and restart ColdFusion.
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Sep 18, 2023 Sep 18, 2023

lol...that's what I was thinking from the beginning!!! Thanks for all your help. That did it! My origional code is working without modification.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
Oct 03, 2023 Oct 03, 2023

You can also add 

--add-opens=java.base/com.sun.crypto.provider=ALL-UNNAMED​

in Coldfusion administrator
Server Settings > Java and JVM > JVM Arguments

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
Oct 15, 2023 Oct 15, 2023

Life saver. Thank you.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
Jun 12, 2024 Jun 12, 2024

I also faced the same issue and this solution saved me a lot of time. Thank you.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Resources