Commit 4d3783d91 for imagemagick.org
commit 4d3783d91b992c6392a54b85273f1f46816173d4
Author: Cristy <urban-warrior@imagemagick.org>
Date: Sat Nov 14 22:14:40 2026 -0500
protect against XOR plaintext recovery
diff --git a/MagickCore/cipher.c b/MagickCore/cipher.c
index 3229bb960..4aacdf70d 100644
--- a/MagickCore/cipher.c
+++ b/MagickCore/cipher.c
@@ -13,7 +13,6 @@
% %
% Software Design %
% Cristy %
-% March 2003 %
% %
% %
% Copyright @ 1999 ImageMagick Studio LLC, a non-profit organization %
@@ -344,9 +343,6 @@ static void FinalizeRoundKey(const unsigned int *ciphertext,
for (j=0; j < 4; j++)
*p++=(unsigned char) ((value >> (8*j)) & 0xff);
}
- /*
- Reset registers.
- */
value=0;
}
@@ -371,9 +367,6 @@ static void InitializeRoundKey(const unsigned char *ciphertext,
value|=((unsigned int) *p++ << (8*j));
plaintext[i]=key[i] ^ value;
}
- /*
- Reset registers.
- */
value=0;
}
@@ -467,9 +460,6 @@ static void EncipherAESBlock(AESInfo *aes_info,const unsigned char *plaintext,
InitializeRoundKey(plaintext,aes_info->encipher_key,text);
for (i=1; i < aes_info->rounds; i++)
{
- /*
- Linear mixing step: cause diffusion of the bits over multiple rounds.
- */
for (j=0; j < 4; j++)
key[j]=D[text[j] & 0xff] ^
RotateLeft(D[(text[map[1][j]] >> 8) & 0xff] ^
@@ -484,9 +474,6 @@ static void EncipherAESBlock(AESInfo *aes_info,const unsigned char *plaintext,
key[i]=ByteSubTransform(alpha,SBox);
}
FinalizeRoundKey(key,aes_info->encipher_key+4*aes_info->rounds,ciphertext);
- /*
- Reset registers.
- */
alpha=0;
(void) ResetMagickMemory(key,0,sizeof(key));
(void) ResetMagickMemory(text,0,sizeof(text));
@@ -505,26 +492,9 @@ static void EncipherAESBlock(AESInfo *aes_info,const unsigned char *plaintext,
%
% PasskeyDecipherImage() converts cipher pixels to plain pixels.
%
-% The format of the PasskeyDecipherImage method is:
-%
-% MagickBooleanType PasskeyDecipherImage(Image *image,
-% const StringInfo *passkey,ExceptionInfo *exception)
-% MagickBooleanType DecipherImage(Image *image,const char *passphrase,
-% ExceptionInfo *exception)
-%
-% A description of each parameter follows:
-%
-% o image: the image.
-%
-% o passphrase: decipher cipher pixels with this passphrase.
-%
-% o passkey: decrypt cipher pixels with this passkey.
-%
-% o exception: return any errors or warnings in this structure.
-%
*/
-static inline void IncrementCipherNonce(const size_t length,
+static inline MagickBooleanType IncrementCipherNonce(const size_t length,
unsigned char *nonce)
{
ssize_t
@@ -534,9 +504,9 @@ static inline void IncrementCipherNonce(const size_t length,
{
nonce[i]++;
if (nonce[i] != 0)
- return;
+ return(MagickTrue);
}
- ThrowFatalException(ResourceLimitFatalError,"Sequence wrap error");
+ return(MagickFalse);
}
MagickExport MagickBooleanType DecipherImage(Image *image,
@@ -605,9 +575,6 @@ MagickExport MagickBooleanType PasskeyDecipherImage(Image *image,
output_block[AESBlocksize],
*pixels;
- /*
- Generate decipher key and nonce.
- */
assert(image != (Image *) NULL);
assert(image->signature == MagickCoreSignature);
assert(exception != (ExceptionInfo *) NULL);
@@ -616,6 +583,7 @@ MagickExport MagickBooleanType PasskeyDecipherImage(Image *image,
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
if (passkey == (const StringInfo *) NULL)
return(MagickTrue);
+
aes_info=AcquireAESInfo();
key=CloneStringInfo(passkey);
if (key == (StringInfo *) NULL)
@@ -647,9 +615,7 @@ MagickExport MagickBooleanType PasskeyDecipherImage(Image *image,
(void) memcpy(input_block,digest,MagickMin(AESBlocksize,
GetSignatureDigestsize(signature_info))*sizeof(*input_block));
signature_info=DestroySignatureInfo(signature_info);
- /*
- Convert cipher pixels to plain pixels.
- */
+
quantum_info=AcquireQuantumInfo((const ImageInfo *) NULL,image);
if (quantum_info == (QuantumInfo *) NULL)
{
@@ -679,7 +645,13 @@ MagickExport MagickBooleanType PasskeyDecipherImage(Image *image,
{
(void) memcpy(output_block,input_block,AESBlocksize*
sizeof(*output_block));
- IncrementCipherNonce(AESBlocksize,input_block);
+ if (IncrementCipherNonce(AESBlocksize,input_block) == MagickFalse)
+ {
+ image_view=DestroyCacheView(image_view);
+ quantum_info=DestroyQuantumInfo(quantum_info);
+ aes_info=DestroyAESInfo(aes_info);
+ ThrowBinaryException(ResourceLimitError,"SequenceWrapError",image->filename);
+ }
EncipherAESBlock(aes_info,output_block,output_block);
for (i=0; i < AESBlocksize; i++)
p[i]^=output_block[i];
@@ -707,9 +679,7 @@ MagickExport MagickBooleanType PasskeyDecipherImage(Image *image,
(void) DeleteImageProperty(image,"cipher:mode");
(void) DeleteImageProperty(image,"cipher:nonce");
image->taint=MagickFalse;
- /*
- Free resources.
- */
+
quantum_info=DestroyQuantumInfo(quantum_info);
aes_info=DestroyAESInfo(aes_info);
(void) ResetMagickMemory(input_block,0,sizeof(input_block));
@@ -730,23 +700,6 @@ MagickExport MagickBooleanType PasskeyDecipherImage(Image *image,
%
% PasskeyEncipherImage() converts pixels to cipher-pixels.
%
-% The format of the PasskeyEncipherImage method is:
-%
-% MagickBooleanType PasskeyEncipherImage(Image *image,
-% const StringInfo *passkey,ExceptionInfo *exception)
-% MagickBooleanType EncipherImage(Image *image,const char *passphrase,
-% ExceptionInfo *exception)
-%
-% A description of each parameter follows:
-%
-% o image: the image.
-%
-% o passphrase: encipher pixels with this passphrase.
-%
-% o passkey: decrypt cipher pixels with this passkey.
-%
-% o exception: return any errors or warnings in this structure.
-%
*/
MagickExport MagickBooleanType EncipherImage(Image *image,
@@ -818,9 +771,6 @@ MagickExport MagickBooleanType PasskeyEncipherImage(Image *image,
output_block[AESBlocksize],
*pixels;
- /*
- Generate encipher key and nonce.
- */
assert(image != (Image *) NULL);
assert(image->signature == MagickCoreSignature);
assert(exception != (ExceptionInfo *) NULL);
@@ -831,6 +781,7 @@ MagickExport MagickBooleanType PasskeyEncipherImage(Image *image,
return(MagickTrue);
if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
return(MagickFalse);
+
aes_info=AcquireAESInfo();
key=CloneStringInfo(passkey);
if (key == (StringInfo *) NULL)
@@ -862,14 +813,13 @@ MagickExport MagickBooleanType PasskeyEncipherImage(Image *image,
(void) SetImageProperty(image,"cipher:mode","CTR",exception);
(void) SetImageProperty(image,"cipher:nonce",signature,exception);
signature=DestroyString(signature);
+
(void) memset(input_block,0,sizeof(input_block));
digest=GetStringInfoDatum(GetSignatureDigest(signature_info));
(void) memcpy(input_block,digest,MagickMin(AESBlocksize,
GetSignatureDigestsize(signature_info))*sizeof(*input_block));
signature_info=DestroySignatureInfo(signature_info);
- /*
- Convert plain pixels to cipher pixels.
- */
+
quantum_info=AcquireQuantumInfo((const ImageInfo *) NULL,image);
if (quantum_info == (QuantumInfo *) NULL)
{
@@ -899,7 +849,13 @@ MagickExport MagickBooleanType PasskeyEncipherImage(Image *image,
{
(void) memcpy(output_block,input_block,AESBlocksize*
sizeof(*output_block));
- IncrementCipherNonce(AESBlocksize,input_block);
+ if (IncrementCipherNonce(AESBlocksize,input_block) == MagickFalse)
+ {
+ image_view=DestroyCacheView(image_view);
+ quantum_info=DestroyQuantumInfo(quantum_info);
+ aes_info=DestroyAESInfo(aes_info);
+ ThrowBinaryException(ResourceLimitError,"SequenceWrapError",image->filename);
+ }
EncipherAESBlock(aes_info,output_block,output_block);
for (i=0; i < AESBlocksize; i++)
p[i]^=output_block[i];
@@ -924,9 +880,7 @@ MagickExport MagickBooleanType PasskeyEncipherImage(Image *image,
}
image_view=DestroyCacheView(image_view);
image->taint=MagickFalse;
- /*
- Free resources.
- */
+
quantum_info=DestroyQuantumInfo(quantum_info);
aes_info=DestroyAESInfo(aes_info);
(void) ResetMagickMemory(input_block,0,sizeof(input_block));
@@ -945,19 +899,7 @@ MagickExport MagickBooleanType PasskeyEncipherImage(Image *image,
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
-% SetAESKey() sets the key for the AES cipher. The key length is specified
-% in bits. Valid values are 128, 192, or 256 requiring a key buffer length
-% in bytes of 16, 24, and 32 respectively.
-%
-% The format of the SetAESKey method is:
-%
-% void SetAESKey(AESInfo *aes_info,const StringInfo *key)
-%
-% A description of each parameter follows:
-%
-% o aes_info: the cipher context.
-%
-% o key: the key.
+% SetAESKey() sets the key for the AES cipher.
%
*/
@@ -997,11 +939,9 @@ static inline unsigned int RotateRight(const unsigned int x)
static void SetAESKey(AESInfo *aes_info,const StringInfo *key)
{
- ssize_t
- i;
-
ssize_t
bytes,
+ i,
n;
unsigned char
@@ -1011,9 +951,6 @@ static void SetAESKey(AESInfo *aes_info,const StringInfo *key)
alpha,
beta;
- /*
- Determine the number of rounds based on the number of bits in key.
- */
assert(aes_info != (AESInfo *) NULL);
assert(aes_info->signature == MagickCoreSignature);
assert(key != (StringInfo *) NULL);
@@ -1032,9 +969,7 @@ static void SetAESKey(AESInfo *aes_info,const StringInfo *key)
n=6;
aes_info->rounds=12;
}
- /*
- Generate crypt key.
- */
+
datum=GetStringInfoDatum(aes_info->key);
(void) memset(datum,0,GetStringInfoLength(aes_info->key));
(void) memcpy(datum,GetStringInfoDatum(key),MagickMin(
@@ -1059,9 +994,6 @@ static void SetAESKey(AESInfo *aes_info,const StringInfo *key)
alpha=ByteSubTransform(alpha,SBox);
aes_info->encipher_key[i]=aes_info->encipher_key[i-n] ^ alpha;
}
- /*
- Generate decipher key (in reverse order).
- */
for (i=0; i < 4; i++)
{
aes_info->decipher_key[i]=aes_info->encipher_key[i];
@@ -1069,9 +1001,6 @@ static void SetAESKey(AESInfo *aes_info,const StringInfo *key)
}
for (i=4; i < (bytes-4); i+=4)
InverseAddRoundKey(aes_info->encipher_key+i,aes_info->decipher_key+i);
- /*
- Reset registers.
- */
datum=GetStringInfoDatum(aes_info->key);
(void) memset(datum,0,GetStringInfoLength(aes_info->key));
alpha=0;
@@ -1080,37 +1009,8 @@ static void SetAESKey(AESInfo *aes_info,const StringInfo *key)
#else
/*
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% %
-% %
-% %
-% P a s s k e y D e c i p h e r I m a g e %
-% %
-% %
-% %
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%
-% PasskeyDecipherImage() converts cipher pixels to plain pixels.
-%
-% The format of the PasskeyDecipherImage method is:
-%
-% MagickBooleanType PasskeyDecipherImage(Image *image,
-% const StringInfo *passkey,ExceptionInfo *exception)
-% MagickBooleanType DecipherImage(Image *image,const char *passphrase,
-% ExceptionInfo *exception)
-%
-% A description of each parameter follows:
-%
-% o image: the image.
-%
-% o passphrase: decipher cipher pixels with this passphrase.
-%
-% o passkey: decrypt cipher pixels with this passkey.
-%
-% o exception: return any errors or warnings in this structure.
-%
+ Disabled cipher support fallback stubs.
*/
-
MagickExport MagickBooleanType DecipherImage(Image *image,
const char *passphrase,ExceptionInfo *exception)
{
@@ -1136,36 +1036,6 @@ MagickExport MagickBooleanType PasskeyDecipherImage(Image *image,
(void) passkey;
ThrowBinaryException(ImageError,"CipherSupportNotEnabled",image->filename);
}
-
-/*
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% %
-% %
-% %
-% P a s s k e y E n c i p h e r I m a g e %
-% %
-% %
-% %
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%
-% PasskeyEncipherImage() converts pixels to cipher-pixels.
-%
-% The format of the PasskeyEncipherImage method is:
-%
-% MagickBooleanType PasskeyEncipherImage(Image *image,
-% const StringInfo *passkey,ExceptionInfo *exception)
-% MagickBooleanType EncipherImage(Image *image,const char *passphrase,
-% ExceptionInfo *exception)
-%
-% A description of each parameter follows:
-%
-% o passphrase: decipher cipher pixels with this passphrase.
-%
-% o passkey: decrypt cipher pixels with this passkey.
-%
-% o exception: return any errors or warnings in this structure.
-%
-*/
MagickExport MagickBooleanType EncipherImage(Image *image,
const char *passphrase,ExceptionInfo *exception)