Nowadays, with DevOps and containers approaches, you will often see components or software that try to go on a diet, to reduce the size needed to deploy them and therefore the images/containers associated to it. I was recently asked to do something similar on a very specific feature that the Documentum DFC jar files provide: extract and minimize the jar file(s) needed for the encryption of a BOF password. In this blog, I will therefore go through the steps I took to achieve this.

As you might know, Documentum DFC jar files provide a lot of capabilities, including encryption and decryption of passwords, as long as you know which class needs to be called for that. As mentioned, I was recently asked to strip down the needed jar files to only allow encryption of BOF passwords and nothing more than what is strictly necessary for it. Since the encryption and decryption are using two different classes, it also means that this new jar file will not be able to decrypt passwords, only encrypt them. Of course, it might technically be possible to decompile Documentum java classes and create your custom class using the (decompiled) source code from OpenText but let me remind you that it’s a proprietary software so that’s not something I will risk myself to do…

I worked on a Documentum 20.2 environment, but I assume the outcome would be very similar on other versions. The approach I used is basically a die and retry one: I know which class is being used to encrypt BOF passwords (“com.documentum.fc.tools.RegistryPasswordUtils“) and I know this is inside the dfc.jar file. Therefore, I can start from there and try to only use this class file to encrypt a password. This will most likely fail a few times, complaining about “NoClassDefFoundError“, which means that there are dependencies that are required to include into our custom jar file to be able to encrypt passwords. Then simply repeat this process until you are successfully able to get an encrypted password (that you can decrypt using the default dfc.jar and verify that it’s indeed a correctly encrypted password). These dependencies might not be necessarily needed for the encryption itself, but as mentioned, since we don’t want to decompile the OpenText class files, we have no other choice than to just include any and all classes that have direct or indirect references/methods being called, starting from the central point (RegistryPasswordUtils.class).

In short, I started doing something like the following (I’m using a sub-folder for the encryption classpath to make sure it’s not using the local folder jar files):

[[email protected] enc]$ workspace="./workspace"
[[email protected] enc]$ classpath="${workspace}/*"
[[email protected] enc]$ mkdir ${workspace}
[[email protected] enc]$
[[email protected] enc]$ ls -l
total 15548
-rw-r----- 1 tomcat tomcat 15913953 Jul 17 13:45 dfc.jar
drwxr-x--- 2 tomcat tomcat     4096 Jul 17 13:46 workspace
[[email protected] enc]$
[[email protected] enc]$ jar -tvf dfc.jar | grep "com/documentum/fc/tools/RegistryPasswordUtils"
  7646 Tue Mar 08 19:53:12 UTC 2022 com/documentum/fc/tools/RegistryPasswordUtils.class
[[email protected] enc]$
[[email protected] enc]$ jar -xf dfc.jar com/documentum/fc/tools/RegistryPasswordUtils.class
[[email protected] enc]$
[[email protected] enc]$ ls -l
total 15552
drwxr-x--- 3 tomcat tomcat     4096 Jul 17 13:47 com
-rw-r----- 1 tomcat tomcat 15913953 Jul 17 13:45 dfc.jar
drwxr-x--- 2 tomcat tomcat     4096 Jul 17 13:46 workspace
[[email protected] enc]$
[[email protected] enc]$ tree com
com
└── documentum
    └── fc
        └── tools
            └── RegistryPasswordUtils.class

