Copy link to clipboard
Copied
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?
Ah, @dwaynea8754223, nice detective work there. Quite Sherlock Holmsey. 🙂
The error message suggests a new idea:
--add-opens=java.base/com.sun.crypto.provider=ALL-UNNAMEDI’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
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
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());
}
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
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
Copy link to clipboard
Copied
That sounds like a better solution, if it works. Let us know, thanks!
Copy link to clipboard
Copied
Sure, I tested it today and worked perfectly
Bests,
Salvatore Cerruto
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
@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
Copy link to clipboard
Copied
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:
remote string function generateKey (required string password, array salt = [])
{
if (arrayLen(salt) == 0) withremote 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)
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);
Copy link to clipboard
Copied
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:
Copy link to clipboard
Copied
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()".
Copy link to clipboard
Copied
Out of curiosity, does the error go away when you apply the suggestions?
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
the 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();
Copy link to clipboard
Copied
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
Copy link to clipboard
Copied
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);
Copy link to clipboard
Copied
Ah, @dwaynea8754223, nice detective work there. Quite Sherlock Holmsey. 🙂
The error message suggests a new idea:
--add-opens=java.base/com.sun.crypto.provider=ALL-UNNAMEDCopy link to clipboard
Copied
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.
Copy link to clipboard
Copied
You can also add
--add-opens=java.base/com.sun.crypto.provider=ALL-UNNAMEDin Coldfusion administrator
Server Settings > Java and JVM > JVM Arguments
Copy link to clipboard
Copied
Life saver. Thank you.
Copy link to clipboard
Copied
I also faced the same issue and this solution saved me a lot of time. Thank you.
Get ready! An upgraded Adobe Community experience is coming in January.
Learn more