Search code examples
javaencryptionbouncycastlefips

FipsUnapprovedOperationError while creating CMS message with BouncyCastle


I am trying to create a CMS Enveloped encrypted message using BouncyCastle FIPS 1.0.0 for Java. I receive the following error indicating that it is trying to use AES for random number generation (which is not an approved algorithm for FIPS mode).

Exception in thread "main" org.bouncycastle.crypto.fips.FipsUnapprovedOperationError: Attempt to create key with unapproved RNG: AES
    at org.bouncycastle.crypto.fips.Utils.validateRandom(Unknown Source)
    at org.bouncycastle.crypto.fips.Utils.validateKeyGenRandom(Unknown Source)
    at org.bouncycastle.crypto.fips.FipsAES$KeyGenerator.<init>(Unknown Source)
    at org.bouncycastle.crypto.fips.FipsAES$KeyGenerator.<init>(Unknown Source)
    at org.bouncycastle.jcajce.provider.ProvAES$39$1.createInstance(Unknown Source)
    at org.bouncycastle.jcajce.provider.BaseKeyGenerator.engineInit(Unknown Source)
    at javax.crypto.KeyGenerator.init(KeyGenerator.java:510)
    at org.bouncycastle.cms.jcajce.JceCMSContentEncryptorBuilder$CMSOutputEncryptor.<init>(Unknown Source)
    at org.bouncycastle.cms.jcajce.JceCMSContentEncryptorBuilder.build(Unknown Source)

First, I make sure BouncyCastle is loaded as a JCE provider and then I make sure that it is running in FIPS approved only mode.

if(!CryptoServicesRegistrar.isInApprovedOnlyMode()) {
    CryptoServicesRegistrar.setApprovedOnlyMode(true);
}

After that I am basically just using code like the example in the BC FIPS in 100 mini-book. The code I have so far is as follows:

private static final String FIPS_PROVIDER = "BCFIPS";

public byte[] encrypt(X509Certificate cert, byte[] dataToEncrypt) throws CertificateEncodingException, CMSException, IOException, InvalidAlgorithmParameterException {
    CMSEnvelopedDataGenerator envelopedGen = new CMSEnvelopedDataGenerator();
    JcaAlgorithmParametersConverter paramsConverter = new JcaAlgorithmParametersConverter();

    AlgorithmIdentifier algId = paramsConverter.getAlgorithmIdentifier(PKCSObjectIdentifiers.id_RSAES_OAEP, OAEPParameterSpec.DEFAULT);
    JceKeyTransRecipientInfoGenerator recipientInfo = new JceKeyTransRecipientInfoGenerator(cert, algId);
    recipientInfo.setProvider(FIPS_PROVIDER);
    envelopedGen.addRecipientInfoGenerator(recipientInfo);

    CMSProcessableByteArray processableArray = new CMSProcessableByteArray(dataToEncrypt);
    JceCMSContentEncryptorBuilder encryptorBuilder = new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES256_CBC);
    encryptorBuilder.setProvider(FIPS_PROVIDER);
    OutputEncryptor outputEncryptor = encryptorBuilder.build();

    return envelopedGen.generate(processableArray, outputEncryptor).getEncoded();
}

If I do not put BouncyCastle into the FIPS approved only mode then this code works fine, but I need to be able to run in this mode. Is there some way to tell the CMSOutputEncryptor to use a different RNG algorithm?


Solution

  • Have you tried setting up a FIPS-approved SecureRandom?

    CryptoServicesRegistrar.setSecureRandom(
        new FipsDRBG.Builder(
            new BasicEntropySourceProvider(new SecureRandom(), true))
        .build(FipsDRBG.SHA512_HMAC, null, false)
    );
    

    then on your builder (and wherever else you may need it):

    encryptorBuilder.setSecureRandom(CryptoServicesRegistrar.getSecureRandom());