Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[master] JCEEncryptor default encryption algorithm upgrade #2004

Merged
merged 10 commits into from
Dec 1, 2023
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
@REM
@REM Copyright (c) 2023 Oracle and/or its affiliates. All rights reserved.
@REM
@REM This program and the accompanying materials are made available under the
@REM terms of the Eclipse Public License v. 2.0 which is available at
@REM http://www.eclipse.org/legal/epl-2.0,
@REM or the Eclipse Distribution License v. 1.0 which is available at
@REM http://www.eclipse.org/org/documents/edl-v10.php.
@REM
@REM SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
@REM

@REM Usage is `passwordUpdate.sh|.cmd -ip <old encrypted password>`
@REM This application internally decrypt old encrypted password used by some previous version EclipseLink and encrypt it by latest algorithm.

@echo off
setlocal
call "%~dp0../../bin/setenv.cmd"

@REM User may increase Java memory setting(s) if desired:
set JVM_ARGS=-Xmx256m

REM Please do not change any of the following lines:
set _FIXPATH=
call :fixpath "%~dp0"
set THIS=%_FIXPATH:~1%

set CLASSPATH=%CLASSPATH%;%THIS%..\..\jlib\eclipselink.jar

set PASSWORD_UPDATE_ARGS=%*

%JAVA_HOME%\bin\java.exe %JVM_ARGS% -cp %CLASSPATH% org.eclipse.persistence.tools.security.JCEEncryptorCmd %PASSWORD_UPDATE_ARGS%

endlocal
goto :EOF

:fixpath
if not %1.==. (
for /f "tokens=1* delims=;" %%a in (%1) do (
call :shortfilename "%%a" & call :fixpath "%%b"
)
)
goto :EOF

:shortfilename
for %%i in (%1) do set _FIXPATH=%_FIXPATH%;%%~fsi
goto :EOF
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/bin/sh
#
# Copyright (c) 2023 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
#

#Usage is `passwordUpdate.sh|.cmd -ip <old encrypted password>`
#This application internally decrypt old encrypted password used by some previous version EclipseLink and encrypt it by latest algorithm.

. `dirname $0`/../../bin/setenv.sh

# User may increase Java memory setting(s) if desired:
JVM_ARGS=-Xmx256m

# Please do not change any of the following lines:
CLASSPATH=`dirname $0`/../../jlib/eclipselink.jar:

PASSWORD_UPDATE_ARGS="$@"

${JAVA_HOME}/bin/java ${JVM_ARGS} -cp ${CLASSPATH} \
org.eclipse.persistence.tools.security.JCEEncryptorCmd ${PASSWORD_UPDATE_ARGS}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2023 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
Expand All @@ -21,12 +21,14 @@
import javax.crypto.CipherOutputStream;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import org.eclipse.persistence.exceptions.ValidationException;
import org.eclipse.persistence.internal.helper.Helper;
import org.eclipse.persistence.internal.security.JCEEncryptor;
import org.eclipse.persistence.internal.security.Securable;
import org.eclipse.persistence.tools.security.JCEEncryptorCmd;
import org.junit.Assert;
import org.junit.Test;

