Algorithm HmacPBESHA256 not available
Asked Answered
K

5

27

So, I have written some code to take a PEM, add it to a PKCS keystore via bouncycastle, and then use java crypto to import the PKCS keystore value into a JKS keystore.

I swear that yesterday I had a unit test pass successfully having executed these steps, but this morning I started hitting this

Caused by: java.security.NoSuchAlgorithmException: Algorithm HmacPBESHA256 not available
    at javax.crypto.Mac.getInstance(Mac.java:181) ~[na:1.8.0_60]
    at sun.security.pkcs12.PKCS12KeyStore.engineLoad(PKCS12KeyStore.java:2039) ~[na:1.8.0_65]

Now, it's always possible something changed underneath me but I cannot figure out what it was. It seems whatever provider I was using for that algorithm has since disappeared.

here's my java.security file snippet:

security.provider.1=sun.security.provider.Sun
security.provider.2=sun.security.rsa.SunRsaSign
security.provider.3=sun.security.ec.SunEC
security.provider.4=com.sun.net.ssl.internal.ssl.Provider
security.provider.5=com.sun.crypto.provider.SunJCE
security.provider.6=sun.security.jgss.SunProvider
security.provider.7=com.sun.security.sasl.Provider
security.provider.8=org.jcp.xml.dsig.internal.dom.XMLDSigRI
security.provider.9=sun.security.smartcardio.SunPCSC
security.provider.10=apple.security.AppleProvider

There's not a whole lot to the code. First I create a PKCS keystore via bouncycastle, adding a pem and saving to disk as PKCS12. Then import via java crypto, saving back out as JKS.

   public KeystoreBuilder createJksFromPem(String pemPrivate, String pemPublic, String alias) throws Exception
    {
        Preconditions.checkState(StringUtils.isNotEmpty(pemPrivate), "pemPrivate must not be empty");
        Preconditions.checkState(StringUtils.isNotEmpty(pemPublic), "pemPublic must not be empty");
        Preconditions.checkState(StringUtils.isNotEmpty(alias), "alias must not be empty");

        String pkcsFilename = filename + ".pkcs";
        convertPemToPkcs(pemPrivate, pemPublic, pkcsFilename);

        importPkcsIntoJks(pkcsFilename);

        return this;
    }

    private void importPkcsIntoJks(String pkcsFilename) throws Exception
    {
        KeyStore pkcs = KeyStore.getInstance("PKCS12");
        File pkcsFile = new File(pkcsFilename);
        try (FileInputStream fis = new FileInputStream(pkcsFile))
        {
            pkcs.load(fis, password.toCharArray());
        }
        pkcsFile.delete();

        KeyStore jks = KeyStore.getInstance("JKS");
        jks.load(null);

        Enumeration<String> aliases = pkcs.aliases();
        while (aliases.hasMoreElements())
        {
            String alias = aliases.nextElement();
            if (!pkcs.isKeyEntry(alias))
            {
                continue;
            }
            Key key = pkcs.getKey(alias, password.toCharArray());
            Certificate[] chain = pkcs.getCertificateChain(alias);

            jks.setKeyEntry(alias, key, password.toCharArray(), chain);
        }

        persist(jks);
    }

    private void convertPemToPkcs(String pemPrivate, String pemPublic, String pkcsFilename) throws IOException, NoSuchAlgorithmException, OperatorCreationException, PKCSException, FileNotFoundException
    {
        Security.addProvider(new BouncyCastleProvider());

        X509CertificateHolder cert = (X509CertificateHolder) readObject(pemPublic);
        PEMKeyPair keyPair = (PEMKeyPair) readObject(pemPrivate);

        JcaX509ExtensionUtils extUtils = new JcaX509ExtensionUtils();
        PKCS12SafeBagBuilder pkcs12BagBuilder = new PKCS12SafeBagBuilder(cert);
        pkcs12BagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName, new DERBMPString("Kafka SSL Certificate"));
        pkcs12BagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_localKeyId, extUtils.createSubjectKeyIdentifier(keyPair.getPublicKeyInfo()));

        PKCS12PfxPduBuilder builder = new PKCS12PfxPduBuilder();

        builder.addData(pkcs12BagBuilder.build());

        builder.addEncryptedData(new JcePKCSPBEOutputEncryptorBuilder(PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC2_CBC).setProvider("BC").build(password.toCharArray()), pkcs12BagBuilder.build());

        PKCS12PfxPdu pfx = builder.build(new JcePKCS12MacCalculatorBuilder(NISTObjectIdentifiers.id_sha256), password.toCharArray());

        try (FileOutputStream fos = new FileOutputStream(new File(pkcsFilename)))
        {
            fos.write(pfx.getEncoded(ASN1Encoding.DL));
        }
    }

and boom it blows up on

pkcs.load(fis, password.toCharArray());

As you can see, the BouncyCastleProvider was added explicitly. Any suggestions?

