org.eclipse.persistence.internal.security.JCEEncryptor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of eclipselink Show documentation
Show all versions of eclipselink Show documentation
EclipseLink build based upon Git transaction f2b9fc5
/*
* Copyright (c) 1998, 2020 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
// Contributors:
// Oracle - initial API and implementation from Oracle TopLink
package org.eclipse.persistence.internal.security;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.eclipse.persistence.exceptions.ConversionException;
import org.eclipse.persistence.exceptions.ValidationException;
import org.eclipse.persistence.internal.helper.Helper;
/**
* EclipseLink reference implementation for password encryption.
*
* @author Guy Pelletier
*/
public class JCEEncryptor implements Securable {
// Legacy DES ECB cipher used for backwards compatibility decryption only.
private static final String DES_ECB = "DES/ECB/PKCS5Padding";
private final Cipher decryptCipherDES_ECB;
// Legacy AES ECB cipher used for backwards compatibility decryption only.
private static final String AES_ECB = "AES/ECB/PKCS5Padding";
private final Cipher decryptCipherAES_ECB;
// All encryption is done through the AES CBC cipher.
private static final String AES_CBC = "AES/CBC/PKCS5Padding";
private final Cipher encryptCipherAES_CBC;
private final Cipher decryptCipherAES_CBC;
public JCEEncryptor() throws Exception {
/**
* We want to force the initialization of the cipher here. This is a fix
* for bug #2696486.
* JDev with JDK 1.3 in some cases will allow a JCE object to be created
* when it shouldn't. That is, JDev includes an incompletely configured JCE
* library for JDK 1.3, meaning JCE will not run properly in the VM. So, JDev
* allows you to create a JCEEncryptor object, but eventually throw's
* errors when trying to make JCE library calls from encryptPassword.
*
* Confusing??? Well, don't move this code before talking to Guy first!
*/
decryptCipherDES_ECB = Cipher.getInstance(DES_ECB);
decryptCipherDES_ECB.init(Cipher.DECRYPT_MODE, Synergizer.getDESMultitasker());
decryptCipherAES_ECB = Cipher.getInstance(AES_ECB);
decryptCipherAES_ECB.init(Cipher.DECRYPT_MODE, Synergizer.getAESMultitasker());
SecretKey sk = Synergizer.getAESCBCMultitasker();
IvParameterSpec iv = Synergizer.getIvSpec();
encryptCipherAES_CBC = Cipher.getInstance(AES_CBC);
encryptCipherAES_CBC.init(Cipher.ENCRYPT_MODE, sk, iv);
decryptCipherAES_CBC = Cipher.getInstance(AES_CBC);
decryptCipherAES_CBC.init(Cipher.DECRYPT_MODE, sk, iv);
}
/**
* Encrypts a string. Will throw a validation exception.
*/
@Override
public synchronized String encryptPassword(String password) {
try {
return Helper.buildHexStringFromBytes(encryptCipherAES_CBC.doFinal(password.getBytes("UTF-8")));
} catch (Exception e) {
throw ValidationException.errorEncryptingPassword(e);
}
}
/**
* Decrypts a string. Will throw a validation exception.
* Handles backwards compatibility for older encrypted strings.
*/
@Override
public synchronized String decryptPassword(String encryptedPswd) {
if (encryptedPswd == null) {
return null;
}
String password = null;
byte[] bytePassword = new byte[0];
try {
bytePassword = Helper.buildBytesFromHexString(encryptedPswd);
// try AES/CBC first
password = new String(decryptCipherAES_CBC.doFinal(bytePassword), "UTF-8");
} catch (ConversionException | IllegalBlockSizeException ce) {
// buildBytesFromHexString failed, assume clear text
password = encryptedPswd;
} catch (Exception e) {
ObjectInputStream oisAes = null;
try {
// try AES/ECB second
oisAes = new ObjectInputStream(new CipherInputStream(new ByteArrayInputStream(bytePassword), decryptCipherAES_ECB));
password = (String)oisAes.readObject();
} catch (Exception f) {
ObjectInputStream oisDes = null;
try {
// try DES/ECB third
oisDes = new ObjectInputStream(new CipherInputStream(new ByteArrayInputStream(bytePassword), decryptCipherDES_ECB));
password = (String)oisDes.readObject();
} catch (ArrayIndexOutOfBoundsException g) {
// JCE 1.2.1 couldn't decrypt it, assume clear text
password = encryptedPswd;
} catch (Exception h) {
if (h.getCause() instanceof IllegalBlockSizeException) {
// JCE couldn't decrypt it, assume clear text
password = encryptedPswd;
} else {
throw ValidationException.errorDecryptingPassword(h);
}
} finally {
if (oisDes != null) {
try {
oisDes.close();
} catch (IOException e2) {}
}
}
} finally {
if (oisAes != null) {
try {
oisAes.close();
} catch (IOException e1) {}
}
}
}
return password;
}
/**
* Returns multitaskers for the ciphers. :-)
*/
private static class Synergizer {
private static SecretKey getDESMultitasker() throws Exception {
SecretKeyFactory factory = SecretKeyFactory.getInstance("DES");
return factory.generateSecret(new DESKeySpec(Helper.buildBytesFromHexString("E60B80C7AEC78038")));
}
private static SecretKey getAESMultitasker() throws Exception {
return new SecretKeySpec(Helper.buildBytesFromHexString("3E7CFEF156E712906E1F603B59463C67"), "AES");
}
private static SecretKey getAESCBCMultitasker() throws Exception {
return new SecretKeySpec(Helper.buildBytesFromHexString("2DB7354A48F1CA7B48ACA247540FC923"), "AES");
}
private static IvParameterSpec getIvSpec() {
byte[] b = new byte[] {
(byte) -26, (byte) 124, (byte) -99, (byte) 32,
(byte) -37, (byte) -58, (byte) -93, (byte) 100,
(byte) 126, (byte) -55, (byte) -21, (byte) 48,
(byte) -86, (byte) 97, (byte) 12, (byte) 113};
return new IvParameterSpec(b);
}
}
}