Expand All @@ -35,64 +37,106 @@
* @author dminsky
*/
public class SecurableBackwardsCompatibilityTest {

/**
* Test the decryption of a String encrypted with DES ECB.
*/
@Test
public void testStringDecryption_DES_ECB() throws Exception {
String plainTextString = "welcome123_des_ecb";

String testString = encryptString_DES_ECB(plainTextString);
Assert.assertFalse("Strings should not match.", plainTextString.equals(testString));


JCEEncryptorCmd jceEncryptorCmd = new JCEEncryptorCmd();
String decryptedString = jceEncryptorCmd.decryptPassword(testString);
Assert.assertEquals("Strings should match.", plainTextString, decryptedString);
}

/**
* Test the decryption of a String encrypted with AES GCM.
*/
@Test
public void testStringDecryption_AES_GCM() throws Exception {
String plainTextString = "welcome123_aes_gcm";

Securable securable = new JCEEncryptor();
String testString = securable.encryptPassword(plainTextString);
Assert.assertFalse("Strings should not match.", plainTextString.equals(testString));

String decryptedString = securable.decryptPassword(testString);
Assert.assertEquals("Strings should match.", plainTextString, decryptedString);
}


/**
* Test the decryption of a String encrypted with AES GCM via JCEEncryptorCmd.
*/
@Test
public void testStringDecryption_AES_GCM_via_jceEncryptorCmd() throws Exception {
String plainTextString = "welcome123_aes_gcm";

Securable securable = new JCEEncryptor();
String testString = securable.encryptPassword(plainTextString);
Assert.assertFalse("Strings should not match.", plainTextString.equals(testString));

JCEEncryptorCmd jceEncryptorCmd = new JCEEncryptorCmd();
String decryptedString = jceEncryptorCmd.decryptPassword(testString);

Assert.assertEquals("Strings should match.", plainTextString, decryptedString);
}

/**
* Test the decryption of a String encrypted with AES CBC.
*/
@Test
public void testStringDecryption_AES_CBC() throws Exception {
String plainTextString = "welcome123_aes_cbc";

Securable securable = new JCEEncryptor();
String testString = securable.encryptPassword(plainTextString);
String testString = encryptString_AES_CBC(plainTextString);
Assert.assertFalse("Strings should not match.", plainTextString.equals(testString));

String decryptedString = securable.decryptPassword(testString);

JCEEncryptorCmd jceEncryptorCmd = new JCEEncryptorCmd();
String decryptedString = jceEncryptorCmd.decryptPassword(testString);
Assert.assertEquals("Strings should match.", plainTextString, decryptedString);
}

/**
* Test the decryption of a String encrypted with AES ECB.
*/
@Test
public void testStringDecryption_AES_ECB() throws Exception {
String plainTextString = "welcome123_aes_ecb";

String testString = encryptString_AES_ECB(plainTextString);
Assert.assertFalse("Strings should not match.", plainTextString.equals(testString));
Securable securable = new JCEEncryptor();
String decryptedString = securable.decryptPassword(testString);

JCEEncryptorCmd jceEncryptorCmd = new JCEEncryptorCmd();
String decryptedString = jceEncryptorCmd.decryptPassword(testString);
Assert.assertEquals("Strings should match.", plainTextString, decryptedString);
}

/**
* Test the decryption/processing of a plaintext String.
*/
@Test
public void testStringDecryption_PlainText() throws Exception {
String plainTextString = "welcome123_plaintext";

Securable securable = new JCEEncryptor();
String decryptedString = securable.decryptPassword(plainTextString);
Assert.assertEquals("Passwords should match.", plainTextString, decryptedString);
}


/**
* Test the decryption/processing of an empty String "".
*/
@Test
public void testEmptyStringParameterDecryption() throws Exception {
Securable securable = new JCEEncryptor();
String returnValue = securable.decryptPassword("");
Assert.assertEquals("Empty string \"\" should be returned when decrypting a \"\" (empty string) value", "", returnValue);
}

/**
* Test the decryption/processing of a null parameter.
*/
Expand All @@ -102,7 +146,7 @@ public void testNullParameterDecryption() throws Exception {
String returnValue = securable.decryptPassword(null);
Assert.assertNull("Null should be returned when decrypting a null value", returnValue);
}

/**
* Test the encryption of a null parameter.
*/
Expand All @@ -117,17 +161,36 @@ public void testNullParameterEncryption() throws Exception {
}
Assert.assertNotNull("A ValidationException should be thrown when encrypting a null value", expectedException);
}


/**
* Test the decryption of a String encrypted with AES ECB and let JCEEncryptor throw Exception
*/
@Test
public void testStringDecryptionDeprecatedAlgorithmWithException() throws Exception {
ValidationException expectedException = ValidationException.errorDecryptingPasswordOldAlgorithm(null);
String plainTextString = "welcome123_aes_ecb";

String testString = encryptString_AES_ECB(plainTextString);
Assert.assertFalse("Strings should not match.", plainTextString.equals(testString));

Securable securable = new JCEEncryptor();
try {
String decryptedString = securable.decryptPassword(testString);
} catch (Exception e) {
Assert.assertTrue(e.getMessage().contains(expectedException.getMessage()));
}
}

/*
* Internal test utility:
* Return a DES ECB encrypted version of the String parameter, using the legacy encryption code.
*/
private String encryptString_DES_ECB(String aString) throws Exception {
final byte[] bytes = Helper.buildBytesFromHexString("E60B80C7AEC78038");

Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, SecretKeyFactory.getInstance("DES").generateSecret(new DESKeySpec(bytes)));

ByteArrayOutputStream baos = new ByteArrayOutputStream();
CipherOutputStream cos = new CipherOutputStream(baos, cipher);
ObjectOutputStream oos = new ObjectOutputStream(cos);
Expand All @@ -137,17 +200,31 @@ private String encryptString_DES_ECB(String aString) throws Exception {

return Helper.buildHexStringFromBytes(baos.toByteArray());
}