UPDATE: Thanks dave_thompson_085 for the suggestion. Can't believe I didn't see that overloaded method, but the solution was to specify the provider in the call get Keystore.getInstance("PKCS12", "BC").

Kamkama answered 30/9, 2016 at 18:22 Comment(7)
An internet search shows this bug could be related. Furthermore, I don't see the Bouncy Castle provider anywhere, maybe that will help?Jupon
Editing some code to replay the issue would be helpful.Jupon
Adding the BC provider doesn't give it priority; your stacktrace confirms you are getting the SunJSSE provider's implementation. Try using KeyStore.getInstance("PKCS12","BC") or if you want to live dangerously inserting the BC provider at or below position 4. Or just do the PB-MAC on the PKCS12 with SHA1 like everybody else -- you're already using it for the PBE. Plus it looks to me like you're strongly encryping the cert -- why??Wheezy
aaaaahhhhhhh that fixed it, thanks dave_thompson_085!!Kamkama
@dave_thompson_085, which code specifically are you referring to WRT 'strongly encrypting'? the 'addEncryptedData()' call?Kamkama
Adam: exactly. <! pad>Wheezy
I just took it from here bouncycastle.org/docs/pkixdocs1.5on/org/bouncycastle/pkcs/…Kamkama
K
4

as dave_thompson_085 pointed out, I can specify which provider I want to be used for the keystore. I didn't realize this initially as I missed the getInstance() overload.

So in summary, calling this fixed my issue:

KeyStore.getInstance("PKCS12","BC")

too easy.

Kamkama answered 5/10, 2016 at 12:20 Comment(0)
E
23

Open Android Studio and go to File > Settings > Build, Execution, Development > Build Tools > Gradle, then change Gradle JDK to jdk16, then click Sync Gradle.

And you can go to the build project without any error.

Erelia answered 15/8, 2021 at 13:19 Comment(2)
Using JDK 15 in android studio solves the problem. JDK 16 throws errors for some dependencies.Isosceles
I'm using JDK16 solves the problem. My React app React work now.Rile
M
8

This problem can be caused by older OpenJDK Java versions. (Keytool)
In my case this version solved the problem: openjdk version "11.0.17" 2022-10-18

Macgregor answered 2/2, 2023 at 14:49 Comment(4)
Had same issue with 11.0.17 (from Oct/2022). A corretto 11.0.13_8 solved it for me. ( from Oct/2021)Principal
I had this issue too. For me fixed with jdk 17Marlonmarlow
11.0.20 fixed it for me . 11.0.20 was shown as the version in android studio, so I used thatHamil
Thank you. I migrated to OpenJDK 17 and now it worksEvvie
M
7

The HmacPBESHA256 sounds like the algorithm to verify the integrity after decrypting the file. You can decrypt your Keystore and encrypt again, which may doesn't use the HmacPBESHA256.


In my case, I generate the key using the Windows tool (i.e "Microsoft Strong Cryptographic Provider"). By default, the pfx uses HmacPBESHA256, which Java 11 doesn't support.

The solution is to create a new Keystore, but using openssl. In order to do that, I run:

openssl pkcs12 -in "your_keystore.pfx" -nodes | openssl pkcs12 -export -out "new_keystore.pfx"

That works on jarsign/apksign, by providing the new_keystore.pfx into as the keystore.

Methacrylate answered 22/2, 2021 at 16:15 Comment(1)
Thank you so much for this fix. Note, in my case, it wiped out my alias value (changed it to 1) and had to re-apply the alias using these steps: https://mcmap.net/q/35986/-how-to-change-the-alias-of-a-key-within-a-keystore. Oddly, testing the offending file using keytool -list -v -keystore as a baseline with Java 11.0.4, the HmacPBESHA256 error shows, but when I switched to 11.0.16, the error went away. For compatibility reasons, I still went the extra mile to use the above openssl steps and now the file works with both versions.Independency
K
4

as dave_thompson_085 pointed out, I can specify which provider I want to be used for the keystore. I didn't realize this initially as I missed the getInstance() overload.

So in summary, calling this fixed my issue:

KeyStore.getInstance("PKCS12","BC")

too easy.

Kamkama answered 5/10, 2016 at 12:20 Comment(0)
B
4

Alternatively the HmacPBESHA256 algorithm is supported by standard java (SunJCE Provider) starting from Java 12. I would use it like this:

//run with Java 12!
public void test() throws NoSuchAlgorithmException {
    Provider provider = java.security.Security.getProvider("SunJCE");
    System.out.println(provider.getName());
    Mac m = Mac.getInstance("HmacPBESHA256",provider);
    System.out.println(m.getAlgorithm());
}
Behold answered 7/1, 2020 at 9:6 Comment(3)
I am using java version 16, But still getting errorInterspace
But it is available if you look at the documentation Did you correctly set the Provider?Behold
Yes it is mentioned there. But what is this provider and where to set it?Interspace

© 2022 - 2024 — McMap. All rights reserved.