I'm attempting to implement Triple DES encryption (DESede/ECB w/ ZeroPadding) in my Java application using Bouncy Castle. I'm running into an issue where the encrypted value that is returned from the implementation doesn't match the expected encrypted value.
if key = "987ff3cc1e3d58d4a698985201d02aed" and unencryptedString = "4548812028759309-0394-123", I expect the resulting encrypted string to equal "6d2db19ab8ff3ae7c59ef7af0813c84eabe7c8e551fedfc94a607a06b239f4ef". My implementation is returning "b8b63dc7c1ec5330b4e19e1210180a1ffa66936298ed8032ea38b7febb9ece98".
What am I overlooking?
Triple DES Implementation using Bouncy Castle
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Security;
import java.util.Arrays;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
import org.apache.commons.codec.binary.Hex;
import org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider;
public class TripleDESEncryptor {
private static final String UNICODE_FORMAT = "UTF8";
private static final String DESEDE_ECB_ENCRYPTION_SCHEME = "DESede/ECB/NoPadding";
private static final String DESEDE_ENCRYPTION_SCHEME = "DESede";
private static String BOUNCY_CASTLE_FIPS_PROVIDER = "BCFIPS";
private final Cipher cipher;
private final SecretKey key;
public TripleDESEncryptor(byte[] encryptionKey) {
try {
ensureBouncyCastleFIPSProviderIsAvailable();
cipher = Cipher.getInstance(DESEDE_ECB_ENCRYPTION_SCHEME, BOUNCY_CASTLE_FIPS_PROVIDER);
key = SecretKeyFactory
.getInstance(DESEDE_ENCRYPTION_SCHEME, BOUNCY_CASTLE_FIPS_PROVIDER)
.generateSecret(new DESedeKeySpec(encryptionKey));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public String encrypt(String unencryptedString)
throws InvalidKeyException, InvalidAlgorithmParameterException,
UnsupportedEncodingException, IllegalBlockSizeException, BadPaddingException {
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] paddedPlainText = padWithZeroBytes(unencryptedString.getBytes(UNICODE_FORMAT));
return Hex.encodeHexString(cipher.doFinal(paddedPlainText));
}
private byte[] padWithZeroBytes(byte[] unencryptedString) {
return Arrays.copyOf(unencryptedString, roundUpToMultipleOf8(unencryptedString.length));
}
private int roundUpToMultipleOf8(int x) {
return ((x + 7) & (-8));
}
private void ensureBouncyCastleFIPSProviderIsAvailable() {
var bcfProvider = Arrays.stream(Security.getProviders())
.filter(provider -> BOUNCY_CASTLE_FIPS_PROVIDER.equals(provider.getName()))
.findAny().orElse(null);
if (bcfProvider == null)
Security.addProvider(new BouncyCastleFipsProvider());
}
}
Unit Test
import static org.junit.Assert.assertEquals;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.spec.InvalidParameterSpecException;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import org.junit.Test;
public class TripleDESEncryptorTest {
@Test
public void encrypt()
throws InvalidKeyException, InvalidParameterSpecException, IllegalBlockSizeException,
BadPaddingException, InvalidAlgorithmParameterException, UnsupportedEncodingException {
byte[] key = "987ff3cc1e3d58d4a698985201d02aed".getBytes("UTF8");
var encryptor = new TripleDESEncryptor(key);
String cleartext = "4548812028759309-0394-123";
String encrypted = encryptor.encrypt(cleartext);
assertEquals("6d2db19ab8ff3ae7c59ef7af0813c84eabe7c8e551fedfc94a607a06b239f4ef", encrypted);
}
}