Skip to content

Support for PBMAC1 algorithms#1485

Open
dev-koan wants to merge 3 commits into
IBM:mainfrom
dev-koan:feature/PBMAC1
Open

Support for PBMAC1 algorithms#1485
dev-koan wants to merge 3 commits into
IBM:mainfrom
dev-koan:feature/PBMAC1

Conversation

@dev-koan

Copy link
Copy Markdown
Collaborator

This update adds support for PBMAC1 algorithms. The algorithms are supported for OpenJCEPlus and OpenJCEPlusFIPS provider. The PBMAC1Core class extends the regular HmacCore class overriding engineInit method as PBMAC1 uses PBKDF2 key derivation.
PBMAC1 tests have also been added.

Signed-off-by: Dev Agarwal dev.agarwal@ibm.com

@JinhangZhang

Copy link
Copy Markdown
Collaborator

Did you by any chance make a build and put openjceplus on the top of the order and create a PKCS12 keystore file with keytool command? e.g. by specifying -J-Dkeystore.pkcs12.macAlgorithm=PBEWithHmacSHA256

@johnpeck-us-ibm

Copy link
Copy Markdown
Member

Since, the need here is for use in keystore. I would like to see some keystore tests that test this functionality. First to make sure this work, but also to make sure the keystores created using our impliementation work when Sun's implementation is used.

Comment thread src/test/java/ibm/jceplus/junit/base/params/file1.txt Outdated
Comment thread src/test/java/ibm/jceplus/junit/base/BaseTestPBMAC1.java Outdated
Comment thread README.md Outdated
Comment thread src/main/java/com/ibm/crypto/plus/provider/PBMAC1Core.java
dev-koan added 2 commits June 5, 2026 15:49
This update adds support for PBMAC1 algorithms.
The algorithms are supported for OpenJCEPlus and
OpenJCEPlusFIPS provider. The PBMAC1Core class extends
the regular HmacCore class overriding engineInit method
as PBMAC1 uses PBKDF2 key derivation.
PBMAC1 tests have also been added.

Signed-off-by: Dev Agarwal <dev.agarwal@ibm.com>
…them as strings within the test, updated readme, some formatting updated to PBMAC1Core class
@dev-koan

dev-koan commented Jun 5, 2026

Copy link
Copy Markdown
Collaborator Author

Since, the need here is for use in keystore. I would like to see some keystore tests that test this functionality. First to make sure this work, but also to make sure the keystores created using our impliementation work when Sun's implementation is used.

I am reading P12 files using PKCS12 KeyStore after adding OpenJCEPlus to the top the security provider list.
If we have the required crypto the openjdk keystore class will use ours.

@johnpeck-us-ibm

Copy link
Copy Markdown
Member

Since, the need here is for use in keystore. I would like to see some keystore tests that test this functionality. First to make sure this work, but also to make sure the keystores created using our impliementation work when Sun's implementation is used.

I am reading P12 files using PKCS12 KeyStore after adding OpenJCEPlus to the top the security provider list. If we have the required crypto the openjdk keystore class will use ours.

It might be fine than. However, sometimes keytool does things a little differently than our code and that causes issues. So, at the bare minimum I think it is best to verify the code using keytool. Even if the test is a one off and not added to our tests.

