You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1191 lines
41 KiB

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% CCCC IIIII PPPP H H EEEEE RRRR %
% C I P P H H E R R %
% C I PPPP HHHHH EEE RRRR %
% C I P H H E R R %
% CCCC IIIII P H H EEEEE R R %
% %
% %
% MagickCore Cipher Methods %
% %
% Software Design %
% Cristy %
% March 2003 %
% %
% %
% Copyright 1999-2021 ImageMagick Studio LLC, a non-profit organization %
% dedicated to making software imaging solutions freely available. %
% %
% You may not use this file except in compliance with the License. You may %
% obtain a copy of the License at %
% %
% https://imagemagick.org/script/license.php %
% %
% Unless required by applicable law or agreed to in writing, software %
% distributed under the License is distributed on an "AS IS" BASIS, %
% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
% See the License for the specific language governing permissions and %
% limitations under the License. %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%
*/
/*
Include declarations.
*/
#include "MagickCore/studio.h"
#include "MagickCore/cache.h"
#include "MagickCore/cipher.h"
#include "MagickCore/exception.h"
#include "MagickCore/exception-private.h"
#include "MagickCore/image.h"
#include "MagickCore/image-private.h"
#include "MagickCore/linked-list.h"
#include "MagickCore/list.h"
#include "MagickCore/memory_.h"
#include "MagickCore/memory-private.h"
#include "MagickCore/monitor.h"
#include "MagickCore/monitor-private.h"
#include "MagickCore/property.h"
#include "MagickCore/quantum-private.h"
#include "MagickCore/registry.h"
#include "MagickCore/semaphore.h"
#include "MagickCore/signature-private.h"
#include "MagickCore/splay-tree.h"
#include "MagickCore/statistic.h"
#include "MagickCore/string_.h"
#if defined(MAGICKCORE_CIPHER_SUPPORT)
/*
Define declarations.
*/
#define AESBlocksize 16
/*
Typedef declarations.
*/
typedef struct _AESInfo
{
StringInfo
*key;
unsigned int
blocksize,
*encipher_key,
*decipher_key;
ssize_t
rounds,
timestamp;
size_t
signature;
} AESInfo;
/*
Global declarations.
*/
static unsigned char
InverseLog[256] =
{
1, 3, 5, 15, 17, 51, 85, 255, 26, 46, 114, 150, 161, 248,
19, 53, 95, 225, 56, 72, 216, 115, 149, 164, 247, 2, 6, 10,
30, 34, 102, 170, 229, 52, 92, 228, 55, 89, 235, 38, 106, 190,
217, 112, 144, 171, 230, 49, 83, 245, 4, 12, 20, 60, 68, 204,
79, 209, 104, 184, 211, 110, 178, 205, 76, 212, 103, 169, 224, 59,
77, 215, 98, 166, 241, 8, 24, 40, 120, 136, 131, 158, 185, 208,
107, 189, 220, 127, 129, 152, 179, 206, 73, 219, 118, 154, 181, 196,
87, 249, 16, 48, 80, 240, 11, 29, 39, 105, 187, 214, 97, 163,
254, 25, 43, 125, 135, 146, 173, 236, 47, 113, 147, 174, 233, 32,
96, 160, 251, 22, 58, 78, 210, 109, 183, 194, 93, 231, 50, 86,
250, 21, 63, 65, 195, 94, 226, 61, 71, 201, 64, 192, 91, 237,
44, 116, 156, 191, 218, 117, 159, 186, 213, 100, 172, 239, 42, 126,
130, 157, 188, 223, 122, 142, 137, 128, 155, 182, 193, 88, 232, 35,
101, 175, 234, 37, 111, 177, 200, 67, 197, 84, 252, 31, 33, 99,
165, 244, 7, 9, 27, 45, 119, 153, 176, 203, 70, 202, 69, 207,
74, 222, 121, 139, 134, 145, 168, 227, 62, 66, 198, 81, 243, 14,
18, 54, 90, 238, 41, 123, 141, 140, 143, 138, 133, 148, 167, 242,
13, 23, 57, 75, 221, 124, 132, 151, 162, 253, 28, 36, 108, 180,
199, 82, 246, 1
},
Log[256] =
{
0, 0, 25, 1, 50, 2, 26, 198, 75, 199, 27, 104, 51, 238,
223, 3, 100, 4, 224, 14, 52, 141, 129, 239, 76, 113, 8, 200,
248, 105, 28, 193, 125, 194, 29, 181, 249, 185, 39, 106, 77, 228,
166, 114, 154, 201, 9, 120, 101, 47, 138, 5, 33, 15, 225, 36,
18, 240, 130, 69, 53, 147, 218, 142, 150, 143, 219, 189, 54, 208,
206, 148, 19, 92, 210, 241, 64, 70, 131, 56, 102, 221, 253, 48,
191, 6, 139, 98, 179, 37, 226, 152, 34, 136, 145, 16, 126, 110,
72, 195, 163, 182, 30, 66, 58, 107, 40, 84, 250, 133, 61, 186,
43, 121, 10, 21, 155, 159, 94, 202, 78, 212, 172, 229, 243, 115,
167, 87, 175, 88, 168, 80, 244, 234, 214, 116, 79, 174, 233, 213,
231, 230, 173, 232, 44, 215, 117, 122, 235, 22, 11, 245, 89, 203,
95, 176, 156, 169, 81, 160, 127, 12, 246, 111, 23, 196, 73, 236,
216, 67, 31, 45, 164, 118, 123, 183, 204, 187, 62, 90, 251, 96,
177, 134, 59, 82, 161, 108, 170, 85, 41, 157, 151, 178, 135, 144,
97, 190, 220, 252, 188, 149, 207, 205, 55, 63, 91, 209, 83, 57,
132, 60, 65, 162, 109, 71, 20, 42, 158, 93, 86, 242, 211, 171,
68, 17, 146, 217, 35, 32, 46, 137, 180, 124, 184, 38, 119, 153,
227, 165, 103, 74, 237, 222, 197, 49, 254, 24, 13, 99, 140, 128,
192, 247, 112, 7,
},
SBox[256] =
{
99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215,
171, 118, 202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175,
156, 164, 114, 192, 183, 253, 147, 38, 54, 63, 247, 204, 52, 165,
229, 241, 113, 216, 49, 21, 4, 199, 35, 195, 24, 150, 5, 154,
7, 18, 128, 226, 235, 39, 178, 117, 9, 131, 44, 26, 27, 110,
90, 160, 82, 59, 214, 179, 41, 227, 47, 132, 83, 209, 0, 237,
32, 252, 177, 91, 106, 203, 190, 57, 74, 76, 88, 207, 208, 239,
170, 251, 67, 77, 51, 133, 69, 249, 2, 127, 80, 60, 159, 168,
81, 163, 64, 143, 146, 157, 56, 245, 188, 182, 218, 33, 16, 255,
243, 210, 205, 12, 19, 236, 95, 151, 68, 23, 196, 167, 126, 61,
100, 93, 25, 115, 96, 129, 79, 220, 34, 42, 144, 136, 70, 238,
184, 20, 222, 94, 11, 219, 224, 50, 58, 10, 73, 6, 36, 92,
194, 211, 172, 98, 145, 149, 228, 121, 231, 200, 55, 109, 141, 213,
78, 169, 108, 86, 244, 234, 101, 122, 174, 8, 186, 120, 37, 46,
28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138, 112, 62,
181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158,
225, 248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85,
40, 223, 140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15,
176, 84, 187, 22
};
/*
Forward declarations.
*/
static AESInfo
*DestroyAESInfo(AESInfo *);
static void
EncipherAESBlock(AESInfo *,const unsigned char *,unsigned char *),
SetAESKey(AESInfo *,const StringInfo *);
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% A c q u i r e A E S I n f o %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% AcquireAESInfo() allocate the AESInfo structure.
%
% The format of the AcquireAESInfo method is:
%
% AESInfo *AcquireAESInfo(void)
%
*/
static AESInfo *AcquireAESInfo(void)
{
AESInfo
*aes_info;
aes_info=(AESInfo *) AcquireCriticalMemory(sizeof(*aes_info));
(void) memset(aes_info,0,sizeof(*aes_info));
aes_info->blocksize=AESBlocksize;
aes_info->key=AcquireStringInfo(32);
aes_info->encipher_key=(unsigned int *) AcquireQuantumMemory(60UL,sizeof(
*aes_info->encipher_key));
aes_info->decipher_key=(unsigned int *) AcquireQuantumMemory(60UL,sizeof(
*aes_info->decipher_key));
if ((aes_info->key == (StringInfo *) NULL) ||
(aes_info->encipher_key == (unsigned int *) NULL) ||
(aes_info->decipher_key == (unsigned int *) NULL))
ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
aes_info->timestamp=(ssize_t) time(0);
aes_info->signature=MagickCoreSignature;
return(aes_info);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% D e s t r o y A E S I n f o %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% DestroyAESInfo() zeros memory associated with the AESInfo structure.
%
% The format of the DestroyAESInfo method is:
%
% AESInfo *DestroyAESInfo(AESInfo *aes_info)
%
% A description of each parameter follows:
%
% o aes_info: the cipher context.
%
*/
static AESInfo *DestroyAESInfo(AESInfo *aes_info)
{
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
assert(aes_info != (AESInfo *) NULL);
assert(aes_info->signature == MagickCoreSignature);
if (aes_info->decipher_key != (unsigned int *) NULL)
aes_info->decipher_key=(unsigned int *) RelinquishMagickMemory(
aes_info->decipher_key);
if (aes_info->encipher_key != (unsigned int *) NULL)
aes_info->encipher_key=(unsigned int *) RelinquishMagickMemory(
aes_info->encipher_key);
if (aes_info->key != (StringInfo *) NULL)
aes_info->key=DestroyStringInfo(aes_info->key);
aes_info->signature=(~MagickCoreSignature);
aes_info=(AESInfo *) RelinquishMagickMemory(aes_info);
return(aes_info);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% E n c i p h e r A E S B l o c k %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% EncipherAESBlock() enciphers a single block of plaintext to produce a block
% of ciphertext.
%
% The format of the EncipherAESBlock method is:
%
% void EncipherAES(AESInfo *aes_info,const unsigned char *plaintext,
% unsigned char *ciphertext)
%
% A description of each parameter follows:
%
% o aes_info: the cipher context.
%
% o plaintext: the plain text.
%
% o ciphertext: the cipher text.
%
*/
static inline void AddRoundKey(const unsigned int *ciphertext,
const unsigned int *key,unsigned int *plaintext)
{
ssize_t
i;
/*
Xor corresponding text input and round key input bytes.
*/
for (i=0; i < 4; i++)
plaintext[i]=key[i] ^ ciphertext[i];
}
static inline unsigned int ByteMultiply(const unsigned char alpha,
const unsigned char beta)
{
/*
Byte multiply two elements of GF(2^m) (mix columns and inverse mix columns).
*/
if ((alpha == 0) || (beta == 0))
return(0);
return((unsigned int) InverseLog[(Log[alpha]+Log[beta]) % 0xff]);
}
static inline unsigned int ByteSubTransform(unsigned int x,
unsigned char *s_box)
{
unsigned int
key;
/*
Non-linear layer resists differential and linear cryptoanalysis attacks.
*/
key=((unsigned int) s_box[x & 0xff]) |
((unsigned int) s_box[(x >> 8) & 0xff] << 8) |
((unsigned int) s_box[(x >> 16) & 0xff] << 16) |
((unsigned int) s_box[(x >> 24) & 0xff] << 24);
return(key);
}
static void FinalizeRoundKey(const unsigned int *ciphertext,
const unsigned int *key,unsigned char *plaintext)
{
unsigned char
*p;
unsigned int
i,
j;
unsigned int
value;
/*
The round key is XORed with the result of the mix-column transformation.
*/
p=plaintext;
for (i=0; i < 4; i++)
{
value=ciphertext[i] ^ key[i];
for (j=0; j < 4; j++)
*p++=(unsigned char) ((value >> (8*j)) & 0xff);
}
/*
Reset registers.
*/
value=0;
}
static void InitializeRoundKey(const unsigned char *ciphertext,
const unsigned int *key,unsigned int *plaintext)
{
const unsigned char
*p;
unsigned int
i,
j;
unsigned int
value;
p=ciphertext;
for (i=0; i < 4; i++)
{
value=0;
for (j=0; j < 4; j++)
value|=((unsigned int) *p++ << (8*j));
plaintext[i]=key[i] ^ value;
}
/*
Reset registers.
*/
value=0;
}
static inline unsigned int RotateLeft(const unsigned int x)
{
return(((x << 8) | ((x >> 24) & 0xff)));
}
static void EncipherAESBlock(AESInfo *aes_info,const unsigned char *plaintext,
unsigned char *ciphertext)
{
ssize_t
i,
j;
static int
map[4][4] =
{
{ 0, 1, 2, 3 },
{ 1, 2, 3, 0 },
{ 2, 3, 0, 1 },
{ 3, 0, 1, 2 }
};
static unsigned int
D[] =
{
0xa56363c6U, 0x847c7cf8U, 0x997777eeU, 0x8d7b7bf6U, 0x0df2f2ffU,
0xbd6b6bd6U, 0xb16f6fdeU, 0x54c5c591U, 0x50303060U, 0x03010102U,
0xa96767ceU, 0x7d2b2b56U, 0x19fefee7U, 0x62d7d7b5U, 0xe6abab4dU,
0x9a7676ecU, 0x45caca8fU, 0x9d82821fU, 0x40c9c989U, 0x877d7dfaU,
0x15fafaefU, 0xeb5959b2U, 0xc947478eU, 0x0bf0f0fbU, 0xecadad41U,
0x67d4d4b3U, 0xfda2a25fU, 0xeaafaf45U, 0xbf9c9c23U, 0xf7a4a453U,
0x967272e4U, 0x5bc0c09bU, 0xc2b7b775U, 0x1cfdfde1U, 0xae93933dU,
0x6a26264cU, 0x5a36366cU, 0x413f3f7eU, 0x02f7f7f5U, 0x4fcccc83U,
0x5c343468U, 0xf4a5a551U, 0x34e5e5d1U, 0x08f1f1f9U, 0x937171e2U,
0x73d8d8abU, 0x53313162U, 0x3f15152aU, 0x0c040408U, 0x52c7c795U,
0x65232346U, 0x5ec3c39dU, 0x28181830U, 0xa1969637U, 0x0f05050aU,
0xb59a9a2fU, 0x0907070eU, 0x36121224U, 0x9b80801bU, 0x3de2e2dfU,
0x26ebebcdU, 0x6927274eU, 0xcdb2b27fU, 0x9f7575eaU, 0x1b090912U,
0x9e83831dU, 0x742c2c58U, 0x2e1a1a34U, 0x2d1b1b36U, 0xb26e6edcU,
0xee5a5ab4U, 0xfba0a05bU, 0xf65252a4U, 0x4d3b3b76U, 0x61d6d6b7U,
0xceb3b37dU, 0x7b292952U, 0x3ee3e3ddU, 0x712f2f5eU, 0x97848413U,
0xf55353a6U, 0x68d1d1b9U, 0x00000000U, 0x2cededc1U, 0x60202040U,
0x1ffcfce3U, 0xc8b1b179U, 0xed5b5bb6U, 0xbe6a6ad4U, 0x46cbcb8dU,
0xd9bebe67U, 0x4b393972U, 0xde4a4a94U, 0xd44c4c98U, 0xe85858b0U,
0x4acfcf85U, 0x6bd0d0bbU, 0x2aefefc5U, 0xe5aaaa4fU, 0x16fbfbedU,
0xc5434386U, 0xd74d4d9aU, 0x55333366U, 0x94858511U, 0xcf45458aU,
0x10f9f9e9U, 0x06020204U, 0x817f7ffeU, 0xf05050a0U, 0x443c3c78U,
0xba9f9f25U, 0xe3a8a84bU, 0xf35151a2U, 0xfea3a35dU, 0xc0404080U,
0x8a8f8f05U, 0xad92923fU, 0xbc9d9d21U, 0x48383870U, 0x04f5f5f1U,
0xdfbcbc63U, 0xc1b6b677U, 0x75dadaafU, 0x63212142U, 0x30101020U,
0x1affffe5U, 0x0ef3f3fdU, 0x6dd2d2bfU, 0x4ccdcd81U, 0x140c0c18U,
0x35131326U, 0x2fececc3U, 0xe15f5fbeU, 0xa2979735U, 0xcc444488U,
0x3917172eU, 0x57c4c493U, 0xf2a7a755U, 0x827e7efcU, 0x473d3d7aU,
0xac6464c8U, 0xe75d5dbaU, 0x2b191932U, 0x957373e6U, 0xa06060c0U,
0x98818119U, 0xd14f4f9eU, 0x7fdcdca3U, 0x66222244U, 0x7e2a2a54U,
0xab90903bU, 0x8388880bU, 0xca46468cU, 0x29eeeec7U, 0xd3b8b86bU,
0x3c141428U, 0x79dedea7U, 0xe25e5ebcU, 0x1d0b0b16U, 0x76dbdbadU,
0x3be0e0dbU, 0x56323264U, 0x4e3a3a74U, 0x1e0a0a14U, 0xdb494992U,
0x0a06060cU, 0x6c242448U, 0xe45c5cb8U, 0x5dc2c29fU, 0x6ed3d3bdU,
0xefacac43U, 0xa66262c4U, 0xa8919139U, 0xa4959531U, 0x37e4e4d3U,
0x8b7979f2U, 0x32e7e7d5U, 0x43c8c88bU, 0x5937376eU, 0xb76d6ddaU,
0x8c8d8d01U, 0x64d5d5b1U, 0xd24e4e9cU, 0xe0a9a949U, 0xb46c6cd8U,
0xfa5656acU, 0x07f4f4f3U, 0x25eaeacfU, 0xaf6565caU, 0x8e7a7af4U,
0xe9aeae47U, 0x18080810U, 0xd5baba6fU, 0x887878f0U, 0x6f25254aU,
0x722e2e5cU, 0x241c1c38U, 0xf1a6a657U, 0xc7b4b473U, 0x51c6c697U,
0x23e8e8cbU, 0x7cdddda1U, 0x9c7474e8U, 0x211f1f3eU, 0xdd4b4b96U,
0xdcbdbd61U, 0x868b8b0dU, 0x858a8a0fU, 0x907070e0U, 0x423e3e7cU,
0xc4b5b571U, 0xaa6666ccU, 0xd8484890U, 0x05030306U, 0x01f6f6f7U,
0x120e0e1cU, 0xa36161c2U, 0x5f35356aU, 0xf95757aeU, 0xd0b9b969U,
0x91868617U, 0x58c1c199U, 0x271d1d3aU, 0xb99e9e27U, 0x38e1e1d9U,
0x13f8f8ebU, 0xb398982bU, 0x33111122U, 0xbb6969d2U, 0x70d9d9a9U,
0x898e8e07U, 0xa7949433U, 0xb69b9b2dU, 0x221e1e3cU, 0x92878715U,
0x20e9e9c9U, 0x49cece87U, 0xff5555aaU, 0x78282850U, 0x7adfdfa5U,
0x8f8c8c03U, 0xf8a1a159U, 0x80898909U, 0x170d0d1aU, 0xdabfbf65U,
0x31e6e6d7U, 0xc6424284U, 0xb86868d0U, 0xc3414182U, 0xb0999929U,
0x772d2d5aU, 0x110f0f1eU, 0xcbb0b07bU, 0xfc5454a8U, 0xd6bbbb6dU,
0x3a16162cU
};
unsigned int
alpha,
key[4],
text[4];
/*
Encipher one block.
*/
(void) memset(text,0,sizeof(text));
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] ^
RotateLeft(D[(text[map[2][j]] >> 16) & 0xff] ^
RotateLeft(D[(text[map[3][j]] >> 24) & 0xff])));
AddRoundKey(key,aes_info->encipher_key+4*i,text);
}
for (i=0; i < 4; i++)
{
alpha=(text[i] & 0x000000ff) | ((text[map[1][i]]) & 0x0000ff00) |
((text[map[2][i]]) & 0x00ff0000) | ((text[map[3][i]]) & 0xff000000);
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));
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% 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.
%
*/
static inline void IncrementCipherNonce(const size_t length,
unsigned char *nonce)
{
ssize_t
i;
for (i=(ssize_t) (length-1); i >= 0; i--)
{
nonce[i]++;
if (nonce[i] != 0)
return;
}
ThrowFatalException(ResourceLimitFatalError,"Sequence wrap error `%s'");
}
MagickExport MagickBooleanType DecipherImage(Image *image,
const char *passphrase,ExceptionInfo *exception)
{
MagickBooleanType
status;
StringInfo
*passkey;
if (passphrase == (const char *) NULL)
return(MagickTrue);
passkey=StringToStringInfo(passphrase);
if (passkey == (StringInfo *) NULL)
return(MagickFalse);
status=PasskeyDecipherImage(image,passkey,exception);
passkey=DestroyStringInfo(passkey);
return(status);
}
MagickExport MagickBooleanType PasskeyDecipherImage(Image *image,
const StringInfo *passkey,ExceptionInfo *exception)
{
#define DecipherImageTag "Decipher/Image "
AESInfo
*aes_info;
CacheView
*image_view;
const unsigned char
*digest;
MagickBooleanType
proceed;
MagickSizeType
extent;
QuantumInfo
*quantum_info;
QuantumType
quantum_type;
SignatureInfo
*signature_info;
unsigned char
*p;
size_t
length;
ssize_t
y;
StringInfo
*key,
*nonce;
unsigned char
input_block[AESBlocksize],
output_block[AESBlocksize],
*pixels;
/*
Generate decipher key and nonce.
*/
assert(image != (Image *) NULL);
assert(image->signature == MagickCoreSignature);
if (image->debug != MagickFalse)
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
assert(exception != (ExceptionInfo *) NULL);
assert(exception->signature == MagickCoreSignature);
if (passkey == (const StringInfo *) NULL)
return(MagickTrue);
aes_info=AcquireAESInfo();
key=CloneStringInfo(passkey);
if (key == (StringInfo *) NULL)
{
aes_info=DestroyAESInfo(aes_info);
ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
image->filename);
}
nonce=SplitStringInfo(key,GetStringInfoLength(key)/2);
if (nonce == (StringInfo *) NULL)
{
key=DestroyStringInfo(key);
aes_info=DestroyAESInfo(aes_info);
ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
image->filename);
}
SetAESKey(aes_info,key);
key=DestroyStringInfo(key);
signature_info=AcquireSignatureInfo();
UpdateSignature(signature_info,nonce);
extent=(MagickSizeType) image->columns*image->rows;
SetStringInfoLength(nonce,sizeof(extent));
SetStringInfoDatum(nonce,(const unsigned char *) &extent);
UpdateSignature(signature_info,nonce);
nonce=DestroyStringInfo(nonce);
FinalizeSignature(signature_info);
(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 cipher pixels to plain pixels.
*/
quantum_info=AcquireQuantumInfo((const ImageInfo *) NULL,image);
if (quantum_info == (QuantumInfo *) NULL)
{
aes_info=DestroyAESInfo(aes_info);
ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
image->filename);
}
quantum_type=GetQuantumType(image,exception);
pixels=(unsigned char *) GetQuantumPixels(quantum_info);
image_view=AcquireAuthenticCacheView(image,exception);
for (y=0; y < (ssize_t) image->rows; y++)
{
ssize_t
i,
x;
Quantum
*magick_restrict q;
q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
if (q == (Quantum *) NULL)
break;
length=ExportQuantumPixels(image,image_view,quantum_info,quantum_type,
pixels,exception);
p=pixels;
for (x=0; x < (ssize_t) length; x+=AESBlocksize)
{
(void) memcpy(output_block,input_block,AESBlocksize*
sizeof(*output_block));
IncrementCipherNonce(AESBlocksize,input_block);
EncipherAESBlock(aes_info,output_block,output_block);
for (i=0; i < AESBlocksize; i++)
p[i]^=output_block[i];
p+=AESBlocksize;
}
(void) memcpy(output_block,input_block,AESBlocksize*
sizeof(*output_block));
EncipherAESBlock(aes_info,output_block,output_block);
for (i=0; x < (ssize_t) length; x++)
{
p[i]^=output_block[i];
i++;
}
(void) ImportQuantumPixels(image,image_view,quantum_info,quantum_type,
pixels,exception);
if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
break;
proceed=SetImageProgress(image,DecipherImageTag,(MagickOffsetType) y,
image->rows);
if (proceed == MagickFalse)
break;
}
image_view=DestroyCacheView(image_view);
(void) DeleteImageProperty(image,"cipher:type");
(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));
(void) ResetMagickMemory(output_block,0,sizeof(output_block));
return(y == (ssize_t) image->rows ? MagickTrue : MagickFalse);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% 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 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,
const char *passphrase,ExceptionInfo *exception)
{
MagickBooleanType
status;
StringInfo
*passkey;
if (passphrase == (const char *) NULL)
return(MagickTrue);
passkey=StringToStringInfo(passphrase);
if (passkey == (StringInfo *) NULL)
return(MagickFalse);
status=PasskeyEncipherImage(image,passkey,exception);
passkey=DestroyStringInfo(passkey);
return(status);
}
MagickExport MagickBooleanType PasskeyEncipherImage(Image *image,
const StringInfo *passkey,ExceptionInfo *exception)
{
#define EncipherImageTag "Encipher/Image "
AESInfo
*aes_info;
CacheView
*image_view;
char
*signature;
const unsigned char
*digest;
MagickBooleanType
proceed;
MagickSizeType
extent;
QuantumInfo
*quantum_info;
QuantumType
quantum_type;
unsigned char
*p;
SignatureInfo
*signature_info;
size_t
length;
ssize_t
y;
StringInfo
*key,
*nonce;
unsigned char
input_block[AESBlocksize],
output_block[AESBlocksize],
*pixels;
/*
Generate encipher key and nonce.
*/
assert(image != (Image *) NULL);
assert(image->signature == MagickCoreSignature);
if (image->debug != MagickFalse)
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
assert(exception != (ExceptionInfo *) NULL);
assert(exception->signature == MagickCoreSignature);
if (passkey == (const StringInfo *) NULL)
return(MagickTrue);
if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
return(MagickFalse);
aes_info=AcquireAESInfo();
key=CloneStringInfo(passkey);
if (key == (StringInfo *) NULL)
{
aes_info=DestroyAESInfo(aes_info);
ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
image->filename);
}
nonce=SplitStringInfo(key,GetStringInfoLength(key)/2);
if (nonce == (StringInfo *) NULL)
{
key=DestroyStringInfo(key);
aes_info=DestroyAESInfo(aes_info);
ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
image->filename);
}
SetAESKey(aes_info,key);
key=DestroyStringInfo(key);
signature_info=AcquireSignatureInfo();
UpdateSignature(signature_info,nonce);
extent=(MagickSizeType) image->columns*image->rows;
SetStringInfoLength(nonce,sizeof(extent));
SetStringInfoDatum(nonce,(const unsigned char *) &extent);
UpdateSignature(signature_info,nonce);
nonce=DestroyStringInfo(nonce);
FinalizeSignature(signature_info);
signature=StringInfoToHexString(GetSignatureDigest(signature_info));
(void) SetImageProperty(image,"cipher:type","AES",exception);
(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)
{
aes_info=DestroyAESInfo(aes_info);
ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
image->filename);
}
quantum_type=GetQuantumType(image,exception);
pixels=(unsigned char *) GetQuantumPixels(quantum_info);
image_view=AcquireAuthenticCacheView(image,exception);
for (y=0; y < (ssize_t) image->rows; y++)
{
ssize_t
i,
x;
Quantum
*magick_restrict q;
q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
if (q == (Quantum *) NULL)
break;
length=ExportQuantumPixels(image,image_view,quantum_info,quantum_type,
pixels,exception);
p=pixels;
for (x=0; x < (ssize_t) length; x+=AESBlocksize)
{
(void) memcpy(output_block,input_block,AESBlocksize*
sizeof(*output_block));
IncrementCipherNonce(AESBlocksize,input_block);
EncipherAESBlock(aes_info,output_block,output_block);
for (i=0; i < AESBlocksize; i++)
p[i]^=output_block[i];
p+=AESBlocksize;
}
(void) memcpy(output_block,input_block,AESBlocksize*
sizeof(*output_block));
EncipherAESBlock(aes_info,output_block,output_block);
for (i=0; x < (ssize_t) length; x++)
{
p[i]^=output_block[i];
i++;
}
(void) ImportQuantumPixels(image,image_view,quantum_info,quantum_type,
pixels,exception);
if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
break;
proceed=SetImageProgress(image,EncipherImageTag,(MagickOffsetType) y,
image->rows);
if (proceed == MagickFalse)
break;
}
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));
(void) ResetMagickMemory(output_block,0,sizeof(output_block));
return(y == (ssize_t) image->rows ? MagickTrue : MagickFalse);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% S e t A E S K e y %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% 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:
%
% SetAESKey(AESInfo *aes_info,const StringInfo *key)
%
% A description of each parameter follows:
%
% o aes_info: the cipher context.
%
% o key: the key.
%
*/
static inline void InverseAddRoundKey(const unsigned int *alpha,
unsigned int *beta)
{
unsigned int
i,
j;
for (i=0; i < 4; i++)
{
beta[i]=0;
for (j=0; j < 4; j++)
beta[i]|=(ByteMultiply(0xe,(alpha[i] >> (8*j)) & 0xff) ^
ByteMultiply(0xb,(alpha[i] >> (8*((j+1) % 4))) & 0xff) ^
ByteMultiply(0xd,(alpha[i] >> (8*((j+2) % 4))) & 0xff) ^
ByteMultiply(0x9,(alpha[i] >> (8*((j+3) % 4))) & 0xff)) << (8*j);
}
}
static inline unsigned int XTime(unsigned char alpha)
{
unsigned char
beta;
beta=(unsigned char) ((alpha & 0x80) != 0 ? 0x1b : 0);
alpha<<=1;
alpha^=beta;
return(alpha);
}
static inline unsigned int RotateRight(const unsigned int x)
{
return((x >> 8) | ((x & 0xff) << 24));
}
static void SetAESKey(AESInfo *aes_info,const StringInfo *key)
{
ssize_t
i;
ssize_t
bytes,
n;
unsigned char
*datum;
unsigned int
alpha,
beta;
/*
Determine the number of rounds based on the number of bits in key.
*/
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
assert(aes_info != (AESInfo *) NULL);
assert(aes_info->signature == MagickCoreSignature);
assert(key != (StringInfo *) NULL);
n=4;
aes_info->rounds=10;
if ((8*GetStringInfoLength(key)) >= 256)
{
n=8;
aes_info->rounds=14;
}
else
if ((8*GetStringInfoLength(key)) >= 192)
{
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(
GetStringInfoLength(key),GetStringInfoLength(aes_info->key)));
for (i=0; i < n; i++)
aes_info->encipher_key[i]=(unsigned int) datum[4*i] |
((unsigned int) datum[4*i+1] << 8) |
((unsigned int) datum[4*i+2] << 16) |
((unsigned int) datum[4*i+3] << 24);
beta=1;
bytes=(AESBlocksize/4)*(aes_info->rounds+1);
for (i=n; i < bytes; i++)
{
alpha=aes_info->encipher_key[i-1];
if ((i % n) == 0)
{
alpha=ByteSubTransform(RotateRight(alpha),SBox) ^ beta;
beta=XTime((unsigned char) (beta & 0xff));
}
else
if ((n > 6) && ((i % n) == 4))
alpha=ByteSubTransform(alpha,SBox);
aes_info->encipher_key[i]=aes_info->encipher_key[i-n] ^ alpha;
}
/*
Generate deciper key (in reverse order).
*/
for (i=0; i < 4; i++)
{
aes_info->decipher_key[i]=aes_info->encipher_key[i];
aes_info->decipher_key[bytes-4+i]=aes_info->encipher_key[bytes-4+i];
}
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;
beta=0;
}
#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.
%
*/
MagickExport MagickBooleanType DecipherImage(Image *image,
const char *passphrase,ExceptionInfo *exception)
{
assert(image != (Image *) NULL);
assert(image->signature == MagickCoreSignature);
if (image->debug != MagickFalse)
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
assert(exception != (ExceptionInfo *) NULL);
assert(exception->signature == MagickCoreSignature);
(void) passphrase;
ThrowBinaryException(ImageError,"CipherSupportNotEnabled",image->filename);
}
MagickExport MagickBooleanType PasskeyDecipherImage(Image *image,
const StringInfo *passkey,ExceptionInfo *exception)
{
assert(image != (Image *) NULL);
assert(image->signature == MagickCoreSignature);
if (image->debug != MagickFalse)
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
assert(exception != (ExceptionInfo *) NULL);
assert(exception->signature == MagickCoreSignature);
(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)
{
assert(image != (Image *) NULL);
assert(image->signature == MagickCoreSignature);
if (image->debug != MagickFalse)
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
assert(exception != (ExceptionInfo *) NULL);
assert(exception->signature == MagickCoreSignature);
(void) passphrase;
ThrowBinaryException(ImageError,"CipherSupportNotEnabled",image->filename);
}
MagickExport MagickBooleanType PasskeyEncipherImage(Image *image,
const StringInfo *passkey,ExceptionInfo *exception)
{
assert(image != (Image *) NULL);
assert(image->signature == MagickCoreSignature);
if (image->debug != MagickFalse)
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
assert(exception != (ExceptionInfo *) NULL);
assert(exception->signature == MagickCoreSignature);
(void) passkey;
ThrowBinaryException(ImageError,"CipherSupportNotEnabled",image->filename);
}
#endif