Skip to content

Commit

Permalink
JCEEncryptor default encryption algorithm upgrade (eclipse-ee4j#2004)
Browse files Browse the repository at this point in the history
JCEEncryptor default encryption algorithm upgrade from AES/CBC/PKCS5Padding to AES/GCM/NoPadding .
Plus extended unit test.
- for AES/GCM/NoPadding random initialization vector (IV) instead of static one.
- shell scripts added, resource strings moved to localization bundle
DBWS builder test fix

Signed-off-by: Radek Felcman <[email protected]>
  • Loading branch information
rfelcman authored Dec 1, 2023
1 parent 7b3c2cb commit 149e9ce
Show file tree
Hide file tree
Showing 11 changed files with 428 additions and 120 deletions.
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

0 comments on commit 149e9ce

Please sign in to comment.