3 directories, 1 file
[[email protected] enc]$
[[email protected] enc]$ echo ${classpath}
./workspace/*
[[email protected] enc]$
[[email protected] enc]$ jar -cf ${workspace}/encrypt.jar com
[[email protected] enc]$
[[email protected] enc]$ echo ${classpath}
./workspace/encrypt.jar
[[email protected] enc]$
[[email protected] enc]$ java -classpath "${classpath}" com.documentum.fc.tools.RegistryPasswordUtils "T3stP4ssw0rd"
Error: Unable to initialize main class com.documentum.fc.tools.RegistryPasswordUtils
Caused by: java.lang.NoClassDefFoundError: com/documentum/fc/common/DfException
[[email protected] enc]$

As you can see above, the “NoClassDefFoundError” is for another class (DfException.class), so then I simply continued from there on, finding this class, adding it into the “encrypt.jar” file and trying again:

[[email protected] enc]$ jar -tvf dfc.jar | grep "com/documentum/fc/common/DfException"
 19265 Tue Mar 08 19:53:08 UTC 2022 com/documentum/fc/common/DfException.class
[[email protected] enc]$
[[email protected] enc]$ jar -xf dfc.jar com/documentum/fc/common/DfException.class
[[email protected] enc]$
[[email protected] enc]$ jar -cf ${workspace}/encrypt.jar com
[[email protected] enc]$
[[email protected] enc]$ java -classpath "${classpath}" com.documentum.fc.tools.RegistryPasswordUtils "T3stP4ssw0rd"
Error: Unable to initialize main class com.documentum.fc.tools.RegistryPasswordUtils
Caused by: java.lang.NoClassDefFoundError: com/documentum/fc/common/IDfException
[[email protected] enc]$
[[email protected] enc]$
[[email protected] enc]$
[[email protected] enc]$ jar -tvf dfc.jar | grep "com/documentum/fc/common/IDfException"
  8453 Tue Mar 08 19:53:16 UTC 2022 com/documentum/fc/common/IDfException.class
[[email protected] enc]$
[[email protected] enc]$ jar -xf dfc.jar com/documentum/fc/common/IDfException.class
[[email protected] enc]$
[[email protected] enc]$ jar -cf ${workspace}/encrypt.jar com
[[email protected] enc]$
[[email protected] enc]$ java -classpath "${classpath}" com.documentum.fc.tools.RegistryPasswordUtils "T3stP4ssw0rd"
Error: Unable to initialize main class com.documentum.fc.tools.RegistryPasswordUtils
Caused by: java.lang.NoClassDefFoundError: org/aspectj/lang/Signature
[[email protected] enc]$

I guess you got the gist of it. As you can see, this last error is caused by a class (Signature.class) that doesn’t seem to belong to a Documentum package but instead to the “org.aspectj” one. There is actually a second jar file that is required to continue and that is the aspectjrt.jar. A big part of the classes that we will need to include to encrypt Documentum passwords (again, because of these dependencies required since we don’t want to touch the OpenText class files) are coming from this second jar.

I went through to the end of it, and I got a list of classes required for the dfc.jar and the aspectjrt.jar (and their sub-classes, that’s why there are wildcards “*” below). I cleaned up everything and did it again from scratch to make sure I didn’t have any mistake in the steps:

[[email protected] enc]$ workspace="./workspace"
[[email protected] enc]$ classpath="${workspace}/*"
[[email protected] enc]$ mkdir ${workspace}
[[email protected] enc]$
[[email protected] enc]$ ls -l
total 15664
-rw-r----- 1 tomcat tomcat   118762 Jul 17 14:07 aspectjrt.jar
-rw-r----- 1 tomcat tomcat 15913953 Jul 17 13:45 dfc.jar
drwxr-x--- 2 tomcat tomcat     4096 Jul 17 14:08 workspace
[[email protected] enc]$
[[email protected] enc]$ jar -xf dfc.jar com/
[[email protected] enc]$ jar -xf aspectjrt.jar org/
[[email protected] enc]$
[[email protected] enc]$ du -sh *
116K    aspectjrt.jar
56M     com
16M     dfc.jar
4.0K    workspace
660K    org
[[email protected] enc]$
[[email protected] enc]$ echo 'com/documentum/com/IDfClientX.class
com/documentum/fc/client/DfServiceInstantiationException.class
com/documentum/fc/client/DfServiceException.class
com/documentum/fc/client/DfTypedObject*.class
com/documentum/fc/client/IDfSession*.class
com/documentum/fc/client/IDfTypedObject.class
com/documentum/fc/client/IDfTypedObjectInternal.class
com/documentum/fc/client/IDfGlobalModuleRegistry.class
com/documentum/fc/client/IDfModuleRegistry.class
com/documentum/fc/client/impl/bof/classmgmt/IClassLoader.class
com/documentum/fc/client/impl/bof/classmgmt/IModuleManager.class
com/documentum/fc/client/impl/bof/classmgmt/ModuleManager*.class
com/documentum/fc/client/impl/bof/classmgmt/URLClassLoaderEx.class
com/documentum/fc/client/impl/bof/registry/IModuleMetadata.class
com/documentum/fc/client/impl/ITypedObject.class
com/documentum/fc/client/internal/IShutdownListener.class
com/documentum/fc/client/internal/ITypedObjectInternal.class
com/documentum/fc/common/DfException.class
com/documentum/fc/common/DfObject.class
com/documentum/fc/common/DfPreferences*.class
com/documentum/fc/common/DfRuntimeException.class
com/documentum/fc/common/IDfLoginInfo.class
com/documentum/fc/common/IDfException.class
com/documentum/fc/common/impl/preferences/IPreferencesObserver.class
com/documentum/fc/common/impl/preferences/TypedPreferences*.class
com/documentum/fc/impl/util/PBEUtils.class
com/documentum/fc/tools/RegistryPasswordUtils.class
com/documentum/fc/tracing/impl/aspects/BaseTracingAspect.class
com/documentum/fc/tracing/impl/Tracing*.class
com/documentum/fc/tracing/IUserIdentifyingObject.class
com/documentum/operations/common/DfBase64Encoder.class
com/documentum/operations/common/DfBase64FormatException.class' > list_dfc.txt
[[email protected] enc]$
[[email protected] enc]$ while read line; do
  for file in $(ls ${line}); do
    dest_folder="${workspace}/$(dirname ${file})"
    mkdir -p "${dest_folder}"
    cp "${file}" "${dest_folder}"
  done
done < <(cat list_dfc.txt)
[[email protected] enc]$
[[email protected] enc]$ echo 'org/aspectj/lang/JoinPoint*
org/aspectj/lang/reflect/AdviceSignature.class
org/aspectj/lang/reflect/CatchClauseSignature.class
org/aspectj/lang/reflect/CodeSignature.class
org/aspectj/lang/reflect/ConstructorSignature.class
org/aspectj/lang/reflect/FieldSignature.class
org/aspectj/lang/reflect/InitializerSignature.class
org/aspectj/lang/reflect/LockSignature.class
org/aspectj/lang/reflect/MemberSignature.class
org/aspectj/lang/reflect/MethodSignature.class
org/aspectj/lang/reflect/SourceLocation.class
org/aspectj/lang/reflect/UnlockSignature.class
org/aspectj/lang/Signature.class
org/aspectj/runtime/reflect/AdviceSignatureImpl.class
org/aspectj/runtime/reflect/CatchClauseSignatureImpl.class
org/aspectj/runtime/reflect/CodeSignatureImpl.class
org/aspectj/runtime/reflect/ConstructorSignatureImpl.class
org/aspectj/runtime/reflect/Factory.class
org/aspectj/runtime/reflect/FieldSignatureImpl.class
org/aspectj/runtime/reflect/InitializerSignatureImpl.class
org/aspectj/runtime/reflect/JoinPointImpl*
org/aspectj/runtime/reflect/LockSignatureImpl.class
org/aspectj/runtime/reflect/MemberSignatureImpl.class
org/aspectj/runtime/reflect/MethodSignatureImpl.class
org/aspectj/runtime/reflect/SignatureImpl*.class
org/aspectj/runtime/reflect/SourceLocationImpl.class
org/aspectj/runtime/reflect/UnlockSignatureImpl.class' > list_aspectjrt.txt
[[email protected] enc]$
[[email protected] enc]$ while read line; do
  for file in $(ls ${line}); do
    dest_folder="${workspace}/$(dirname ${file})"
    mkdir -p "${dest_folder}"
    cp "${file}" "${dest_folder}"
  done
done < <(cat list_aspectjrt.txt)
[[email protected] enc]$
[[email protected] enc]$ du -sh *
116K    aspectjrt.jar
56M     com
16M     dfc.jar
1.4M    workspace
4.0K    list_aspectjrt.txt
4.0K    list_dfc.txt
660K    org
[[email protected] enc]$
[[email protected] enc]$ cd ${workspace}/
[[email protected] workspace]$
[[email protected] workspace]$ du -sh *
1.2M    com
176K    org
[[email protected] workspace]$
[[email protected] workspace]$ jar -cf encrypt.jar com org
[[email protected] workspace]$
[[email protected] workspace]$ rm -rf com/ org/
[[email protected] workspace]$
[[email protected] workspace]$ ls -l
total 324
-rw-r----- 1 tomcat tomcat 328470 Jul 17 14:11 encrypt.jar
[[email protected] workspace]$
[[email protected] workspace]$ java -classpath "./encrypt.jar" com.documentum.fc.tools.RegistryPasswordUtils "T3stP4ssw0rd"
AAAAEGSo3bu4EisUf3nIQkN0geKBTCWJePigsKNqozw+XVIz
[[email protected] workspace]$

And voila, we have an encrypted password. To validate that it’s properly done, you can try to decrypt it. I won’t put in this blog the command to be used to decrypt passwords because I don’t really think that’s something that should be public, but if you really want to know, all I can say is that if you are looking on official resources provided by Documentum, you will probably find what you are looking for… In any cases, the decryption is working properly using the default dfc.jar (it doesn’t need aspectjrt.jar to decrypt) but it’s of course not working for our newly created encrypt.jar:

[[email protected] workspace]$ java -classpath "./encrypt.jar" ***something*** AAAAEGSo3bu4EisUf3nIQkN0geKBTCWJePigsKNqozw+XVIz
Error: Could not find or load main class ***something***
Caused by: java.lang.ClassNotFoundException: ***something***
[[email protected] workspace]$
[[email protected] workspace]$ cd ..
[[email protected] enc]$
[[email protected] enc]$ java -classpath "./dfc.jar" ***something*** AAAAEGSo3bu4EisUf3nIQkN0geKBTCWJePigsKNqozw+XVIz
The decrypted password is: T3stP4ssw0rd
[[email protected] enc]$

As you can see, it’s the same password that we had initially, so the encryption works properly. Now the main purpose of this activity was to decrease the size of the jar file needed to encrypt password, so what’s the status there? The default “com” (from dfc.jar) and “org” (from aspectjrt.jar) folders are roughly 56Mb, while the minimal ones that we are using to create the encrypt.jar file are only 1.2Mb! To be able to encrypt passwords, you would need normally both the dfc.jar as well as the aspectjrt.jar, for a total size of 16032715 bytes (~15.3Mb). On the other hand, the encrypt.jar file that we just created is only 328475 bytes (~0.31Mb, i.e., 48.8 times smaller) so that’s good. It would obviously be possible to add the decrypt capability to our encrypt.jar but the goal here was to only be able to encrypt passwords, so that you can use this jar file anywhere to quickly encrypt a password to use right away.


Thumbnail [60x60]
by
Morgan Patou