Wildfly 35.0.1 Final + elytron 2.6.0 Final : BouncyCastleFips Credential Store, storing passwords in external file error

52 views
Skip to first unread message

Creepy Weasel

unread,
Jun 26, 2026, 3:39:48 PM (5 days ago) Jun 26
to WildFly
Hello, 

I am having a weird issue with adding passwords to my credential's store external file. I am updating to use BouncyCastle Fips for my elytron credential store. I am doing this offline and not using the JBOSS CLI. 

I originally stumbled across this issue on my rocky 8 linux environment in a shell script that when ran will delete all existing keystores and external files. I used the elytron-tool.sh to create the keystore with a 256-bit AES key and created the credential store successfully. 
I then add like 10 passwords to it with --secret lengths of about 22 characters long. 
As it reaches like the 9th password I get an error like this :

Caused by: java.io.IOException: ELY09524: The actual number of bytes read 40 is different from the expected number of bytes 80 to be read

at org.wildfly.security.credential.store.impl.KeyStoreCredentialStore$ExternalStorage.readBytes(KeyStoreCredentialStore.java:1297)

at org.wildfly.security.credential.store.impl.KeyStoreCredentialStore$ExternalStorage.loadSecretKey(KeyStoreCredentialStore.java:1280)

at org.wildfly.security.credential.store.impl.KeyStoreCredentialStore$ExternalStorage.load(KeyStoreCredentialStore.java:1268)

at org.wildfly.security.credential.store.impl.KeyStoreCredentialStore.load(KeyStoreCredentialStore.java:893)


I'm pretty new this kind of stuff, but I assume there is a read/write error going on with the external file. 

I managed to replicate this issue in a Windows environment using a programmatic approach. It is a standalone version but still uses the BouncyCastleFips API and follows the same procedure. 

Has anyone run into this issue? Am I missing something?
I believe we are supposed to write the credentials to the external file and the AES key to do the encryption/decryption belongs in the keystore, so we have two files in total. 

I have the following java code: 

import java.io.File;

import java.io.FileOutputStream;

import java.io.OutputStream;

import java.security.KeyStore;

import java.security.Provider;

import java.security.Security;

import java.util.HashMap;

import java.util.Map;

import java.util.Set;


import javax.crypto.KeyGenerator;

import javax.crypto.SecretKey;


import org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider;

import org.wildfly.security.auth.server.IdentityCredentials;

import org.wildfly.security.credential.PasswordCredential;

import org.wildfly.security.credential.store.CredentialStore;

import org.wildfly.security.credential.store.WildFlyElytronCredentialStoreProvider;

import org.wildfly.security.credential.store.impl.KeyStoreCredentialStore;

import org.wildfly.security.password.WildFlyElytronPasswordProvider;

import org.wildfly.security.password.interfaces.ClearPassword;