/*
* Internal test utility:
* Return an AES CBC encrypted version of the String parameter, using the legacy encryption code.
*/
private String encryptString_AES_CBC(String aString) throws Exception {
final byte[] bytes = Helper.buildBytesFromHexString("2DB7354A48F1CA7B48ACA247540FC923");

Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
IvParameterSpec iv = getIvSpec();
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(bytes, "AES"), iv);

return Helper.buildHexStringFromBytes(cipher.doFinal(aString.getBytes("UTF-8")));
}

/*
* Internal test utility:
* Return an AES ECB encrypted version of the String parameter, using the legacy encryption code.
*/
private String encryptString_AES_ECB(String aString) throws Exception {
final byte[] bytes = Helper.buildBytesFromHexString("3E7CFEF156E712906E1F603B59463C67");

Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(bytes, "AES"));

ByteArrayOutputStream baos = new ByteArrayOutputStream();
CipherOutputStream cos = new CipherOutputStream(baos, cipher);
ObjectOutputStream oos = new ObjectOutputStream(cos);
Expand All @@ -157,5 +234,13 @@ private String encryptString_AES_ECB(String aString) throws Exception {

return Helper.buildHexStringFromBytes(baos.toByteArray());
}


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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@
exports org.eclipse.persistence.platform.server.wls;
exports org.eclipse.persistence.platform.xml;
exports org.eclipse.persistence.queries;
exports org.eclipse.persistence.security;
exports org.eclipse.persistence.sequencing;
exports org.eclipse.persistence.services;
exports org.eclipse.persistence.services.glassfish;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ public class ValidationException extends EclipseLinkException {
public static final int ERROR_DECRYPTING_PASSWORD = 7107;
public static final int NOT_SUPPORTED_FOR_DATASOURCE = 7108;
public static final int PROJECT_LOGIN_IS_NULL = 7109;
public static final int ENCRYPTION_OLD_ALGORITHM = 7360;

// for flashback:
public static final int HISTORICAL_SESSION_ONLY_SUPPORTED_ON_ORACLE = 7110;
Expand Down Expand Up @@ -907,6 +908,13 @@ public static ValidationException errorDecryptingPassword(Exception exception) {
return validationException;
}

public static ValidationException errorDecryptingPasswordOldAlgorithm(Exception exception) {
Object[] args = { };
ValidationException validationException = new ValidationException(ExceptionMessageGenerator.buildMessage(ValidationException.class, ENCRYPTION_OLD_ALGORITHM, args), exception);
validationException.setErrorCode(ENCRYPTION_OLD_ALGORITHM);
return validationException;
}

public static ValidationException invalidEncryptionClass(String className, Throwable throwableError) {
Object[] args = { className };
ValidationException validationException = new ValidationException(ExceptionMessageGenerator.buildMessage(ValidationException.class, INVALID_ENCRYPTION_CLASS, args));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ public final class ValidationExceptionResource extends ListResourceBundle {
{ "7105", "Error encountered converting encrypting class: [{0}]" },
{ "7106", "Error encountered during string encryption." },
{ "7107", "Error encountered during string decryption." },
{ "7360", "Database password was encrypted by deprecated algorithm.\nIt's recommended to re-encrypt it by `passwordUpdate.sh` from eclipselink.zip bundle"},
{ "7108", "This operation is not supported for non-relational platforms." },
{ "7109", "The login in the project used to create the session is null, it must be a valid login." },
{ "7110", "At present HistoricalSession only works with Oracle 9R2 or later databases, as it uses Oracle''s Flashback feature." },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -481,7 +481,11 @@ public class LoggingLocalizationResource extends ListResourceBundle {
{ "validate_object_space", "validate object space." },
{ "stack_of_visited_objects_that_refer_to_the_corrupt_object", "stack of visited objects that refer to the corrupt object: {0}" },
{ "corrupt_object_referenced_through_mapping", "The following corrupt object is referenced through mapping: {0}" },
{ "corrupt_object", "corrupt object: {0}" }
{ "corrupt_object", "corrupt object: {0}" },

{ "encryptor_script_usage", "Usage is `passwordUpdate.sh|.cmd -ip <old encrypted password>`"},
{ "encryptor_script_description", "This application internally decrypt old encrypted password used by some previous version EclipseLink and encrypt it by latest algorithm."},
{ "encryptor_script_output", "Re-encrypted password is: {0}"}
};

/**
Expand Down
Loading
Loading