Commit 8152030a4 for imagemagick.org

commit 8152030a498f491ff8b70f4323a36d2a652acef6
Author: Cristy <urban-warrior@imagemagick.org>
Date:   Fri Oct 30 14:47:26 2026 -0400

    add mix to pixel and meta content

diff --git a/MagickCore/distribute-cache.c b/MagickCore/distribute-cache.c
index 547e4d2e6..3d66e8438 100644
--- a/MagickCore/distribute-cache.c
+++ b/MagickCore/distribute-cache.c
@@ -140,14 +140,11 @@ static WSADATA
 #endif

 #if defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
-static char
-  *dpc_shared_secret = (char *) NULL;
-
 static SemaphoreInfo
   *dpc_semaphore = (SemaphoreInfo *) NULL;

-static int
-  ComputeHMACSHA256Mac(const void *,size_t,const void *,size_t,unsigned char *,size_t);
+static char
+  *dpc_shared_secret = (char *) NULL;

 static size_t
   dpc_clients = 0,
@@ -306,53 +303,6 @@ static inline MagickOffsetType dpc_receive_deadline(SOCKET_TYPE file,
   }
   return(offset);
 }
-
-static inline int mac_compare(const unsigned char *a,const unsigned char *b,
-  const size_t length)
-{
-  size_t
-    i;
-
-  volatile unsigned char
-    difference = 0;
-
-  /*
-    Compare in time independent of where (or whether) the buffers differ.
-  */
-  for (i=0; i < length; i++)
-    difference|=(unsigned char) (a[i] ^ b[i]);
-  return(difference == 0 ? 0 : -1);
-}
-
-static inline MagickOffsetType dpc_receive_mac(SOCKET_TYPE file,
-  const MagickSizeType length,unsigned char *magick_restrict message,
-  uint64_t session_key)
-{
-  MagickOffsetType
-    count;
-
-  unsigned char
-    expected_mac[32],
-    received_mac[32];
-
-  /*
-    Read back the MAC from the wire and the message.
-  */
-  if (length > (MagickSizeType) MAGICK_SSIZE_MAX)
-    return(-1);
-  count=dpc_receive(file,sizeof(received_mac),received_mac);
-  if (count != (MagickOffsetType) sizeof(received_mac))
-    return(-1);
-  count=dpc_receive(file,length,message);
-  if (count != (MagickOffsetType) length)
-    return(count);
-  if (ComputeHMACSHA256Mac(&session_key,sizeof(session_key),message,(size_t) length,expected_mac,sizeof(expected_mac)) != 0)
-    return(-1);  /* HMAC computation failed */
-  if (mac_compare(received_mac,expected_mac,sizeof(expected_mac)) != 0)
-    return(-1);  /* HMAC verification failed */
-  return(count);
-}
-
 #endif

 #if defined(MAGICKCORE_HAVE_WINSOCK2)