@dev-koan dev-koan requested a review from jasonkatonica June 8, 2026 13:33
void testPBMACFunctionality(String alg) throws Exception {
if (getProviderName().equalsIgnoreCase("OpenJCEPlusFIPS") && (alg.equalsIgnoreCase("PBEWithHmacSHA1") ||
alg.equalsIgnoreCase("PBEWithHmacSHA224") || alg.equalsIgnoreCase("PBEWithHmacSHA256"))) {
return;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of returning and assuming that the test was run we instead have been using assume statements. Something like the following would assume we are not using OpenJCEPlusFIPS for example and record it as skipped in Junit. Similar comment to other places where you check for fips provider and excute return.

assumeFalse("OpenJCEPlusFIPS".equals(getProviderName()) && ... .... ...    );

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated.

mac.init(key, new PBEParameterSpec(smallSalt, iterationCount));
fail("Expected InvalidKeyException not thrown, small salt length");
} catch (InvalidKeyException e) {
assertTrue(true);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No reason to assert true. You could however assert that the exception message is as expected in all these locations where we are doing an assertTrue(true);

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated.

Comment thread src/main/java/com/ibm/crypto/plus/provider/PBMAC1Core.java
private byte[] salt = new byte[20];
private int iterationCount = 300000;

private String p12file1 = "MIIKigIBAzCCCgUGCSqGSIb3DQEHAaCCCfYEggnyMIIJ7jCCBGIGCSqGSIb3DQEH" +

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please add some comments here as to where these pkcs12 file values were found. I believe that these were found in an RFC as a known answer test? Besides a comment saying where we obtained these values ideally we would add a comment showing the human readable asn1 breakdown of the value so we can easily know what is within these pcks12 files in terms of crypto.

Also my understanding is that these are not really PKCS12 standard files. They are RFC 9579 (and its successor, RFC 9879) format files correct?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The decoded value is extremely long and on directly copying pasting as text there is no indentation making it hard to read.
can still add it if preferred.

try {
ks.load(new ByteArrayInputStream(decodedBytes), "1234".toCharArray());
} catch (Exception e) {
fail(e.getMessage());

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to strip out all the stack trace information or even to catch the exception. The try catch can be removed and just allow the exception to be thrown in the case of a failure. Similar comment for the rest of the checks being done here.

Maybe the test should also be parameterized such that there is not so much duplicate cod here taking in a pkcs12 file instead?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated.
Now using a helper method and letting the exception get thrown.

try {
ks.load(new ByteArrayInputStream(decodedBytes), "1234".toCharArray());
} catch (java.io.IOException e) {
// Expected error (Incorrect iteration count)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we assert the error message? Seems checking we are are getting a reasonable error message would be better then accepting any IOException that occurs. Similar comment on line 561 and 569.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: OpenJCEPlusFIPS is running in developer mode. Non production workload assumed. This environment is not certified for FIPS 140-3: Mac OS X:aarch64
WARNING: OpenJCEPlusFIPS is running in developer mode. Non production workload assumed. This environment is not certified for FIPS 140-3: Mac OS X:aarch64
Integrity check failed: java.security.UnrecoverableKeyException: Failed PKCS12 integrity checking

This is the exception message not sure if asserting the message provides much value.

@dev-koan

Copy link
Copy Markdown
Collaborator Author

Since, the need here is for use in keystore. I would like to see some keystore tests that test this functionality. First to make sure this work, but also to make sure the keystores created using our impliementation work when Sun's implementation is used.

I am reading P12 files using PKCS12 KeyStore after adding OpenJCEPlus to the top the security provider list. If we have the required crypto the openjdk keystore class will use ours.

It might be fine than. However, sometimes keytool does things a little differently than our code and that causes issues. So, at the bare minimum I think it is best to verify the code using keytool. Even if the test is a one off and not added to our tests.

I took the following steps to test PBMAC1 with keytool (with Bob's help)

  1. A personal build with OpenJCEPlus first and bundled with PBMAC1 algos
  2. Used the generated jdk to generate my p12 file using keytool with the command jdk/bin/keytool -J-Dkeystore.pkcs12.macAlgorithm=PBEWithHmacSHA256 -genkeypair -alias mykey -keyalg RSA -keysize 2048 -storetype PKCS12 -keystore mykeystore.p12 -validity 365
  3. Exported it to base64 to verify the crypto (Screenshot of the decoding is attached below)
  4. Ran the following program to validate everything was working as expected.
public class run {
    public void main() throws Exception {
        // Security.insertProviderAt(new OpenJCEPlusFIPS(), 1);
        System.out.println(Security.getProviders()[0]);
        Mac t = Mac.getInstance("PBEWithHmacSHA384");
        System.out.println(t.getProvider().getName());

        KeyStore ks = KeyStore.getInstance("PKCS12");
        ks.load(new FileInputStream("mykeystore.p12"), "ibmcanada".toCharArray());

        String alias = "mykey";
        PrivateKey privateKey = (PrivateKey) ks.getKey(alias, "ibmcanada".toCharArray());
        Certificate cert = ks.getCertificate(alias);
        PublicKey publicKey = cert.getPublicKey();
        
        // 3. Sign some data
        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initSign(privateKey);
        String data = "Test data to sign";
        signature.update(data.getBytes());
        byte[] signedData = signature.sign();
        
        // 4. Verify the signature
        signature.initVerify(publicKey);
        signature.update(data.getBytes());
        boolean verified = signature.verify(signedData);
        
        System.out.println("P12 file is valid: " + verified);
    }
}
image

@dev-koan dev-koan requested a review from jasonkatonica June 11, 2026 19:02
@johnpeck-us-ibm

Copy link
Copy Markdown
Member

Since, the need here is for use in keystore. I would like to see some keystore tests that test this functionality. First to make sure this work, but also to make sure the keystores created using our impliementation work when Sun's implementation is used.

I am reading P12 files using PKCS12 KeyStore after adding OpenJCEPlus to the top the security provider list. If we have the required crypto the openjdk keystore class will use ours.

It might be fine than. However, sometimes keytool does things a little differently than our code and that causes issues. So, at the bare minimum I think it is best to verify the code using keytool. Even if the test is a one off and not added to our tests.

I took the following steps to test PBMAC1 with keytool (with Bob's help)

1. A personal build with `OpenJCEPlus` first and bundled with PBMAC1 algos

2. Used the generated jdk to generate my p12 file using keytool with the command `jdk/bin/keytool -J-Dkeystore.pkcs12.macAlgorithm=PBEWithHmacSHA256 -genkeypair -alias mykey -keyalg RSA -keysize 2048 -storetype PKCS12 -keystore mykeystore.p12 -validity 365`

3. Exported it to base64 to verify the crypto (Screenshot of the decoding is attached below)

4. Ran the following program to validate everything was working as expected.
public class run {
    public void main() throws Exception {
        // Security.insertProviderAt(new OpenJCEPlusFIPS(), 1);
        System.out.println(Security.getProviders()[0]);
        Mac t = Mac.getInstance("PBEWithHmacSHA384");
        System.out.println(t.getProvider().getName());

        KeyStore ks = KeyStore.getInstance("PKCS12");
        ks.load(new FileInputStream("mykeystore.p12"), "ibmcanada".toCharArray());

        String alias = "mykey";
        PrivateKey privateKey = (PrivateKey) ks.getKey(alias, "ibmcanada".toCharArray());
        Certificate cert = ks.getCertificate(alias);
        PublicKey publicKey = cert.getPublicKey();
        
        // 3. Sign some data
        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initSign(privateKey);
        String data = "Test data to sign";
        signature.update(data.getBytes());
        byte[] signedData = signature.sign();
        
        // 4. Verify the signature
        signature.initVerify(publicKey);
        signature.update(data.getBytes());
        boolean verified = signature.verify(signedData);
        
        System.out.println("P12 file is valid: " + verified);
    }
}
image

Did you verify that keytool used OpenJCEPlus when it created the file?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants