1/*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3 *
4 * This code is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 only, as
6 * published by the Free Software Foundation. Oracle designates this
7 * particular file as subject to the "Classpath" exception as provided
8 * by Oracle in the LICENSE file that accompanied this code.
9 *
10 * This code is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * version 2 for more details (a copy is included in the LICENSE file that
14 * accompanied this code).
15 *
16 * You should have received a copy of the GNU General Public License version
17 * 2 along with this work; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21 * or visit www.oracle.com if you need additional information or have any
22 * questions.
23 */
24
25// This file is available under and governed by the GNU General Public
26// License version 2 only, as published by the Free Software Foundation.
27// However, the following notice accompanied the original version of this
28// file:
29//
30//---------------------------------------------------------------------------------
31//
32// Little Color Management System
33// Copyright (c) 1998-2017 Marti Maria Saguer
34//
35// Permission is hereby granted, free of charge, to any person obtaining
36// a copy of this software and associated documentation files (the "Software"),
37// to deal in the Software without restriction, including without limitation
38// the rights to use, copy, modify, merge, publish, distribute, sublicense,
39// and/or sell copies of the Software, and to permit persons to whom the Software
40// is furnished to do so, subject to the following conditions:
41//
42// The above copyright notice and this permission notice shall be included in
43// all copies or substantial portions of the Software.
44//
45// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
46// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
47// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
48// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
49// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
50// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
51// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
52//
53//---------------------------------------------------------------------------------
54
55
56#include "lcms2_internal.h"
57
58#ifdef CMS_USE_BIG_ENDIAN
59
60static
61void byteReverse(cmsUInt8Number * buf, cmsUInt32Number longs)
62{
63 do {
64
65 cmsUInt32Number t = _cmsAdjustEndianess32(*(cmsUInt32Number *) buf);
66 *(cmsUInt32Number *) buf = t;
67 buf += sizeof(cmsUInt32Number);
68
69 } while (--longs);
70
71}
72
73#else
74#define byteReverse(buf, len)
75#endif
76
77
78typedef struct {
79
80 cmsUInt32Number buf[4];
81 cmsUInt32Number bits[2];
82 cmsUInt8Number in[64];
83 cmsContext ContextID;
84
85} _cmsMD5;
86
87#define F1(x, y, z) (z ^ (x & (y ^ z)))
88#define F2(x, y, z) F1(z, x, y)
89#define F3(x, y, z) (x ^ y ^ z)
90#define F4(x, y, z) (y ^ (x | ~z))
91
92#define STEP(f, w, x, y, z, data, s) \
93 ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
94
95
96static
97void MD5_Transform(cmsUInt32Number buf[4], cmsUInt32Number in[16])
98
99{
100 register cmsUInt32Number a, b, c, d;
101
102 a = buf[0];
103 b = buf[1];
104 c = buf[2];
105 d = buf[3];
106
107 STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
108 STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
109 STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
110 STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
111 STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
112 STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
113 STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
114 STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
115 STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
116 STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
117 STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
118 STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
119 STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
120 STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
121 STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
122 STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
123
124 STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
125 STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
126 STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
127 STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
128 STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
129 STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
130 STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
131 STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
132 STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
133 STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
134 STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
135 STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
136 STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
137 STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
138 STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
139 STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
140
141 STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
142 STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
143 STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
144 STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
145 STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
146 STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
147 STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
148 STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
149 STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
150 STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
151 STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
152 STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
153 STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
154 STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
155 STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
156 STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
157
158 STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
159 STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
160 STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
161 STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
162 STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
163 STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
164 STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
165 STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
166 STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
167 STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
168 STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
169 STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
170 STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
171 STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
172 STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
173 STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
174
175 buf[0] += a;
176 buf[1] += b;
177 buf[2] += c;
178 buf[3] += d;
179}
180
181
182// Create a MD5 object
183static
184cmsHANDLE MD5alloc(cmsContext ContextID)
185{
186 _cmsMD5* ctx = (_cmsMD5*) _cmsMallocZero(ContextID, sizeof(_cmsMD5));
187 if (ctx == NULL) return NULL;
188
189 ctx ->ContextID = ContextID;
190
191 ctx->buf[0] = 0x67452301;
192 ctx->buf[1] = 0xefcdab89;
193 ctx->buf[2] = 0x98badcfe;
194 ctx->buf[3] = 0x10325476;
195
196 ctx->bits[0] = 0;
197 ctx->bits[1] = 0;
198
199 return (cmsHANDLE) ctx;
200}
201
202
203static
204void MD5add(cmsHANDLE Handle, cmsUInt8Number* buf, cmsUInt32Number len)
205{
206 _cmsMD5* ctx = (_cmsMD5*) Handle;
207 cmsUInt32Number t;
208
209 t = ctx->bits[0];
210 if ((ctx->bits[0] = t + (len << 3)) < t)
211 ctx->bits[1]++;
212
213 ctx->bits[1] += len >> 29;
214
215 t = (t >> 3) & 0x3f;
216
217 if (t) {
218
219 cmsUInt8Number *p = (cmsUInt8Number *) ctx->in + t;
220
221 t = 64 - t;
222 if (len < t) {
223 memmove(p, buf, len);
224 return;
225 }
226
227 memmove(p, buf, t);
228 byteReverse(ctx->in, 16);
229
230 MD5_Transform(ctx->buf, (cmsUInt32Number *) ctx->in);
231 buf += t;
232 len -= t;
233 }
234
235 while (len >= 64) {
236 memmove(ctx->in, buf, 64);
237 byteReverse(ctx->in, 16);
238 MD5_Transform(ctx->buf, (cmsUInt32Number *) ctx->in);
239 buf += 64;
240 len -= 64;
241 }
242
243 memmove(ctx->in, buf, len);
244}
245
246// Destroy the object and return the checksum
247static
248void MD5finish(cmsProfileID* ProfileID, cmsHANDLE Handle)
249{
250 _cmsMD5* ctx = (_cmsMD5*) Handle;
251 cmsUInt32Number count;
252 cmsUInt8Number *p;
253
254 count = (ctx->bits[0] >> 3) & 0x3F;
255
256 p = ctx->in + count;
257 *p++ = 0x80;
258
259 count = 64 - 1 - count;
260
261 if (count < 8) {
262
263 memset(p, 0, count);
264 byteReverse(ctx->in, 16);
265 MD5_Transform(ctx->buf, (cmsUInt32Number *) ctx->in);
266
267 memset(ctx->in, 0, 56);
268 } else {
269 memset(p, 0, count - 8);
270 }
271 byteReverse(ctx->in, 14);
272
273 ((cmsUInt32Number *) ctx->in)[14] = ctx->bits[0];
274 ((cmsUInt32Number *) ctx->in)[15] = ctx->bits[1];
275
276 MD5_Transform(ctx->buf, (cmsUInt32Number *) ctx->in);
277
278 byteReverse((cmsUInt8Number *) ctx->buf, 4);
279 memmove(ProfileID ->ID8, ctx->buf, 16);
280
281 _cmsFree(ctx ->ContextID, ctx);
282}
283
284
285
286// Assuming io points to an ICC profile, compute and store MD5 checksum
287// In the header, rendering intentent, attributes and ID should be set to zero
288// before computing MD5 checksum (per 6.1.13 in ICC spec)
289
290cmsBool CMSEXPORT cmsMD5computeID(cmsHPROFILE hProfile)
291{
292 cmsContext ContextID;
293 cmsUInt32Number BytesNeeded;
294 cmsUInt8Number* Mem = NULL;
295 cmsHANDLE MD5 = NULL;
296 _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
297 _cmsICCPROFILE Keep;
298
299 _cmsAssert(hProfile != NULL);
300
301 ContextID = cmsGetProfileContextID(hProfile);
302
303 // Save a copy of the profile header
304 memmove(&Keep, Icc, sizeof(_cmsICCPROFILE));
305
306 // Set RI, attributes and ID
307 memset(&Icc ->attributes, 0, sizeof(Icc ->attributes));
308 Icc ->RenderingIntent = 0;
309 memset(&Icc ->ProfileID, 0, sizeof(Icc ->ProfileID));
310
311 // Compute needed storage
312 if (!cmsSaveProfileToMem(hProfile, NULL, &BytesNeeded)) goto Error;
313
314 // Allocate memory
315 Mem = (cmsUInt8Number*) _cmsMalloc(ContextID, BytesNeeded);
316 if (Mem == NULL) goto Error;
317
318 // Save to temporary storage
319 if (!cmsSaveProfileToMem(hProfile, Mem, &BytesNeeded)) goto Error;
320
321 // Create MD5 object
322 MD5 = MD5alloc(ContextID);
323 if (MD5 == NULL) goto Error;
324
325 // Add all bytes
326 MD5add(MD5, Mem, BytesNeeded);
327
328 // Temp storage is no longer needed
329 _cmsFree(ContextID, Mem);
330
331 // Restore header
332 memmove(Icc, &Keep, sizeof(_cmsICCPROFILE));
333
334 // And store the ID
335 MD5finish(&Icc ->ProfileID, MD5);
336 return TRUE;
337
338Error:
339
340 // Free resources as something went wrong
341 // "MD5" cannot be other than NULL here, so no need to free it
342 if (Mem != NULL) _cmsFree(ContextID, Mem);
343 memmove(Icc, &Keep, sizeof(_cmsICCPROFILE));
344 return FALSE;
345}
346
347