首页 > 解决方案 > 使用 Bouncy Castle 的三重 DES Java 实现返回意外结果

问题描述

我正在尝试使用 Bouncy Castle 在我的 Java 应用程序中实现三重 DES 加密(DESede/ECB w/ ZeroPadding)。我遇到了一个问题,即从实现返回的加密值与预期的加密值不匹配。

如果 key = "987ff3cc1e3d58d4a698985201d02aed" 和 unencryptedString = "4548812028759309-0394-123",我希望得到的加密字符串等于 "6d2db19ab8ff3ae7c59ef7af0813c84eabe7c8e551fedfcffc94a607a06b293"。我的实现返回“b8b63dc7c1ec5330b4e19e1210180a1ffa66936298ed8032ea38b7febb9ece98”。

我在看什么?

使用 Bouncy Castle 实现三重 DES

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());
    }
}

单元测试

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);
    }

}

标签: javaencryptionbouncycastletripledes

解决方案


推荐阅读