BouncyCipherFactory.java
/*
* GordianKnot: Security Suite
* Copyright 2012-2026. Tony Washer
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package io.github.tonywasher.joceanus.gordianknot.impl.bc;
import io.github.tonywasher.joceanus.gordianknot.api.base.GordianException;
import io.github.tonywasher.joceanus.gordianknot.api.base.GordianKeySpec;
import io.github.tonywasher.joceanus.gordianknot.api.base.GordianLength;
import io.github.tonywasher.joceanus.gordianknot.api.cipher.GordianStreamCipher;
import io.github.tonywasher.joceanus.gordianknot.api.cipher.GordianSymCipher;
import io.github.tonywasher.joceanus.gordianknot.api.cipher.GordianWrapper;
import io.github.tonywasher.joceanus.gordianknot.api.cipher.spec.GordianCipherMode;
import io.github.tonywasher.joceanus.gordianknot.api.cipher.spec.GordianPadding;
import io.github.tonywasher.joceanus.gordianknot.api.cipher.spec.GordianStreamCipherSpec;
import io.github.tonywasher.joceanus.gordianknot.api.cipher.spec.GordianStreamKeySubType.GordianBlakeXofKey;
import io.github.tonywasher.joceanus.gordianknot.api.cipher.spec.GordianStreamKeySubType.GordianChaCha20Key;
import io.github.tonywasher.joceanus.gordianknot.api.cipher.spec.GordianStreamKeySubType.GordianElephantKey;
import io.github.tonywasher.joceanus.gordianknot.api.cipher.spec.GordianStreamKeySubType.GordianISAPKey;
import io.github.tonywasher.joceanus.gordianknot.api.cipher.spec.GordianStreamKeySubType.GordianRomulusKey;
import io.github.tonywasher.joceanus.gordianknot.api.cipher.spec.GordianStreamKeySubType.GordianSalsa20Key;
import io.github.tonywasher.joceanus.gordianknot.api.cipher.spec.GordianStreamKeySubType.GordianSkeinXofKey;
import io.github.tonywasher.joceanus.gordianknot.api.cipher.spec.GordianStreamKeySubType.GordianSparkleKey;
import io.github.tonywasher.joceanus.gordianknot.api.cipher.spec.GordianStreamKeySubType.GordianVMPCKey;
import io.github.tonywasher.joceanus.gordianknot.api.cipher.spec.GordianSymCipherSpec;
import io.github.tonywasher.joceanus.gordianknot.api.cipher.spec.GordianSymCipherSpecBuilder;
import io.github.tonywasher.joceanus.gordianknot.api.cipher.spec.GordianSymKeySpec;
import io.github.tonywasher.joceanus.gordianknot.api.cipher.spec.GordianSymKeyType;
import io.github.tonywasher.joceanus.gordianknot.api.key.GordianKey;
import io.github.tonywasher.joceanus.gordianknot.impl.core.base.GordianBaseData;
import io.github.tonywasher.joceanus.gordianknot.impl.core.base.GordianBaseFactory;
import io.github.tonywasher.joceanus.gordianknot.impl.core.cipher.GordianCoreCipherFactory;
import io.github.tonywasher.joceanus.gordianknot.impl.core.exc.GordianDataException;
import io.github.tonywasher.joceanus.gordianknot.impl.core.spec.cipher.GordianCoreStreamCipherSpec;
import io.github.tonywasher.joceanus.gordianknot.impl.core.spec.cipher.GordianCoreStreamKeySpec;
import io.github.tonywasher.joceanus.gordianknot.impl.core.spec.cipher.GordianCoreStreamKeySubType;
import io.github.tonywasher.joceanus.gordianknot.impl.core.spec.cipher.GordianCoreSymCipherSpec;
import io.github.tonywasher.joceanus.gordianknot.impl.core.spec.cipher.GordianCoreSymCipherSpecBuilder;
import io.github.tonywasher.joceanus.gordianknot.impl.core.spec.cipher.GordianCoreSymKeySpec;
import io.github.tonywasher.joceanus.gordianknot.impl.ext.digests.GordianBlake2bDigest;
import io.github.tonywasher.joceanus.gordianknot.impl.ext.digests.GordianBlake2sDigest;
import io.github.tonywasher.joceanus.gordianknot.impl.ext.engines.GordianAnubisEngine;
import io.github.tonywasher.joceanus.gordianknot.impl.ext.engines.GordianBlake2XEngine;
import io.github.tonywasher.joceanus.gordianknot.impl.ext.engines.GordianBlake3Engine;
import io.github.tonywasher.joceanus.gordianknot.impl.ext.engines.GordianLeaEngine;
import io.github.tonywasher.joceanus.gordianknot.impl.ext.engines.GordianMARSEngine;
import io.github.tonywasher.joceanus.gordianknot.impl.ext.engines.GordianRabbitEngine;
import io.github.tonywasher.joceanus.gordianknot.impl.ext.engines.GordianSimonEngine;
import io.github.tonywasher.joceanus.gordianknot.impl.ext.engines.GordianSkeinXofEngine;
import io.github.tonywasher.joceanus.gordianknot.impl.ext.engines.GordianSnow3GEngine;
import io.github.tonywasher.joceanus.gordianknot.impl.ext.engines.GordianSosemanukEngine;
import io.github.tonywasher.joceanus.gordianknot.impl.ext.engines.GordianSpeckEngine;
import io.github.tonywasher.joceanus.gordianknot.impl.ext.engines.GordianXChaCha20Engine;
import io.github.tonywasher.joceanus.gordianknot.impl.ext.engines.GordianZuc128Engine;
import io.github.tonywasher.joceanus.gordianknot.impl.ext.engines.GordianZuc256Engine;
import io.github.tonywasher.joceanus.gordianknot.impl.ext.modes.GordianChaChaPoly1305;
import io.github.tonywasher.joceanus.gordianknot.impl.ext.modes.GordianGCMSIVBlockCipher;
import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.BufferedBlockCipher;
import org.bouncycastle.crypto.CipherKeyGenerator;
import org.bouncycastle.crypto.DefaultBufferedBlockCipher;
import org.bouncycastle.crypto.StreamCipher;
import org.bouncycastle.crypto.engines.AESEngine;
import org.bouncycastle.crypto.engines.ARIAEngine;
import org.bouncycastle.crypto.engines.AsconAEAD128;
import org.bouncycastle.crypto.engines.BlowfishEngine;
import org.bouncycastle.crypto.engines.CAST5Engine;
import org.bouncycastle.crypto.engines.CAST6Engine;
import org.bouncycastle.crypto.engines.CamelliaEngine;
import org.bouncycastle.crypto.engines.ChaCha7539Engine;
import org.bouncycastle.crypto.engines.ChaChaEngine;
import org.bouncycastle.crypto.engines.DESedeEngine;
import org.bouncycastle.crypto.engines.DSTU7624Engine;
import org.bouncycastle.crypto.engines.ElephantEngine;
import org.bouncycastle.crypto.engines.GOST28147Engine;
import org.bouncycastle.crypto.engines.GOST3412_2015Engine;
import org.bouncycastle.crypto.engines.Grain128Engine;
import org.bouncycastle.crypto.engines.HC128Engine;
import org.bouncycastle.crypto.engines.HC256Engine;
import org.bouncycastle.crypto.engines.IDEAEngine;
import org.bouncycastle.crypto.engines.ISAACEngine;
import org.bouncycastle.crypto.engines.ISAPEngine;
import org.bouncycastle.crypto.engines.NoekeonEngine;
import org.bouncycastle.crypto.engines.PhotonBeetleEngine;
import org.bouncycastle.crypto.engines.PhotonBeetleEngine.PhotonBeetleParameters;
import org.bouncycastle.crypto.engines.RC2Engine;
import org.bouncycastle.crypto.engines.RC4Engine;
import org.bouncycastle.crypto.engines.RC532Engine;
import org.bouncycastle.crypto.engines.RC564Engine;
import org.bouncycastle.crypto.engines.RC6Engine;
import org.bouncycastle.crypto.engines.RomulusEngine;
import org.bouncycastle.crypto.engines.SEEDEngine;
import org.bouncycastle.crypto.engines.SM4Engine;
import org.bouncycastle.crypto.engines.Salsa20Engine;
import org.bouncycastle.crypto.engines.SerpentEngine;
import org.bouncycastle.crypto.engines.Shacal2Engine;
import org.bouncycastle.crypto.engines.SkipjackEngine;
import org.bouncycastle.crypto.engines.SparkleEngine;
import org.bouncycastle.crypto.engines.TEAEngine;
import org.bouncycastle.crypto.engines.ThreefishEngine;
import org.bouncycastle.crypto.engines.TwofishEngine;
import org.bouncycastle.crypto.engines.VMPCEngine;
import org.bouncycastle.crypto.engines.VMPCKSA3Engine;
import org.bouncycastle.crypto.engines.XSalsa20Engine;
import org.bouncycastle.crypto.engines.XTEAEngine;
import org.bouncycastle.crypto.engines.XoodyakEngine;
import org.bouncycastle.crypto.generators.DESedeKeyGenerator;
import org.bouncycastle.crypto.modes.AEADBlockCipher;
import org.bouncycastle.crypto.modes.AEADCipher;
import org.bouncycastle.crypto.modes.CBCBlockCipher;
import org.bouncycastle.crypto.modes.CCMBlockCipher;
import org.bouncycastle.crypto.modes.CFBBlockCipher;
import org.bouncycastle.crypto.modes.CTSBlockCipher;
import org.bouncycastle.crypto.modes.EAXBlockCipher;
import org.bouncycastle.crypto.modes.G3413CBCBlockCipher;
import org.bouncycastle.crypto.modes.G3413CFBBlockCipher;
import org.bouncycastle.crypto.modes.G3413CTRBlockCipher;
import org.bouncycastle.crypto.modes.G3413OFBBlockCipher;
import org.bouncycastle.crypto.modes.GCFBBlockCipher;
import org.bouncycastle.crypto.modes.GCMBlockCipher;
import org.bouncycastle.crypto.modes.GOFBBlockCipher;
import org.bouncycastle.crypto.modes.KCTRBlockCipher;
import org.bouncycastle.crypto.modes.OCBBlockCipher;
import org.bouncycastle.crypto.modes.OFBBlockCipher;
import org.bouncycastle.crypto.modes.SICBlockCipher;
import org.bouncycastle.crypto.paddings.ISO7816d4Padding;
import org.bouncycastle.crypto.paddings.PKCS7Padding;
import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.bouncycastle.crypto.paddings.TBCPadding;
import org.bouncycastle.crypto.paddings.X923Padding;
import org.bouncycastle.crypto.patch.modes.GordianKCCMBlockCipher;
import org.bouncycastle.crypto.patch.modes.GordianKGCMBlockCipher;
import java.util.HashMap;
import java.util.Map;
/**
* Factory for BouncyCastle Ciphers.
*/
public class BouncyCipherFactory
extends GordianCoreCipherFactory {
/**
* KeyPairGenerator Cache.
*/
private final Map<GordianKeySpec, BouncyKeyGenerator<? extends GordianKeySpec>> theCache;
/**
* Constructor.
*
* @param pFactory the factory
*/
BouncyCipherFactory(final GordianBaseFactory pFactory) {
/* Initialise underlying class */
super(pFactory);
/* Create the cache */
theCache = new HashMap<>();
}
@Override
@SuppressWarnings("unchecked")
public <T extends GordianKeySpec> BouncyKeyGenerator<T> getKeyGenerator(final T pKeySpec) throws GordianException {
/* Look up in the cache */
BouncyKeyGenerator<T> myGenerator = (BouncyKeyGenerator<T>) theCache.get(pKeySpec);
if (myGenerator == null) {
/* Create the new generator */
final CipherKeyGenerator myBCGenerator = getBCKeyGenerator(pKeySpec);
myGenerator = new BouncyKeyGenerator<>(getFactory(), pKeySpec, myBCGenerator);
/* Add to cache */
theCache.put(pKeySpec, myGenerator);
}
return myGenerator;
}
@Override
public GordianSymCipher createSymKeyCipher(final GordianSymCipherSpec pCipherSpec) throws GordianException {
/* Check validity of SymKeySpec */
checkSymCipherSpec(pCipherSpec);
final GordianCoreSymCipherSpec mySpec = (GordianCoreSymCipherSpec) pCipherSpec;
/* If this is an AAD cipher */
if (mySpec.isAAD()) {
/* Create the AAD cipher */
final AEADBlockCipher myBCCipher = getBCAADCipher(mySpec);
return new BouncySymKeyAEADCipher(getFactory(), mySpec, myBCCipher);
/* else create the standard cipher */
} else {
/* Create the cipher */
final BufferedBlockCipher myBCCipher = getBCBlockCipher(mySpec);
return new BouncySymKeyCipher(getFactory(), mySpec, myBCCipher);
}
}
@Override
public GordianStreamCipher createStreamKeyCipher(final GordianStreamCipherSpec pCipherSpec) throws GordianException {
/* Check validity of StreamKeySpec */
checkStreamCipherSpec(pCipherSpec);
final GordianCoreStreamCipherSpec mySpec = (GordianCoreStreamCipherSpec) pCipherSpec;
/* Create the cipher */
return pCipherSpec.isAEAD()
? new BouncyStreamKeyAEADCipher(getFactory(), mySpec, getBCAEADStreamCipher(mySpec))
: new BouncyStreamKeyCipher(getFactory(), mySpec, getBCStreamCipher(mySpec));
}
@Override
public GordianWrapper createKeyWrapper(final GordianKey<GordianSymKeySpec> pKey) throws GordianException {
/* Create the cipher */
final BouncyKey<GordianSymKeySpec> myKey = BouncyKey.accessKey(pKey);
final GordianSymCipherSpecBuilder myBuilder = GordianCoreSymCipherSpecBuilder.newInstance();
final GordianSymCipherSpec mySpec = myBuilder.ecb(myKey.getKeyType(), GordianPadding.NONE);
final BouncySymKeyCipher myBCCipher = (BouncySymKeyCipher) createSymKeyCipher(mySpec);
return createKeyWrapper(myKey, myBCCipher);
}
/**
* Create the BouncyCastle KeyGenerator.
*
* @param pKeySpec the keySpec
* @return the KeyGenerator
* @throws GordianException on error
*/
private CipherKeyGenerator getBCKeyGenerator(final GordianKeySpec pKeySpec) throws GordianException {
checkKeySpec(pKeySpec);
return pKeySpec instanceof GordianSymKeySpec mySpec
&& GordianSymKeyType.DESEDE.equals(mySpec.getSymKeyType())
? new DESedeKeyGenerator()
: new CipherKeyGenerator();
}
/**
* Create the BouncyCastle Block Cipher.
*
* @param pCipherSpec the cipherSpec
* @return the Cipher
* @throws GordianException on error
*/
private static BufferedBlockCipher getBCBlockCipher(final GordianCoreSymCipherSpec pCipherSpec) throws GordianException {
/* Build the cipher */
final BlockCipher myEngine = getBCSymEngine(pCipherSpec.getCoreKeySpec());
final BlockCipher myMode = getBCSymModeCipher(myEngine, pCipherSpec.getCipherMode());
return getBCSymBufferedCipher(myMode, pCipherSpec.getPadding());
}
/**
* Create the BouncyCastle Stream Cipher.
*
* @param pCipherSpec the cipherSpec
* @return the Cipher
* @throws GordianException on error
*/
private static StreamCipher getBCStreamCipher(final GordianCoreStreamCipherSpec pCipherSpec) throws GordianException {
final GordianCoreStreamKeySpec mySpec = pCipherSpec.getCoreKeySpec();
return switch (mySpec.getStreamKeyType()) {
case HC -> GordianLength.LEN_128 == mySpec.getKeyLength()
? new HC128Engine()
: new HC256Engine();
case CHACHA20 -> switch ((GordianChaCha20Key) mySpec.getSubKeyType()) {
case XCHACHA -> new GordianXChaCha20Engine();
case ISO7539 -> new ChaCha7539Engine();
default -> new ChaChaEngine();
};
case SALSA20 -> mySpec.getSubKeyType() == GordianSalsa20Key.STD
? new Salsa20Engine()
: new XSalsa20Engine();
case VMPC -> mySpec.getSubKeyType() == GordianVMPCKey.STD
? new VMPCEngine()
: new VMPCKSA3Engine();
case GRAIN -> new Grain128Engine();
case ISAAC -> new ISAACEngine();
case RC4 -> new RC4Engine();
case SOSEMANUK -> new GordianSosemanukEngine();
case RABBIT -> new GordianRabbitEngine();
case SNOW3G -> new GordianSnow3GEngine();
case ZUC -> GordianLength.LEN_128 == mySpec.getKeyLength()
? new GordianZuc128Engine()
: new GordianZuc256Engine();
case SKEINXOF -> {
final GordianSkeinXofKey mySkeinKeyType = (GordianSkeinXofKey) mySpec.getSubKeyType();
yield new GordianSkeinXofEngine(GordianCoreStreamKeySubType.getLengthForSkeinXofKey(mySkeinKeyType).getLength());
}
case BLAKE2XOF -> {
final GordianBlakeXofKey myBlakeKeyType = (GordianBlakeXofKey) mySpec.getSubKeyType();
yield new GordianBlake2XEngine(GordianBlakeXofKey.BLAKE2XB == myBlakeKeyType
? new GordianBlake2bDigest()
: new GordianBlake2sDigest());
}
case BLAKE3XOF -> new GordianBlake3Engine();
default -> throw new GordianDataException(GordianBaseData.getInvalidText(pCipherSpec));
};
}
/**
* Create the BouncyCastle AEAD Stream Cipher.
*
* @param pCipherSpec the cipherSpec
* @return the Cipher
* @throws GordianException on error
*/
private static AEADCipher getBCAEADStreamCipher(final GordianCoreStreamCipherSpec pCipherSpec) throws GordianException {
final GordianCoreStreamKeySpec mySpec = pCipherSpec.getCoreKeySpec();
return switch (mySpec.getStreamKeyType()) {
case CHACHA20 -> switch ((GordianChaCha20Key) mySpec.getSubKeyType()) {
case XCHACHA -> new GordianChaChaPoly1305(new GordianXChaCha20Engine());
default -> new GordianChaChaPoly1305(new ChaCha7539Engine());
};
case ASCON -> new AsconAEAD128();
case ELEPHANT ->
new ElephantEngine(GordianCoreStreamKeySubType.getParameters((GordianElephantKey) mySpec.getSubKeyType()));
case ISAP ->
new ISAPEngine(GordianCoreStreamKeySubType.getISAPType((GordianISAPKey) mySpec.getSubKeyType()));
case PHOTONBEETLE -> new PhotonBeetleEngine(PhotonBeetleParameters.pb128);
case ROMULUS ->
new RomulusEngine(GordianCoreStreamKeySubType.getParameters((GordianRomulusKey) mySpec.getSubKeyType()));
case SPARKLE ->
new SparkleEngine(GordianCoreStreamKeySubType.getParameters((GordianSparkleKey) mySpec.getSubKeyType()));
case XOODYAK -> new XoodyakEngine();
default -> throw new GordianDataException(GordianBaseData.getInvalidText(pCipherSpec));
};
}
/**
* Create the BouncyCastle Cipher Engine.
*
* @param pKeySpec the SymKeySpec
* @return the Engine
* @throws GordianException on error
*/
static BlockCipher getBCSymEngine(final GordianCoreSymKeySpec pKeySpec) throws GordianException {
return switch (pKeySpec.getSymKeyType()) {
case AES -> AESEngine.newInstance();
case SERPENT -> new SerpentEngine();
case TWOFISH -> new TwofishEngine();
case CAMELLIA -> new CamelliaEngine();
case RC6 -> new RC6Engine();
case CAST6 -> new CAST6Engine();
case ARIA -> new ARIAEngine();
case THREEFISH -> new ThreefishEngine(pKeySpec.getBlockLength().getLength());
case KALYNA -> new DSTU7624Engine(pKeySpec.getBlockLength().getLength());
case SM4 -> new SM4Engine();
case NOEKEON -> new NoekeonEngine();
case SEED -> new SEEDEngine();
case BLOWFISH -> new BlowfishEngine();
case SKIPJACK -> new SkipjackEngine();
case IDEA -> new IDEAEngine();
case TEA -> new TEAEngine();
case XTEA -> new XTEAEngine();
case RC2 -> new RC2Engine();
case RC5 -> GordianLength.LEN_128.equals(pKeySpec.getBlockLength())
? new RC564Engine()
: new RC532Engine();
case CAST5 -> new CAST5Engine();
case DESEDE -> new DESedeEngine();
case GOST -> new GOST28147Engine();
case KUZNYECHIK -> new GOST3412_2015Engine();
case SHACAL2 -> new Shacal2Engine();
case SPECK -> new GordianSpeckEngine();
case ANUBIS -> new GordianAnubisEngine();
case SIMON -> new GordianSimonEngine();
case MARS -> new GordianMARSEngine();
case LEA -> new GordianLeaEngine();
default -> throw new GordianDataException(GordianBaseData.getInvalidText(pKeySpec));
};
}
/**
* Create the BouncyCastle Buffered Cipher.
*
* @param pEngine the underlying engine
* @param pMode the cipher mode
* @return the Cipher
* @throws GordianException on error
*/
private static BlockCipher getBCSymModeCipher(final BlockCipher pEngine,
final GordianCipherMode pMode) throws GordianException {
return switch (pMode) {
case ECB -> pEngine;
case CBC -> CBCBlockCipher.newInstance(pEngine);
case SIC -> SICBlockCipher.newInstance(pEngine);
case KCTR -> new KCTRBlockCipher(pEngine);
case CFB -> CFBBlockCipher.newInstance(pEngine, Byte.SIZE * pEngine.getBlockSize());
case CFB8 -> CFBBlockCipher.newInstance(pEngine, Byte.SIZE);
case GCFB -> new GCFBBlockCipher(pEngine);
case OFB -> new OFBBlockCipher(pEngine, Byte.SIZE * pEngine.getBlockSize());
case OFB8 -> new OFBBlockCipher(pEngine, Byte.SIZE);
case GOFB -> new GOFBBlockCipher(pEngine);
case G3413CBC -> new G3413CBCBlockCipher(pEngine);
case G3413CTR -> new G3413CTRBlockCipher(pEngine);
case G3413CFB -> new G3413CFBBlockCipher(pEngine, Byte.SIZE * pEngine.getBlockSize());
case G3413OFB -> new G3413OFBBlockCipher(pEngine);
default -> throw new GordianDataException(GordianBaseData.getInvalidText(pMode));
};
}
/**
* Create the BouncyCastle Buffered Cipher.
*
* @param pCipherSpec the cipherSpec
* @return the Cipher
* @throws GordianException on error
*/
private static AEADBlockCipher getBCAADCipher(final GordianCoreSymCipherSpec pCipherSpec) throws GordianException {
final GordianCoreSymKeySpec mySpec = pCipherSpec.getCoreKeySpec();
return switch (pCipherSpec.getCipherMode()) {
case EAX -> new EAXBlockCipher(getBCSymEngine(mySpec));
case CCM -> CCMBlockCipher.newInstance(getBCSymEngine(mySpec));
case KCCM -> new GordianKCCMBlockCipher(getBCSymEngine(mySpec));
case GCM -> GCMBlockCipher.newInstance(getBCSymEngine(mySpec));
case GCMSIV -> new GordianGCMSIVBlockCipher(getBCSymEngine(mySpec));
case KGCM -> new GordianKGCMBlockCipher(getBCSymEngine(mySpec));
case OCB -> new OCBBlockCipher(getBCSymEngine(mySpec), getBCSymEngine(mySpec));
default -> throw new GordianDataException(GordianBaseData.getInvalidText(pCipherSpec));
};
}
/**
* Create the BouncyCastle Mode Cipher.
*
* @param pEngine the underlying engine
* @param pPadding use padding true/false
* @return the Cipher
*/
private static BufferedBlockCipher getBCSymBufferedCipher(final BlockCipher pEngine,
final GordianPadding pPadding) {
return switch (pPadding) {
case CTS -> new CTSBlockCipher(pEngine);
case X923 -> new PaddedBufferedBlockCipher(pEngine, new X923Padding());
case PKCS7 -> new PaddedBufferedBlockCipher(pEngine, new PKCS7Padding());
case ISO7816D4 -> new PaddedBufferedBlockCipher(pEngine, new ISO7816d4Padding());
case TBC -> new PaddedBufferedBlockCipher(pEngine, new TBCPadding());
default -> new DefaultBufferedBlockCipher(pEngine);
};
}
}