public class CredStoreTest {

static final String PASS = "theMasterPassword";

static final String CRED_PASS ="someReallyLongPasswordBelongsInHereToBreak";

static final String ALIAS = "credential-store-key";

static final String DIR = System.getProperty("java.io.tmpdir");

static final String LOC = new File(DIR, "MyCredStore.bcfks").getAbsolutePath();

static final String EXT = new File(DIR, "MyCredStore-ext.cs").getAbsolutePath();

static Provider BC;

static {

BC = new BouncyCastleFipsProvider();

Security.addProvider(BC);

Security.addProvider(WildFlyElytronPasswordProvider.getInstance());

}


public static void main(String[] args) {

String ver = KeyStoreCredentialStore.class.getPackage().getImplementationVersion();

System.out.println("elytron-base version: " + ver);

System.out.println("files: " + LOC + " | " + EXT);

System.out.println("Password length: " + CRED_PASS.length());

// Increments and tests with a set number of aliases

for (int count = 1; count <= 40; count ++) {

boolean ok = runScenario(count, CRED_PASS);

System.out.printf("count=%2d -> %s%n", count, ok ? "OK" : "FAIL");

if (!ok) {

System.out.println(" Failure at count = " + count + " (total character length -" + (count * PASS.length()) + " secret-chars) ");

break;

}

}

System.out.println("Done!");

}

static boolean runScenario(int count, String secret) {

try {

new File(LOC).delete();

new File(EXT).delete();

createKeyStore(); // This is our BCFKS holding the AES key

CredentialStore write = open(true); // Our external file that holds our passwords

// write the passwords to the external file

for (int i = 0; i < count; i++) {

ClearPassword cp = ClearPassword.createRaw(ClearPassword.ALGORITHM_CLEAR, secret.toCharArray());

write.store("alias" + i, new PasswordCredential(cp));

}

write.flush();

// Reads the passwords in our external file

CredentialStore read = open(false);

Set<String> aliases = read.getAliases();

return aliases.size() == count;

} catch (Throwable t) {

t.printStackTrace(System.out);

return false;

}

}

/**

* Used to first create our credential store and to read existing passwords

* @param create

* @return

* @throws Exception

*/

static CredentialStore open(boolean create) throws Exception {

// Use the Bouncy Castle Fips provider and store credentials in the external path (ISSACredStore.cs)

Map<String, String> attributes = new HashMap<>();

attributes.put("keyStoreType", "BCFKS");

attributes.put("keyAlias", ALIAS);

attributes.put("external", "true");

attributes.put("externalPath", EXT);

attributes.put("location", LOC);

attributes.put("modifiable", "true");

attributes.put("create", String.valueOf(create));

CredentialStore cs = CredentialStore.getInstance("KeyStoreCredentialStore", WildFlyElytronCredentialStoreProvider.getInstance());

cs.initialize(attributes, protection(PASS), new Provider[] {BC, WildFlyElytronPasswordProvider.getInstance()});

return cs;

}

/**

* Creates a keystore with an AES key with the BouncyCastleFips provider

* @throws Exception

*/

static void createKeyStore() throws Exception {

KeyStore ks = KeyStore.getInstance("BCFKS", BC);

ks.load(null, null);

KeyGenerator kg = KeyGenerator.getInstance("AES", BC);

kg.init(256);

SecretKey aes = kg.generateKey();

ks.setKeyEntry(ALIAS, aes, PASS.toCharArray(), null);

try (OutputStream out = new FileOutputStream(LOC)) {

ks.store(out, PASS.toCharArray());

}

}

/**

* This is used to unlock the credential store with the master password

*/

static CredentialStore.ProtectionParameter protection(String pw) {

ClearPassword cp = ClearPassword.createRaw(ClearPassword.ALGORITHM_CLEAR, pw.toCharArray());

return new CredentialStore.CredentialSourceProtectionParameter(IdentityCredentials.NONE.withCredential(new PasswordCredential(cp)));

}

}


This is being done in a maven eclipse project: 
The pom.xml: 

<project xmlns="http://maven.apache.org/POM/4.0.0"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">

<modelVersion>4.0.0</modelVersion>

<groupId>com.test</groupId>

<artifactId>credstore-repro</artifactId>

<version>0.0.1-SNAPSHOT</version>

<properties>

<maven.compiler.release>21</maven.compiler.release>

<elytron.version>2.6.0.Final</elytron.version>

</properties>

<dependencies>

<dependency>

<groupId>org.wildfly.security</groupId>

<artifactId>wildfly-elytron-credential-store</artifactId>

<version>${elytron.version}</version>

</dependency>

<dependency>

<groupId>org.bouncycastle</groupId>

<artifactId>bc-fips</artifactId>

<version>2.1.0</version>

</dependency>

<dependency>

<groupId>org.wildfly.security</groupId>

<artifactId>wildfly-elytron</artifactId>

<version>${elytron.version}</version>

</dependency>

</dependencies>

</project>

Thanks 
Reply all
Reply to author
Forward
0 new messages