Skip to content

Commit

Permalink
JCEEncryptor default encryption algorithm upgrade
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:
- Standalone conversion tool to re-encrypt passwords
- Extended unit test to verify backwards compatibility.
  • Loading branch information
rfelcman committed Dec 5, 2023
1 parent e2dde6b commit b3607a7
Show file tree
Hide file tree
Showing 14 changed files with 367 additions and 81 deletions.
1 change: 1 addition & 0 deletions antbuild.properties
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,7 @@ setenv-scripts=setenv.*
package-rename-scripts=packageRename.*
jaxb-compiler-scripts=jaxb-compiler.*
sdo-compiler-scripts=sdo-*.*
security-scripts=passwordUpdate.*

#Manifest Information
eclipselink.specification.title=Eclipse Persistence Services
Expand Down
4 changes: 4 additions & 0 deletions antbuild.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1699,6 +1699,10 @@
<zipfileset dir="${eclipselink.util.rename}" prefix="eclipselink/utils/rename" filemode="755">
<include name="${package-rename-scripts}"/>
</zipfileset>
<!-- password updater scripts -->
<zipfileset dir="${eclipselink.core.bin}" prefix="eclipselink/utils/security" filemode="755">
<include name="${security-scripts}"/>
</zipfileset>

<!-- jaxb-compiler scripts -->
<zipfileset dir="${eclipselink.moxy.bin}" includes="${jaxb-compiler-scripts}" prefix="eclipselink/bin" filemode="755"/>
Expand Down
1 change: 1 addition & 0 deletions etc/jenkins/pr_verify.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ spec:
steps {
container('el-build') {
sh """
export bind_address=0.0.0.0
/opt/bin/mysql-start.sh
mkdir $HOME/extension.lib.external
wget -nc https://repo1.maven.org/maven2/junit/junit/4.12/junit-4.12.jar -O $HOME/extension.lib.external/junit-4.12.jar
Expand Down
1 change: 1 addition & 0 deletions features/bundles/eclipselink/src/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,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
47 changes: 47 additions & 0 deletions foundation/bin/passwordUpdate.cmd
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
28 changes: 28 additions & 0 deletions foundation/bin/passwordUpdate.sh
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, 2018 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.internal.sessions.AbstractSession;
import org.junit.Assert;
import org.junit.Test;

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

/**
* Test the decryption of a String encrypted with DES ECB.
* @throws Exception
*/
@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));

Securable securable = new JCEEncryptor();
String decryptedString = securable.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 CBC.
* @throws Exception
*/
@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));


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

/**
* Test the decryption of a String encrypted with AES ECB.
* @throws Exception
*/
@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);
Assert.assertEquals("Strings should match.", plainTextString, decryptedString);
}


@Test
public void testStringDecryption_AES_ECB_withSessionName() throws Exception {
String plainTextString = "welcome123_aes_ecb";

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

JCEEncryptor jceEncryptor = new JCEEncryptor();
jceEncryptor.setSessionName("/file:/testdir/_test-jpa-pu");
String decryptedString = jceEncryptor.decryptPassword(testString);
Assert.assertEquals("Strings should match.", plainTextString, decryptedString);
}

/**
* Test the decryption/processing of a plaintext String.
* @throws Exception
*/
@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.
* @throws Exception
*/
@Test
public void testNullParameterDecryption() throws Exception {
Securable securable = new JCEEncryptor();
String returnValue = securable.decryptPassword(null);
Assert.assertNull("Null should be returned when decrypting a null value", returnValue);
}

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

/*
* 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 @@ -143,17 +177,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 @@ -163,5 +211,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 @@ -492,7 +492,16 @@ 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", "corrupt object referenced through mapping: {0}" },
{ "corrupt_object", "corrupt object: {0}" }
{ "corrupt_object", "corrupt object: {0}" },

{ "encryptor_decrypt_old_algorithm", "Database password used in {0} was encrypted by deprecated algorithm." +
"\nIt is recommended to re-encrypt it by `passwordUpdate.sh` from eclipselink.zip bundle."},
{ "encryptor_decrypt_old_algorithm_without_session_name", "Database password was encrypted by deprecated algorithm." +
"\nIt is recommended to re-encrypt it by `passwordUpdate.sh` from eclipselink.zip bundle."},
{ "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 b3607a7

Please sign in to comment.