|
|
/*
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
% %
|
|
|
% %
|
|
|
% 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
|