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)
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)));
}
}
<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>