From 1bda529e3cf685d5108832ecac7f433c85acb6fd Mon Sep 17 00:00:00 2001
From: Valery Kharseko <vharseko@3a-systems.ru>
Date: Thu, 06 Aug 2026 11:31:31 +0000
Subject: [PATCH] Remove global digestLock serialization in digest password storage schemes (#667)

---
 opendj-server-legacy/src/main/java/org/opends/server/util/Crypt.java |   33 ++++++++++++++++++---------------
 1 files changed, 18 insertions(+), 15 deletions(-)

diff --git a/opendj-server-legacy/src/main/java/org/opends/server/util/Crypt.java b/opendj-server-legacy/src/main/java/org/opends/server/util/Crypt.java
index 1391b2e..078f849 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/util/Crypt.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/util/Crypt.java
@@ -13,6 +13,7 @@
  *
  * Copyright 2008 Sun Microsystems, Inc.
  * Portions Copyright 2015 ForgeRock AS.
+ * Portions Copyright 2026 3A Systems, LLC
  */
 /*
  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
@@ -136,18 +137,26 @@
     int _iobuf[]  = new int[16];
   }
 
-  private final SubCrypt _crypt;
+  /**
+   * The working state of the algorithm. setkey(), encrypt() and _crypt() all
+   * scribble on these buffers (and _crypt() returns a reference to _iobuf),
+   * so a per-thread instance is used instead of a shared instance guarded by
+   * a lock: encrypting under a global lock serializes all concurrent {CRYPT}
+   * password operations.
+   */
+  private final ThreadLocal<SubCrypt> _crypt = ThreadLocal.withInitial(() -> {
+    SubCrypt c = new SubCrypt();
+    copy(e, c._E);
+    return c;
+  });
 
   /**
    * Constructor.
    */
   public Crypt() {
-    _crypt = new SubCrypt();
-
-    copy(e, _crypt._E);
   }
 
-  private void copy(byte[] src, int[] dest) {
+  private static void copy(byte[] src, int[] dest) {
     for (int i = 0; i < dest.length; i++) {
       dest[i] = src[i];
     }
@@ -158,7 +167,7 @@
    */
   private void setkey(int[] key)
   {
-    SubCrypt _c = _crypt;
+    SubCrypt _c = _crypt.get();
 
     /*
      * if (_c == null) { _cryptinit(); _c = __crypt; }
@@ -270,7 +279,7 @@
    */
   private final void encrypt(int block[], int edflag)
   {
-    SubCrypt _c = _crypt;
+    SubCrypt _c = _crypt.get();
 
     /*
      * First, permute the bits in the input
@@ -369,8 +378,6 @@
     }
   }
 
-  private Object digestLock = new Object();
-
   /**
    * Encode the supplied password in unix crypt form with the provided
    * salt.
@@ -382,11 +389,7 @@
    */
   public byte[] crypt(byte[] pw, byte[] salt)
   {
-    int[] r;
-    synchronized (digestLock)
-    {
-      r = _crypt(pw, salt);
-    }
+    int[] r = _crypt(pw, salt);
 
     //TODO: crypt always returns same size array?  So don't mess
     // around calculating the number of zeros at the end.
@@ -416,7 +419,7 @@
 
   private int[] _crypt(byte[] pw, byte[] salt)
   {
-    SubCrypt _c = _crypt;
+    SubCrypt _c = _crypt.get();
 
     Arrays.fill(_c._ablock, 0);
 

--
Gitblit v1.10.0