Плохое заполнение исключений JPA AttributeConverter / Проблема многопоточности - PullRequest
0 голосов
/ 15 февраля 2019

У меня есть конфиденциальные данные, которые необходимо зашифровать при сохранении в базе данных, чтобы никто не мог прочитать их, даже если они заглянут в базу данных.Таким образом, подход, который я использовал, заключается в использовании AttributeConverter.

Я создал такой класс

import javax.persistence.AttributeConverter;
import javax.persistence.Converter;

@Converter
public class SensitiveDataConverter implements AttributeConverter<String, String> {

    private final EncryptDecryptUtils encryptDecryptUtils;

    /**
     * Instantiates a new vulnerable data converter.
     * Not using {@link javax.inject.Inject}  because @Inject doesn't
     * work with AttributeConverter
     *
     */
    public SensitiveDataConverter() {
        this.encryptDecryptUtils = EncryptDecryptUtils.getInstance();
    }

    @Override
    public String convertToDatabaseColumn(String attribute) {
        return attribute != null ?  encryptDecryptUtils.encrypt(attribute): null;
    }

    @Override
    public String convertToEntityAttribute(String dbData) {
        return dbData != null ?  encryptDecryptUtils.decrypt(dbData): null;
    }

И в моем классе Entity у меня есть чувствительные поля, помеченные как

@Column
@Convert(converter = SensitiveDataConverter.class)
private String sensitiveData;

Существует более одного столбца с таким чувствительнымdata.

Мой код шифрования / дешифрования выглядит следующим образом.Я использую ключ длиной 128.

private static final byte[] IV = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
private static final IvParameterSpec IV_PARAMETER_SPEC = new IvParameterSpec(IV);
private static final int KEY_LENGTH = 128;

private final SecretKeySpec secretKeySpec;
private final Cipher cipher;

private static volatile EncryptDecryptUtils instance;

private String secretKey = "someSecretkey";

private String salt = "someSalt";

private EncryptDecryptUtils() {

    try {
        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
        KeySpec spec = new PBEKeySpec(secretKey.toCharArray(), salt.getBytes(StandardCharsets.UTF_8),
                65536, KEY_LENGTH);
        SecretKey tmp = factory.generateSecret(spec);
        secretKeySpec = new SecretKeySpec(tmp.getEncoded(), "AES");
        cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    } catch (NoSuchAlgorithmException | InvalidKeySpecException | NoSuchPaddingException e) {
        LOG.error("Error while encrypting: {}", e);
        throw new EncryptDecryptException("Error while initializing encryption mechanism", e);
    }

}

public static EncryptDecryptUtils getInstance() {
    if (instance == null) {
        synchronized (EncryptDecryptUtils .class) {
            if (instance == null) {
                instance = new EncryptDecryptUtils();
            }
        }
    }
    return instance;
}

public String encrypt(String stringToEncrypt){
    try {
        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, IV_PARAMETER_SPEC);
        return Base64.getEncoder().encodeToString(cipher.doFinal(stringToEncrypt.getBytes(StandardCharsets.UTF_8)));
    } catch (BadPaddingException | InvalidKeyException | IllegalBlockSizeException
            | InvalidAlgorithmParameterException e) {
        LOG.error("Error while encrypting: {}", stringToEncrypt, e);
        throw new EncryptDecryptException("Error while encrypting sensitive data", e);
    }
}

public  String decrypt(String stringToDecrypt){
    try {
        cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, IV_PARAMETER_SPEC);
        return new String(cipher.doFinal(Base64.getDecoder().decode(stringToDecrypt)), StandardCharsets.UTF_8);
    } catch (BadPaddingException | InvalidKeyException | IllegalBlockSizeException
            | InvalidAlgorithmParameterException e) {
        LOG.error("Error while decrypting: {}", stringToDecrypt, e);
        throw new EncryptDecryptException("Error while decrypting sensitive data", e);
    }
}

Весь поток кода работает отлично.Но время от времени во время расшифровки я вижу, как выдается это исключение

Caused by: javax.crypto.BadPaddingException: Invalid PKCS#5 padding length: <somenumber>
    at iaik.security.cipher.f.b(Unknown Source)
    at iaik.security.cipher.a.a(Unknown Source)
    at iaik.security.cipher.a.engineDoFinal(Unknown Source)
    at javax.crypto.Cipher.doFinal(Cipher.java:2164)
    at com.bmw.scmaer.scenario.util.EncryptDecryptUtils.decrypt(EncryptDecryptUtils.java:xxx)

Если я снова запускаю тот же поток.Оно работает.Это происходит с перерывами.Поэтому я не могу выяснить причину этого.

Я использую JPA и eclipselink в качестве ORM.

Любая помощь очень ценится.

...