---
schema_version: "1"
id: ebcb21b11b80ecf9d8600ddf23663c15c0fd1b71354292312ba67e93b7b178e1
title: Upgrading and Migrating Cryptography Module 2.x
collection: mulesoft
version: current
locale: en-us
portal_url: https://docs.salesforce.com/mulesoft/current/en-us/cryptography-module/2.1/cryptography-module-upgrade.md
canonical_url: https://docs.mulesoft.com/cryptography-module/2.1/cryptography-module-upgrade
source_site: docs.mulesoft.com
content_type: documentation
content_hash: 7579adf94ba093af91ce4d6ecb4ad329e34a22036e868509eaefc7a9b8c633f9
description: MuleSoft Documentation Site
release: "2.1"
latest: false
---
---
product: Cryptography Module
version: 2.1
---

# Upgrading and Migrating Cryptography Module 2.x

> For the full documentation index, see: https://docs.mulesoft.com/llms.txt

Upgrade Cryptography Module to version 2.x.x.

## Supported Upgrade Paths

<table><colgroup><col> <col></colgroup><thead><tr><th>From Version</th><th>To Version</th></tr></thead><tbody><tr><td><div><div><p>1.3.x</p></div></div></td><td><div><div><p>2.x</p></div></div></td></tr></tbody></table>

## Changes in This Release

> [!IMPORTANT] FIPS Compatibility Notice for PGP Operations  
> PGP Encrypt is unsupported in FIPS environments because the OpenPGP standard (RFC 4880) mandates a
> session key encryption mechanism that is strictly prohibited in FIPS-approved runtimes like
> MuleSoft Government Cloud.
>
> The keyring migration steps in this guide are for operations such as PGP Sign/Validate and PGP
> Decrypt for legacy data only, which does not enable PGP encryption functionality under FIPS.
>
> No FIPS-compliant configuration for PGP encryption exists for projects requiring the encryption of
> new payloads while maintaining strict compliance.

This release contains these changes:

- Changes to default values for connector operations

- Migrating your PGP keyrings to AES-encrypted secret keys for FIPS-compatible PGP operations (for
  example, Sign/Validate and legacy Decrypt scenarios)

- Using different key pairs for PGP Sign and PGP Decrypt operations to enhance security and avoid
  key-usage restrictions in FIPS providers

- Using password-based encryption

- Using BCFKS as the required keystore and truststore type

- Specifying algorithms dynamically

- Registering the XMLDSig Security Provider

- Enabling compatibility for Decrypt or Validate operations without KDF parameters

> [!NOTE] Every reference to Federal Information Processing Standards (FIPS) in this guide pertains
> to FIPS version 140-2 or 140-3.

The minimum supported Mule runtime engine version is 4.4.x to use Cryptography Module 2.x. Make sure
compatibility with FIPS compliance and supported runtime environments. Upgrade your Mule runtime if
you use an older version.

## Scope and Limitations (FIPS)

**PGP Encrypt** is not supported in FIPS environments because the OpenPGP standard (RFC 4880)
mandates the use of RSAES-PKCS1-v1\_5, which is strictly prohibited in FIPS mode. This
protocol-level limitation applies regardless of how you generate your keyring (GPG 2.0, GPG 2.1+, or
BC-FIPS).

Consequently:

- You can’t encrypt new payloads using the PGP Encrypt operation while maintaining strict FIPS
  compliance.

- You can still use PGP Sign/Validate and PGP Decrypt for legacy data, provided the underlying
  algorithms are FIPS-compliant and secret keys are AES-protected.

