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-2016 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