@@ -741,7 +691,7 @@ MagickPrivate DistributeCacheInfo *AcquireDistributeCacheInfo(
 %
 %    o mac: the mac is computed and returned in this buffer.
 %
-%    o mac_length: the mac length in bytes;  mac must be at least this length.
+%    o mac_length: the mac length in bytes .  mac must be at least this length.
 %
 */

@@ -770,17 +720,14 @@ static void TransformSHA256Hash(SHA256Hash *sha256_hash,const unsigned char data

   static const uint32_t K[64] =
   {
-    0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,
-    0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
-    0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
-    0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
-    0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
-    0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
-    0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
-    0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
-    0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
-    0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
-    0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
+    0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+    0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+    0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+    0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+    0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+    0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+    0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+    0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
   };

   uint32_t
@@ -1052,31 +999,230 @@ static inline MagickOffsetType dpc_send(SOCKET_TYPE file,
 }
 #endif

+#define DPCMacLength  32
+#define DPCScratchExtent  16384  /* bytes; send-side encrypt buffer */
+
+static const char *GetDPCSharedSecret(void)
+{
+#if defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
+  /*
+    The server loads the secret at start-up; a client loads it on first use.
+  */
+  if (dpc_shared_secret == (char *) NULL)
+    {
+      if (dpc_semaphore == (SemaphoreInfo *) NULL)
+        ActivateSemaphoreInfo(&dpc_semaphore);
+      LockSemaphoreInfo(dpc_semaphore);
+      if (dpc_shared_secret == (char *) NULL)
+        dpc_shared_secret=GetPolicyValue("cache:shared-secret");
+      UnlockSemaphoreInfo(dpc_semaphore);
+    }
+  return(dpc_shared_secret);
+#else
+  return((const char *) NULL);
+#endif
+}
+
+static int DeriveDPCKey(const uint64_t session_key,const char label,
+  unsigned char key[DPCMacLength])
+{
+  const char
+    *shared_secret;
+
+  unsigned char
+    info[sizeof(session_key)+1];
+
+  /*
+    key = HMAC-SHA-256(shared secret, session key || label).  The session key
+    travels in the clear, so the shared secret is what keeps this private.
+  */
+  shared_secret=GetDPCSharedSecret();
+  if (shared_secret == (const char *) NULL)
+    return(-1);
+  (void) memcpy(info,&session_key,sizeof(session_key));
+  info[sizeof(session_key)]=(unsigned char) label;
+  return(ComputeHMACSHA256Mac(shared_secret,strlen(shared_secret),info,
+    sizeof(info),key,DPCMacLength));
+}
+
+static inline uint64_t LoadDPCWord(const unsigned char *p)
+{
+  return(((uint64_t) p[0]) | ((uint64_t) p[1] << 8) |
+    ((uint64_t) p[2] << 16) | ((uint64_t) p[3] << 24) |
+    ((uint64_t) p[4] << 32) | ((uint64_t) p[5] << 40) |
+    ((uint64_t) p[6] << 48) | ((uint64_t) p[7] << 56));
+}
+
+static void SplitMix64Keystream(const unsigned char *stream_key,
+  const unsigned char *mac,const MagickSizeType offset,unsigned char *data,
+  const size_t length)
+{
+  size_t
+    i;
+
+  uint64_t
+    block,
+    seed,
+    z;
+
+  /*
+    XOR data with the SplitMix64 keystream starting at byte 'offset'.
+  */
+  seed=LoadDPCWord(stream_key) ^ LoadDPCWord(mac);
+  block=(uint64_t) (offset >> 3);
+  z=0;
+  for (i=0; i < length; i++)
+  {
+    size_t
+      j = (size_t) ((offset+i) & 7);
+
+    if ((i == 0) || (j == 0))
+      {
+        block=(uint64_t) ((offset+i) >> 3);
+        z=seed+(block+1)*0x9e3779b97f4a7c15ULL;
+        z=(z ^ (z >> 30))*0xbf58476d1ce4e5b9ULL;
+        z=(z ^ (z >> 27))*0x94d049bb133111ebULL;
+        z^=z >> 31;
+      }
+    data[i]^=(unsigned char) (z >> (j*8));
+  }
+}
+
+static inline void WipeDPCKey(unsigned char *key,const size_t length)
+{
+  volatile unsigned char
+    *p = key;
+
+  size_t
+    i;
+
+  for (i=0; i < length; i++)
+    p[i]=0;
+}
+
+static inline int mac_compare(const unsigned char *a,const unsigned char *b,
+  const size_t length)
+{
+  size_t
+    i;
+
+  volatile unsigned char
+    difference = 0;
+
+  /*
+    Compare in time independent of where (or whether) the buffers differ.
+  */
+  for (i=0; i < length; i++)
+    difference|=(unsigned char) (a[i] ^ b[i]);
+  return(difference == 0 ? 0 : -1);
+}
+
 static inline MagickOffsetType dpc_send_mac(SOCKET_TYPE file,
   const MagickSizeType length,const void *magick_restrict message,
   uint64_t session_key)
 {
+  const unsigned char
+    *p = (const unsigned char *) message;
+
   MagickOffsetType
     status;

+  MagickSizeType
+    offset;
+
   unsigned char
-     mac[32];
+    mac[DPCMacLength],
+    mac_key[DPCMacLength],
+    scratch[DPCScratchExtent],
+    stream_key[DPCMacLength];

   /*
-    Compute HMAC-SHA-256 MAC of the message using the session key.
+    MAC the plaintext, then send MAC || (plaintext XOR keystream).
   */
   if (length > (MagickSizeType) MAGICK_SSIZE_MAX)
     return(-1);
-  if (ComputeHMACSHA256Mac(&session_key,sizeof(session_key),message,
-      (size_t) length,mac,sizeof(mac)) != 0)
-    return(-1);  /* HMAC computation failed */
-  /*
-    Push the MAC onto the wire then the actual message.
-  */
+  if ((DeriveDPCKey(session_key,'m',mac_key) != 0) ||
+      (DeriveDPCKey(session_key,'e',stream_key) != 0) ||
+      (ComputeHMACSHA256Mac(mac_key,sizeof(mac_key),message,(size_t) length,
+         mac,sizeof(mac)) != 0))
+    {
+      WipeDPCKey(mac_key,sizeof(mac_key));
+      WipeDPCKey(stream_key,sizeof(stream_key));
+      return(-1);  /* key derivation or HMAC computation failed */
+    }
+  WipeDPCKey(mac_key,sizeof(mac_key));
   status=dpc_send(file,sizeof(mac),mac);
   if (status != (MagickOffsetType) sizeof(mac))
+    {
+      WipeDPCKey(stream_key,sizeof(stream_key));
+      return(-1);
+    }
+  /*
+    Encrypt into a scratch buffer: the caller's buffer may be the live cache.
+  */
+  for (offset=0; offset < length; )
+  {
+    size_t
+      chunk = (size_t) MagickMin(length-offset,(MagickSizeType)
+        sizeof(scratch));
+
+    (void) memcpy(scratch,p+offset,chunk);
+    SplitMix64Keystream(stream_key,mac,offset,scratch,chunk);
+    status=dpc_send(file,(MagickSizeType) chunk,scratch);
+    if (status != (MagickOffsetType) chunk)
+      break;
+    offset+=(MagickSizeType) chunk;
+  }
+  WipeDPCKey(stream_key,sizeof(stream_key));
+  WipeDPCKey(scratch,sizeof(scratch));
+  if (offset != length)
+    return(-1);
+  return((MagickOffsetType) length);
+}
+
+static inline MagickOffsetType dpc_receive_mac(SOCKET_TYPE file,
+  const MagickSizeType length,unsigned char *magick_restrict message,
+  uint64_t session_key)
+{
+  MagickOffsetType
+    count;
+
+  unsigned char
+    expected_mac[DPCMacLength],
+    mac_key[DPCMacLength],
+    received_mac[DPCMacLength],
+    stream_key[DPCMacLength];
+
+  int
+    status;
+
+  /*
+    Read MAC || ciphertext, decrypt in place, then verify the MAC.
+  */
+  if (length > (MagickSizeType) MAGICK_SSIZE_MAX)
+    return(-1);
+  count=dpc_receive(file,sizeof(received_mac),received_mac);
+  if (count != (MagickOffsetType) sizeof(received_mac))
     return(-1);
-  return(dpc_send(file,length,message));
+  count=dpc_receive(file,length,message);
+  if (count != (MagickOffsetType) length)
+    return(count);
+  status=DeriveDPCKey(session_key,'e',stream_key);
+  if (status == 0)
+    {
+      SplitMix64Keystream(stream_key,received_mac,0,message,(size_t) length);
+      status=DeriveDPCKey(session_key,'m',mac_key);
+    }
+  if (status == 0)
+    status=ComputeHMACSHA256Mac(mac_key,sizeof(mac_key),message,
+      (size_t) length,expected_mac,sizeof(expected_mac));
+  WipeDPCKey(mac_key,sizeof(mac_key));
+  WipeDPCKey(stream_key,sizeof(stream_key));
+  if (status != 0)
+    return(-1);  /* key derivation or HMAC computation failed */
+  if (mac_compare(received_mac,expected_mac,sizeof(expected_mac)) != 0)
+    return(-1);  /* HMAC verification failed */
+  return(count);
 }

 #if !defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
@@ -2125,7 +2271,8 @@ MagickPrivate MagickOffsetType ReadDistributePixelCacheMetacontent(
   count=dpc_send(server_info->file,(MagickSizeType) (p-message),message);
   if (count != (MagickOffsetType) (p-message))
     return(-1);
-  return(dpc_receive_mac(server_info->file,length,metacontent,server_info->session_key));
+  return(dpc_receive_mac(server_info->file,length,metacontent,
+    server_info->session_key));
 }

 /*
@@ -2198,7 +2345,8 @@ MagickPrivate MagickOffsetType ReadDistributePixelCachePixels(
   count=dpc_send(server_info->file,(MagickSizeType) (p-message),message);
   if (count != (MagickOffsetType) (p-message))
     return(-1);
-  return(dpc_receive_mac(server_info->file,length,pixels,server_info->session_key));
+  return(dpc_receive_mac(server_info->file,length,pixels,
+    server_info->session_key));
 }

 /*
@@ -2327,7 +2475,8 @@ MagickPrivate MagickOffsetType WriteDistributePixelCacheMetacontent(
   count=dpc_send(server_info->file,(MagickSizeType) (p-message),message);
   if (count != (MagickOffsetType) (p-message))
     return(-1);
-  return(dpc_send_mac(server_info->file,length,metacontent,server_info->session_key));
+  return(dpc_send_mac(server_info->file,length,metacontent,
+    server_info->session_key));
 }

 /*
@@ -2401,5 +2550,6 @@ MagickPrivate MagickOffsetType WriteDistributePixelCachePixels(
   count=dpc_send(server_info->file,(MagickSizeType) (p-message),message);
   if (count != (MagickOffsetType) (p-message))
     return(-1);
-  return(dpc_send_mac(server_info->file,length,pixels,server_info->session_key));
+  return(dpc_send_mac(server_info->file,length,pixels,
+    server_info->session_key));
 }
diff --git a/coders/psd.c b/coders/psd.c
index 6b991a617..2b0ea6c4c 100644
--- a/coders/psd.c
+++ b/coders/psd.c
@@ -805,11 +805,12 @@ static StringInfo *ParseImageResourceBlocks(PSDInfo *psd_info,Image *image,
       break;
     p=PushLongPixel(MSBEndian,p,&count);
     offset=(ssize_t) count;
-    if ((offset <= 0) || ((p+offset) > (blocks+length)) ||
+    if ((offset < 0) || ((p+offset) > (blocks+length)) ||
         (((size_t) (p-blocks)+(size_t) offset) > (size_t) length))
       {
-        (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError,
-          "Invalid PSD resource block offset","`%s'",image->filename);
+        (void) ThrowMagickException(exception,GetMagickModule(),
+          CorruptImageError,"Invalid PSD resource block offset","`%s'",
+          image->filename);
         profile=DestroyStringInfo(profile);
         break;
       }