The [Troubleshoot Key Protection Issues](#troubleshoot-key-protection-issues) section does not apply
to enabling **PGP Encrypt** in FIPS environments. It only helps you diagnose key protection settings
for operations that remain supported (for example, signing/validation and legacy decrypt scenarios).

## Upgrade Steps

Follow these steps to perform the upgrade:

1.  In Anypoint Studio, create a Mule project.

2.  In **Mule Palette**, click **Search in Exchange**.

3.  In **Add Dependencies to Project**, enter `cryptography module` in the search field.

4.  In **Available modules**, select **Cryptography Module** and click **Add**.

5.  Click **Finish**.

6.  Verify that the `mule-cryptography-module` dependency version is 2.x in the `pom.xml` file in
    the Mule project.

Studio upgrades the connector automatically.

## Post Upgrade Steps

After upgrading Cryptography Module, the module no longer bundles security providers. If your
environment already has the security providers (such as those in the MuleSoft Government Cloud
environment), you must not do any additional configuration. The existing environment offers ‌the
security providers. Otherwise, add the dependencies for either Bouncy Castle (BC) or Bouncy Castle
FIPS (BCFIPS) to your Mule app project configuration by including them as
[Additional Plugin Dependencies](https://docs.mulesoft.com/mule-runtime/latest/mmp-concept#configure-plugin-dependencies)
or as [Shared Libraries](https://docs.mulesoft.com/mule-runtime/latest/mmp-concept#configure-shared-libraries) in your
`pom.xml` file of your Mule app. This ensures the module has access to the required security
providers for its operations.

BCFIPS dependency:

```xml
<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bc-fips</artifactId>
    <version>${bc-fips.version}</version>
</dependency>
<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcpg-fips</artifactId>
    <version>${bcpg-fips.version}</version>
</dependency>
```

BC dependency:

```xml
<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcpg-jdk18on</artifactId>
    <version>${bcpg.version}</version>
</dependency>
<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk18on</artifactId>
    <version>${bcprov.version}</version>
</dependency>
<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcpkix-jdk18on</artifactId>
    <version>${bcpkix.version}</version>
</dependency>
```

> [!IMPORTANT] For PGP operations, you must include `bcpkix-jdk18on` (or `bcpkix-fips` for FIPS
> environments) in addition to `bcpg-jdk18on` and `bcprov-jdk18on`. Without `bcpkix-jdk18on`, you
> may encounter runtime errors such as: \*
> `java.lang.ClassNotFoundException: org.bouncycastle.openpgp.PGPPublicKey` \*
> `java.lang.NoClassDefFoundError: org.bouncycastle.openpgp.PGPSecretKey`
>
> The `bcpkix-jdk18on` library contains essential classes for PGP key handling and cryptographic
> protocol structures.

### Using Bouncy Castle JDK 18 on Dependencies Version 1.80

Starting from Bouncy Castle version 1.80, the project version underwent a significant internal
reorganization, which affects how you must include the libraries when using JDK18on artifacts, for
example `bcprov-jdk18on`, `bcpg-jdk18on`.

In prior versions to version 1.80, for example 1.79 or earlier, to enable full functionality for PGP
operations and password-based encryption (PBE) features, it was sufficient to add only the
`bcprov-jdk18on` or `bcpg-jdk18on` libraries.

These additional libraries are mandatory because:

- `bcpkix-jdk18on` contains essential cryptographic protocol classes, for example ASN.1 structures
  used in PGP operations.

- `bcutil-jdk18on` includes utility classes that are now referenced by low-level operations in the
  other modules.

If you don’t add these dependencies, you can encounter runtime errors such as:

- java.lang.ClassNotFoundException: org.bouncycastle.bcpg.ArmoredOutputStream

- java.lang.NoClassDefFoundError: org.bouncycastle.asn1.cryptlib.CryptlibObjectIdentifiers

- java.lang.IllegalArgumentException: Attempt to override lookup strategy ParentFirstLookupStrategy
  for package: org.bouncycastle.asn1.nist

Therefore, if you use BC version 1.80 or higher with Cryptography Module 2.x in non-FIPS mode, make
sure you include these libraries in your Mule app:

- `bcprov-jdk18on`

- `bcpg-jdk18on`

- `bcpkix-jdk18on`

- `bcutil-jdk18on`

If you prefer a FIPS-compliant environment, use the `bc-fips` and `bcpg-fips` libraries.

Example of Mule Maven Plugin configuration for Cryptography Module using Bouncy Castle JDK 18 on
Dependencies Version 1.80:

```xml
<plugin>
    <!-- Mule Maven Plugin configuration -->
    <groupId>org.mule.tools.maven</groupId>
    <artifactId>mule-maven-plugin</artifactId>
    <version>${mule.maven.plugin.version}</version>
    <configuration>
        <!-- Plugin dependencies configuration-->
        <additionalPluginDependencies>
            <!-- The connector for which the dependency is defined -->
            <plugin>
                <groupId>com.mulesoft.modules</groupId>
                <artifactId>mule-cryptography-module</artifactId>
                <!-- Dependencies definition for the connector -->
                <additionalDependencies>
                    <!-- Bouncy Castle OpenPGP -->
                    <dependency>
						<groupId>org.bouncycastle</groupId>
						<artifactId>bcprov-jdk18on</artifactId>
						<version>1.80</version>
					</dependency>
					<dependency>
						<groupId>org.bouncycastle</groupId>
						<artifactId>bcpg-jdk18on</artifactId>
						<version>1.80</version>
					</dependency>
					<dependency>
						<groupId>org.bouncycastle</groupId>
						<artifactId>bcpkix-jdk18on</artifactId>
						<version>1.80</version>
					</dependency>
					<dependency>
						<groupId>org.bouncycastle</groupId>
						<artifactId>bcutil-jdk18on</artifactId>
						<version>1.80</version>
					</dependency>
                </additionalDependencies>
            </plugin>
        </additionalPluginDependencies>
    </configuration>
</plugin>
```

## Verify the Upgrade

After you install the latest version of the module, verify the upgrade:

1.  In Studio, verify that there are no errors in the **Problems** or **Console** views.

2.  Verify that there are no problems in the project’s `pom.xml` file.

3.  Test the connection to verify that the operations work.

## Reverting the Upgrade

If you must revert to the previous version of Cryptography Module, go to Anypoint Studio and do the
following:

1.  In the project’s `pom.xml file`, change the `mule-cryptography-module` dependency version 2.1.0
    to the previous version, and delete the dependencies used from the <dependencies> section.

2.  Return to the **Execute** tab, and in the **Engine** section, select one of the default engines.

3.  In the **Configuration XML** tab, confirm the selected engine name also changed.

## Changes to Default Values for Connector Operations

To improve the security posture of the Cryptography Module, many default values for operations and
configuration parameters are updated in version 2.x. These changes reflect the adoption of more
secure algorithm stacks and modern cryptographic practices.

When migrating from a previous version, declare the default values you relied on in version 1.x.
This ensures compatibility and avoids unexpected results due to default value changes in the new
version.

This table provides the default values that changed in version 2.x:

<table><caption>Table 1. Default values summary table</caption> <colgroup><col> <col> <col></colgroup><thead><tr><th>Component</th><th>Default in version 1.x</th><th>Default in version 2.x</th></tr></thead><tbody><tr><td><p>XML Signature Digest Algorithm</p></td><td><p><code>SHA1</code></p></td><td><p><code>SHA512</code></p></td></tr><tr><td><p>JCE PBE Signature Algorithm</p></td><td><p><code>PBEWithHmacSHA256</code></p></td><td><p><code>PBKDF2withHmacSHA512</code></p></td></tr><tr><td><p>JCE PBE Encryption/Decryption Algorithm</p></td><td><p><code>PBEWithHmacSHA256AndAES_128</code></p></td><td><p><code>PBKDF2withHmacSHA512<em>AES256</em>CBC__PKCS5Padding</code></p></td></tr><tr><td><p>Checksum Algorithm</p></td><td><p><code>SHA_256</code></p></td><td><p><code>SHA_512</code></p></td></tr><tr><td><p>Keystore Type</p></td><td><p><code>JKS</code></p></td><td><p>None, must be explicitly provided; BCFKS required in FIPS.</p></td></tr></tbody></table>

## Migrate PGP Keyring to AES-Encrypted Keys for FIPS

To ensure your Mule app adheres to FIPS when performing PGP operations, you must migrate your PGP
keyrings to utilize Advanced Encryption Standard (AES) encryption.

The default PGP key generation employs the CAST5 cipher, which isn’t FIPS-compliant. Using
non-compliant ciphers can lead to runtime exceptions, such as
`org.mule.runtime.api.exception.MuleRuntimeException` indicating issues with the signed content
format and a failure in the signing operation. This exception can happen if the `InputStream`
returned by the PGP operation is empty or corrupted.

To achieve FIPS compliance for PGP signatures, follow this process:

1.  Create keyrings and keys

2.  Migrate keys to AES

3.  Export secret and public keys

4.  Configure the Cryptography Module to use the keyring

### Create Keyrings and Keys

> [!NOTE] Create a backup of your keyrings and keys in case you must perform a rollback.

To create a keyring from scratch, perform ‌these steps using GNU GPG:

1.  Create a new keyring by running this command:

```xml
gpg --no-default-keyring --keyring example.kbx --fingerprint
gpg: keybox '/Users/youruser/.gnupg/example.kbx' created
```

2.  Save the new keybox location to use it later.

3.  Create your PGP keys for signing or validating by running this command and following the
    instructions returned. (Select RSA as your cipher, because DSA isn’t FIPS-compliant.)

**On Windows:**

```cmd
gpg --no-default-keyring --keyring C:\Users\youruser\AppData\Roaming\gnupg\example.kbx --full-generate-key
```

**On Linux/macOS:**

```bash
gpg --no-default-keyring --keyring example.kbx --full-generate-key
gpg (GnuPG/MacGPG2) 2.2.41; Copyright (C) 2022 g10 Code GmbH
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Please select what kind of key you want:
   (1) RSA and RSA (default)
   (2) DSA and Elgamal
   (3) DSA (sign only)
   (4) RSA (sign only)
  (14) Existing key from card
Your selection? 1
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (3072) 4096
Requested keysize is 4096 bits
Please specify how long the key should be valid.
         0 = key does not expire
      <n>  = key expires in n days
      <n>w = key expires in n weeks
      <n>m = key expires in n months
      <n>y = key expires in n years
Key is valid for? (0) 0
Key does not expire at all
Is this correct? (y/N) y
GnuPG needs to construct a user ID to identify your key.
Real name: Test
Name must be at least 5 characters long
Real name: TestName
Email address: test@example.com
Comment:
You selected this USER-ID:
    "TestName <test@example.com>"
Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
gpg: revocation certificate stored as '/Users/youruser/.gnupg/openpgp-revocs.d/991F7216B03C0B2B088AB20D5F46261934B56AF2.rev'
public and secret key created and signed.
pub   rsa4096 2024-12-26 [SC]
      991F7216B03C0B2B088AB20D5F46261934B56AF2
uid                      TestName <test@example.com>
sub   rsa4096 2024-12-26 [E]
```

4.  List your keys to find out their fingerprints before migrating them to AES by running this
    command:

**On Windows:**

```cmd
gpg --no-default-keyring --keyring C:\Users\youruser\AppData\Roaming\gnupg\example.kbx --list-secret-keys --keyid-format=long --fingerprint
C:\Users\youruser\AppData\Roaming\gnupg\example.kbx
---------------------------------------------------
sec   rsa4096/5F46261934B56AF2 2024-12-26 [SC]
      Key fingerprint = 991F 7216 B03C 0B2B 088A  B20D 5F46 2619 34B5 6AF2
uid                 [ultimate] TestName <test@example.com>
ssb   rsa4096/E7C647D222B1F1C1 2024-12-26 [E]
```

**On Linux/macOS:**

```bash
gpg --no-default-keyring --keyring /Users/youruser/.gnupg/example.kbx --list-secret-keys --keyid-format=long --fingerprint
/Users/youruser/.gnupg/example.kbx
-----------------------------------
sec   rsa4096/5F46261934B56AF2 2024-12-26 [SC]
      Key fingerprint = 991F 7216 B03C 0B2B 088A  B20D 5F46 2619 34B5 6AF2
uid                 [ultimate] TestName <test@example.com>
ssb   rsa4096/E7C647D222B1F1C1 2024-12-26 [E]
```

### Migrate Keys to AES

> [!WARNING] This migration process may not work reliably with GPG 2.1 and later versions due to
> `gpg-agent` limitations. If the migration fails, use the
> [programmatic Bouncy Castle approach](#alternative-programmatic-key-generation) instead.

Migrate each key to AES with SHA256 to make them FIPS compliant:

1.  Copy the key to migrate fingerprint.

2.  Paste the key in this ‌command without spaces. Note that running this command enables a command
    line:

**On Windows:**

```cmd
gpg --no-default-keyring --keyring C:\Users\youruser\AppData\Roaming\gnupg\example.kbx --s2k-cipher-algo AES256 --s2k-digest-algo SHA256 --s2k-mode 3 --s2k-count 65000000 --edit-key [KEYID]
```

**On Linux/macOS:**

```bash
gpg --no-default-keyring --keyring /Users/youruser/.gnupg/example.kbx --s2k-cipher-algo AES256 --s2k-digest-algo SHA256 --s2k-mode 3 --s2k-count 65000000 --edit-key [KEYID]
```

3.  Enter the passwd command to change the key password. You can use the same password. A prompt
    requires the current password first and then the new one:

```bash
passwd
```

4.  Exit the gpg prompt:

    - On Windows: Press `Ctrl+C`

    - On macOS: Press `Command+C`

    - On Linux: Press `Ctrl+C`

5.  Repeat this procedure for each of the listed keys in your keybox.

#### Verify Key Protection

After creating or migrating a key, validate that the expected protection algorithms, AES-256 and
SHA-256 are correctly applied.

Run this command to inspect the actual protection applied to the secret key:

```xml
gpg --export-secret-keys [KEYID] | gpg --list-packets
```

1.  In the output, look for a line similar to:

iter+salt S2K, algo: 9, SHA256 protection, hash: 8

Use this reference to interpret the values:

<table><colgroup><col> <col></colgroup><thead><tr><th>Algorithm</th><th>Hash Function</th></tr></thead><tbody><tr><td><div><div><ul><li><p><code>algo: 9</code> → AES256</p></li><li><p><code>algo: 7</code> → AES128</p></li></ul></div></div></td><td><div><div><ul><li><p><code>hash: 8</code> → SHA256</p></li><li><p><code>hash: 2</code> → SHA1</p></li></ul></div></div></td></tr></tbody></table>

If the output shows AES128 or SHA1, it means the protection wasn’t correctly applied, and the key
isn’t FIPS-compliant. In that case, repeat the migration process or consider using the next
alternative approach.

Note that SHA1 protection can still appear in GPG output due to the v4 packet format, even when
SHA256 is used for the hash algorithm. For example:

iter+salt S2K, algo: 9, SHA1 protection, hash: 8

In this case, `algo: 9` indicates AES256 encryption and `hash: 8` indicates SHA256 hashing. The
"SHA1 protection" text refers to the packet format version, not the actual hash algorithm used. ====
FIPS Support Matrix

<table><colgroup><col> <col> <col></colgroup><thead><tr><th>Operation</th><th>FIPS Support</th><th>Notes</th></tr></thead><tbody><tr><td><p>PGP Encrypt</p></td><td><p>Not supported — blocked by BCFIPS since RSA PKCS#1 v1.5 encryption is disallowed.</p></td><td><p>OpenPGP limitation in FIPS environments</p></td></tr><tr><td><p>PGP Decrypt</p></td><td><p>Supported</p></td><td><p>For legacy data compatibility</p></td></tr><tr><td><p>PGP Sign</p></td><td><p>Supported</p></td><td><p>With AES256 and SHA256 protection</p></td></tr><tr><td><p>PGP Validate</p></td><td><p>Supported</p></td><td><p>For legacy data compatibility</p></td></tr></tbody></table>

PGP Encrypt remains unsupported in FIPS environments by design due to OpenPGP limitations. However,
PGP Decrypt and Validate operations are supported for processing legacy data. ==== GPG Behavior by
Version

<table><colgroup><col> <col> <col></colgroup><thead><tr><th>GPG Version</th><th>Key Generation Command</th><th>Output Behavior</th></tr></thead><tbody><tr><td><p>GPG 2.0 and lower</p></td><td><p><code>--gen-key</code></p></td><td><p>Output correctly shows AES-256 cipher and SHA-256 hash, but secret key packet still displays "SHA1 protection" field</p></td></tr><tr><td><p>GPG 2.1 and higher</p></td><td><p><code>--full-generate-key</code></p></td><td><p>Output correctly shows AES-256 cipher and SHA-256 hash, but secret key packet still displays "SHA1 protection" field</p></td></tr></tbody></table>

For both GPG versions, the "SHA1 protection" field in the secret key packet refers to the packet
format version, not the actual protection algorithms used.

### Export Secret and Public Key

After migrating the keys to AES (or generating them programmatically), export the secret and public
keys:

1.  Export the secret keys in a secret keyring to be used by the `mule-cryptography-module` module
    by running this command. This prompts you to enter the password for each of the secret keys in
    the keybox:

**On Windows:**

```cmd
gpg --no-default-keyring --keyring C:\Users\youruser\AppData\Roaming\gnupg\example.kbx --export-secret-keys > secring_example_aes.gpg
```

**On Linux/macOS:**

```bash
gpg --no-default-keyring --keyring /Users/youruser/.gnupg/example.kbx --export-secret-keys > secring_example_aes.gpg
```

1.  Export the public keys if needed:

**On Windows:**

```cmd
gpg --no-default-keyring --keyring C:\Users\youruser\AppData\Roaming\gnupg\example.kbx --export > pubring_example_aes.gpg
```

**On Linux/macOS:**

```bash
gpg --no-default-keyring --keyring /Users/youruser/.gnupg/example.kbx --export > pubring_example_aes.gpg
```

### Troubleshoot Key Protection Issues

In some cases, even after executing:

```xml
gpg --s2k-cipher-algo AES256 --s2k-digest-algo SHA256 --s2k-mode 3 --s2k-count 65000000 --edit-key [KEYID]
```

The key may still appear protected with AES128 and SHA1. This is due to a change introduced in GPG
2.1 and later: secret key protection is no longer managed directly by `gpg`, but by `gpg-agent`.

In GPG 2.1 and later, `gpg` isn’t directly responsible for encrypting secret keys at rest, and
options such as `--s2k-cipher-algo` have no effect. Instead, `gpg-agent` is solely responsible and
it provides no interface to change the cipher or digest algorithms in use.

In practice:

- S2K parameters passed on the command line or stored in `gpg.conf` aren’t applied when generating
  or editing keys in GPG 2.1+.

- `gpg-agent` uses internal defaults — typically AES128 and SHA1 — with no configuration interface
  to change them.

#### Alternative: Programmatic Key Generation with Bouncy Castle

If you want to make secret keys protected with certain algorithms, like AES256 and SHA256, use Java
and Bouncy Castle to make them directly.

This approach gives you full control over:

- Encryption algorithm: AES-256

- Hash digest: SHA-256

- S2K mode: Iterated and Salted (mode 3)

- Iteration count: e.g., 65,000,000

This method ensures FIPS-compliant protection and is suitable for automated or controlled
environments.

##### Complete Java Example for Programmatic Key Generation

Create a Java class to generate FIPS-compliant PGP keys. This example creates a complete key pair
with proper AES-256 and SHA-256 protection:

```java
import org.bouncycastle.bcpg.ArmoredOutputStream;
import org.bouncycastle.bcpg.HashAlgorithmTags;
import org.bouncycastle.bcpg.sig.Features;
import org.bouncycastle.bcpg.sig.KeyFlags;
import org.bouncycastle.crypto.generators.RSAKeyPairGenerator;
import org.bouncycastle.crypto.params.RSAKeyGenerationParameters;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openpgp.*;
import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptorBuilder;
import org.bouncycastle.openpgp.operator.PGPDigestCalculator;
import org.bouncycastle.openpgp.operator.bc.BcPBESecretKeyEncryptorBuilder;
import org.bouncycastle.openpgp.operator.bc.BcPGPContentSignerBuilder;
import org.bouncycastle.openpgp.operator.bc.BcPGPDigestCalculatorProvider;
import org.bouncycastle.openpgp.operator.bc.BcPGPKeyPair;

import java.io.*;
import java.math.BigInteger;
import java.security.SecureRandom;
import java.security.Security;
import java.util.Date;

public class PGPKeyGenerator {

    static {
        if (Security.getProvider("BC") == null) {
            Security.addProvider(new BouncyCastleProvider());
        }
    }

    public static void generateKeyPair(
            String identity,
            String passphrase,
            String secretKeyringPath,
            String publicKeyringPath,
            int keySize) throws Exception {

        // Generate RSA key pair
        RSAKeyPairGenerator keyPairGenerator = new RSAKeyPairGenerator();
        RSAKeyGenerationParameters keyGenParams = new RSAKeyGenerationParameters(
            BigInteger.valueOf(0x10001), new SecureRandom(), keySize, 12);
        keyPairGenerator.init(keyGenParams);

        // Create PGP key pair
        BcPGPKeyPair signingKeyPair = new BcPGPKeyPair(
            PGPPublicKey.RSA_SIGN, keyPairGenerator.generateKeyPair(), new Date());
        BcPGPKeyPair encryptionKeyPair = new BcPGPKeyPair(
            PGPPublicKey.RSA_ENCRYPT, keyPairGenerator.generateKeyPair(), new Date());

        // Create key ring generator
        PGPKeyRingGenerator keyRingGen = new PGPKeyRingGenerator(
            PGPSignature.POSITIVE_CERTIFICATION,
            signingKeyPair,
            identity,
            new BcPGPDigestCalculatorProvider().get(HashAlgorithmTags.SHA256),
            null,
            null,
            new BcPGPContentSignerBuilder(
                signingKeyPair.getPublicKey().getAlgorithm(),
                HashAlgorithmTags.SHA256),
            createKeyEncryptor(passphrase));

        // Add encryption subkey
        keyRingGen.addSubKey(encryptionKeyPair);

        // Generate secret key ring
        PGPSecretKeyRing secretKeyRing = keyRingGen.generateSecretKeyRing();
        try (FileOutputStream fos = new FileOutputStream(secretKeyringPath);
             ArmoredOutputStream aos = new ArmoredOutputStream(fos)) {
            secretKeyRing.encode(aos);
        }

        // Generate public key ring
        PGPPublicKeyRing publicKeyRing = keyRingGen.generatePublicKeyRing();
        try (FileOutputStream fos = new FileOutputStream(publicKeyringPath);
             ArmoredOutputStream aos = new ArmoredOutputStream(fos)) {
            publicKeyRing.encode(aos);
        }
    }

    private static PBESecretKeyEncryptorBuilder createKeyEncryptor(String passphrase) {
        PGPDigestCalculator sha256Calc = new BcPGPDigestCalculatorProvider()
            .get(HashAlgorithmTags.SHA256);

        return new BcPBESecretKeyEncryptorBuilder(
            PGPEncryptedData.AES_256, sha256Calc)
            .setProvider("BC")
            .setIterationCount(65000000);
    }

    public static void main(String[] args) throws Exception {
        generateKeyPair(
            "TestName <test@example.com>",
            "your-secure-passphrase",
            "secring_example_aes.gpg",
            "pubring_example_aes.gpg",
            4096);
    }
}
```

##### Maven Dependencies Required

Add these dependencies to your `pom.xml` to compile and run the key generation code:

```xml
<dependencies>
    <dependency>
        <groupId>org.bouncycastle</groupId>
        <artifactId>bcpg-jdk18on</artifactId>
        <version>1.80</version>
    </dependency>
    <dependency>
        <groupId>org.bouncycastle</groupId>
        <artifactId>bcprov-jdk18on</artifactId>
        <version>1.80</version>
    </dependency>
    <dependency>
        <groupId>org.bouncycastle</groupId>
        <artifactId>bcpkix-jdk18on</artifactId>
        <version>1.80</version>
    </dependency>
    <dependency>
        <groupId>org.bouncycastle</groupId>
        <artifactId>bcutil-jdk18on</artifactId>
        <version>1.80</version>
    </dependency>
</dependencies>
```

##### Compile and Run

**On Windows:**

```cmd
javac -cp "bcpg-jdk18on-1.80.jar;bcprov-jdk18on-1.80.jar;bcpkix-jdk18on-1.80.jar;bcutil-jdk18on-1.80.jar" PGPKeyGenerator.java
java -cp ".;bcpg-jdk18on-1.80.jar;bcprov-jdk18on-1.80.jar;bcpkix-jdk18on-1.80.jar;bcutil-jdk18on-1.80.jar" PGPKeyGenerator
```

**On Linux/macOS:**

```bash
javac -cp "bcpg-jdk18on-1.80.jar:bcprov-jdk18on-1.80.jar:bcpkix-jdk18on-1.80.jar:bcutil-jdk18on-1.80.jar" PGPKeyGenerator.java
java -cp ".:bcpg-jdk18on-1.80.jar:bcprov-jdk18on-1.80.jar:bcpkix-jdk18on-1.80.jar:bcutil-jdk18on-1.80.jar" PGPKeyGenerator
```

This generates `secring_example_aes.gpg` and `pubring_example_aes.gpg` files with FIPS-compliant
AES-256 and SHA-256 protection.

### Configure the Cryptography Module to Use the Keyring

Configure the Cryptography Module to use the generated keyring for signature and validation.

1.  Copy the `secring_example.aes.gpg` and `pubring_example_aes.gpg` to your Mule project’s
    `src/main/resources` folder or to the ‌location inside your on-premises server.

2.  Create a pop configuration like this to be used by the Cryptography Module PGP operations:

```xml
<crypto:pgp-config name="pgpConfig-aes" publicKeyring="pubring_example_aes.gpg" privateKeyring="secring_example_aes.gpg">
        <crypto:pgp-key-infos>
            <crypto:pgp-asymmetric-key-info keyId="validation" fingerprint="5F46261934B56AF2" passphrase="mule1234"/>
            <crypto:pgp-asymmetric-key-info keyId="signature"
                                            principal="TestName &lt;test@example.com&gt;"/>
        </crypto:pgp-key-infos>
    </crypto:pgp-config>
```

Notes for Cryptography Module PGP operations:

- The fingerprint used for validation can be the complete value or the last 16 characters, as shown
  in the previous example.

- The org.mule.runtime.api.exception.MuleRuntimeException may be thrown at runtime in FIPS
  environments if the sign operation fails to generate the signed content. This can occur if the
  InputStream is empty or corrupted, or if a non-compliant cipher is configured in the keyrings or
  generated PGP keys. Make sure your keyring and keys follow the guidelines in this migration guide.

- DSA encryption isn’t allowed because DSA isn’t a FIPS-compliant cipher.

- ECDSA or RSA PKCS v1.5 algorithms are no longer allowed for encryption in FIPS environments. If
  you use the PGP Encrypt operation with these algorithms, you can get these errors:

  - "RSA PKCS#1 v1.5 encryption disallowed"

  - "Can’t use ECDSA for encryption"

  - "ElGamal KeyFactory not available"

- RSA encryption using PKCS#1 v1.5 is also disabled in FIPS mode. While you can reenable it using
  the system property `-Dorg.bouncycastle.rsa.allow_pkcs15_enc=true`, don’t enable it so you can
  maintain strict FIPS compliance. Enable it only if necessary and you understand the security
  implications.

## Use Different Key Pair for Sign, Encrypt, and Decrypt Operations

If you use the same key pair, especially when using Bouncy Castle FIPS as a security provider or
running your Mule app on MuleSoft Government Cloud, you can get this error:

```xml
org.mule.runtime.api.component.execution.ComponentExecutionException:
org.bouncycastle.crypto.IllegalKeyException: Attempt to sign/verify with RSA modulus already used for encrypt/decrypt
```

Therefore, use different key pairs for Sign, Encrypt, and Decrypt operations.

## Use Password-Based Encryption

When using a FIPS-enabled environment, password-based encryption (PBE) algorithms starting with
PBEWith are no longer supported because of security limits. For example:

- `PBEWithSHA1AndRC2_40`

- `PBEWithSHA1AndRC2_128`

- `PBEWithSHA1AndRC4_128`

- `PBEWithSHA1AndRC4_40`

- `PBEWithMD5AndDES`

- `PBEWithMD5AndTripleDES`

- `PBEWithSHA1AndDESede`

To ensure compliance, all password-based encryption implementations in FIPS mode follow these rules:

- Your password must be at least 16 characters long.

- A password SALT is mandatory for all PBE operations. This password must be at least 16 characters
  long. Furthermore, for enhanced security, you must change the password SALT for each configured
  operation.

- For sign or validate, the default algorithm is PBKDF2withHmacSHA512.

- For encrypt or decrypt, the default algorithm is PBKDF2withHmacSHA512_AES256_CBC\_\_PKCS5Padding

- JCE PBE operations in FIPS environments require both a password SALT and an iteration count. You
  must update the module configurations to provide these values for all PBE operations. If you have
  data that was encrypted without a SALT and iteration count, you have these options:

  - Decrypt it outside of FIPS mode.

  - Temporarily enable the `com.mulesoft.crypto.allow-default-kdf-params` system property to decrypt
    it within FIPS, and then re-encrypt it using the new configuration. Also, in a FIPS environment,
    you must enable the `` com.mulesoft.crypto.allow-sun-pbe-in-fips` `` system property to allow
    the use of SUN algorithms.

## Specify Algorithms Dynamically

Cryptography Module version 2.1.0 supports dynamic algorithm definitions, offering great flexibility
by removing the dependency of a predefined list of available values shown in the value provider.

You can specify dynamic algorithm definitions in two ways:

- As a complete transformation string available in your environment’s registered security providers
  (for example `PBEWithHmacSHA256AndAES_128`, `PBEwithSHA1and3-KeyDESede`, and so on).

- As a custom algorithm format introduced in version 2.1.0, which is detailed in the next section.

> [!NOTE] Algorithms not present in your Mule runtime’s `Security.getProviders()` list result in
> runtime errors. If needed, make sure you include the required cryptographic providers, for example
> BouncyCastle FIPS, BC non-FIPS, in your Mule app’s classpath or security configuration.

### Use Custom Algorithm Format

To enable better support for modern cryptographic configurations, especially in FIPS environments,
Cryptography Module version 2.1.0 introduces a custom algorithm format that separates key derivation
and encryption components.

Format: `PBKDF2withHmac<digest>_AES<keyLength>_<mode>__<padding>`

Example: `PBKDF2withHmacSHA512_AES256_CBC__PKCS5Padding`

This format:

- Ensures full compatibility with FIPS-approved cryptographic profiles.

- Provides explicit definition of key length, block mode, and padding.

- Enables support for future extensions without requiring changes to the connector code or Studio
  configuration.

You must define all four components. Defaults aren’t assumed. If a component is missing or
malformed, ‌validation fails.

<table><colgroup><col> <col></colgroup><thead><tr><th>Component</th><th>Description</th></tr></thead><tbody><tr><td><p>PBKDF2withHmac&lt;digest&gt;</p></td><td><p>Key derivation function (KDF) using HMAC + SHA512</p></td></tr><tr><td><p>AES&lt;keyLength&gt;</p></td><td><p>Cipher algorithm with key size (128, 192, 256)</p></td></tr><tr><td><p>mode</p></td><td><p>Cipher block mode (for example CBC, GCM)</p></td></tr><tr><td><p>padding</p></td><td><p>Padding scheme (for example PKCS5Padding, NoPadding)</p></td></tr></tbody></table>

Additionally, the default algorithm values are updated for stronger cryptographic guarantees:

<table><colgroup><col> <col> <col></colgroup><thead><tr><th>Operation</th><th>Default value Cryptography Module version 1.x</th><th>Default value Cryptography Module version 2.x</th></tr></thead><tbody><tr><td><p><strong>Encrypt</strong> or <strong>Decrypt</strong></p></td><td><p><code>PBEWithHmacSHA256AndAES_128</code></p></td><td><p><code>PBKDF2withHmacSHA512<em>AES256</em>CBC__PKCS5Padding</code></p></td></tr><tr><td><p><strong>Sign</strong> or <strong>Validate</strong></p></td><td><p><code>PBEWithHmacSHA256</code></p></td><td><p>`PBKDF2withHmacSHA512</p></td></tr></tbody></table>

## Register the XMLDSig Security Provider

Cryptographic operations involving XML signatures (for example XML Sign, XML Encrypt, XML Decrypt,
and XML Validate) require the XMLDSig security provider (org.jcp.xml.dsig.internal.dom.XMLDSigRI),
commonly provided by Apache Santuario.

In FIPS-compliant environments, this provider might not be available or registered by default due to
stricter security policies.

To enable these XML-related cryptographic operations, the module can register the provider if you
explicitly set this system property:

`` -Dcom.mulesoft.connectors.allow-registration-of-xmldsig-provider-in-fips` ``

This action registers the provider at the JVM level, making it globally available to all Mule apps
running on the same JVM. Only use this setting if your Mule app explicitly requires XML signature or
encryption support and the provider isn’t already present.

## Enable Compatibility for Decrypt or Validate Operations without KDF Parameters

In Cryptography Module version 2.1, password-based encryption operations now enforce the
configuration of both SALT and `iterationCount` parameters for enhanced security.

To make sure your Mule app still decrypts or validates data that was encrypted or signed using
Cryptography Module version 1.x, where SALT and `iterationCount` weren’t mandatory, activate these
system properties:

```xml
com.mulesoft.crypto.allow-default-kdf-params=true
com.mulesoft.crypto.allow-sun-pbe-in-fips=true  (only necessary when running in a FIPS-enabled environment)
```

Activating these system properties enables ‌compatibility mode under these conditions:

- The operation is either Decrypt or Validate.

- The encryption algorithm is based on Sun’s PBE schemes, for example, `PBEWithHmacSHA1AndAES_128`.

- Neither SALT nor `iterationCount` parameters are explicitly provided (null or empty).

If you provide a value for either SALT or `iterationCount` parameters, the module targets version
2.x compatibility and intentionally fails the operation to avoid inconsistent behavior.

This compatibility mode is intended as a temporary solution to handle existing data. For all new
data, make sure you configure both SALT and `iterationCount` as required by Cryptography Module
version 2.x for optimal security and behavior.

## Use BCFKS as the Required Keystore and Truststore Type

To enhance security compliance, the Bouncy Castle FIPS Keystore (BCFKS) type is mandatory for all
Mule apps running in FIPS mode. You must migrate your existing Java KeyStore (JKS) or Public-Key
Cryptography Standards #12 (PKCS12) keystores and truststores to BCFKS and update your
mule-cryptography-module configurations to reference these new files:

1.  Download Bouncy Castle FIPS Provider:

```xml
curl -o $JAVA_HOME/jre/lib/ext/bc-fips-1.0.2.5.jar https://repo1.maven.org/maven2/org/bouncycastle/bc-fips/1.0.2.5/bc-fips-1.0.2.5.jar
```

2.  For JKS Keystores execute this keytool command, replacing `<keystore_password>` with your
    current keystore password and adjusting the file paths accordingly:

```xml
sudo /absolute/path/to/keytool_command/keytool -importkeystore -srckeystore /absolut/path/to/your/keystore/keystore.jks -srcstoretype JKS -srcstorepass changeit -destkeystore /absolute/path/to/new/keystore/keystore.bcfks -storepass <keystore_password> -deststoretype BCFKS -providerclass org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider -providerpath /absolut/path/to/bcfips-1.0.2.5.jar
```

For PKCS12 Keystores if your current keystore is in PKCS12 format, simply replace -srcstoretype JKS
with -srcstoretype PKCS12 in the previous command.

> [!NOTE] In FIPS environments, JKS can only store certificates and can’t hold private or secret
> keys. JKS isn’t enabled by default in Bouncy Castle FIPS. To use JKS, enable it by setting the
> system property:

`` org.bouncycastle.jca.enable_jks=true` ``

JKS is no longer the default keystore type. You must explicitly select the keystore type. In FIPS
environments, BCFKS is required.

## JCE Keystore Generation Example

Use **JCE Encrypt** as an alternative to **PGP Encrypt** when operating in a FIPS environment. PGP
Encrypt is not supported in FIPS environments because the OpenPGP standard (RFC 4880) mandates the
use of RSAES-PKCS1-v1\_5, which is strictly prohibited in FIPS mode. For more information, refer to
[Scope and Limitations (FIPS)](#scope-and-limitations-fips).

To use JCE Encrypt in a FIPS environment, you must first generate a JCE keystore:

1.  Download Bouncy Castle FIPS Provider:

    ```xml
    curl -o $JAVA_HOME/jre/lib/ext/bc-fips-1.0.2.5.jar https://repo1.maven.org/maven2/org/bouncycastle/bc-fips/1.0.2.5/bc-fips-1.0.2.5.jar
    ```

2.  Generate the keystore.

    In this example, you generate a BCFKS using the AES symmetric algorithm:

    ```xml
    keytool -genseckey -alias <alias-name> -keyalg AES -keysize 256 \
      -keystore keystore.bcfks -storetype BCFKS \
      -providerclass org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider \
      -providerpath /absolute/path/to/bc-fips-1.0.2.5.jar
    ```

## See Also

- [Cryptography Module Reference 2.1](https://docs.mulesoft.com/cryptography-module/2.1/cryptography-module-reference)
