md5.c
author Ryan C. Gordon <icculus@icculus.org>
Fri, 23 Jun 2017 17:28:03 -0400
changeset 58 1390348facc7
parent 0 d7ee4e2ed49d
permissions -rw-r--r--
Command line tool that decrypts an OPVault keychain and dumps it to stdout.

To compile: gcc -o opvault opvault.c cJSON.c -lcrypto

Usage: ./opvault </path/to/mykeychain.opvault> <password>

This is just a proof of concept; I'll be recycling this into proper OPVault
support in 1pass later and deleting this tool.

This uses OpenSSL's libcrypto for the math instead of all the homegrown
crypto this project is otherwise using. I'll probably migrate the rest in
this direction, too, since this wasn't as bad as I expected to use and
gets you all the package-manager mojo of automatic bug fixes and security
patches and shared code, etc.

cJSON parses JSON in C. That is from https://github.com/DaveGamble/cJSON

An example OPVault keychain from AgileBits is available here:

https://cache.agilebits.com/security-kb/
icculus@0
     1
// MD5 code originally from http://sourceforge.net/projects/libmd5-rfc/
icculus@0
     2
//  License: zlib.
icculus@0
     3
//  I cleaned it up a little for MojoSetup's specific purposes. --ryan.
icculus@0
     4
icculus@0
     5
/*
icculus@0
     6
  Copyright (C) 1999, 2000, 2002 Aladdin Enterprises.  All rights reserved.
icculus@0
     7
icculus@0
     8
  This software is provided 'as-is', without any express or implied
icculus@0
     9
  warranty.  In no event will the authors be held liable for any damages
icculus@0
    10
  arising from the use of this software.
icculus@0
    11
icculus@0
    12
  Permission is granted to anyone to use this software for any purpose,
icculus@0
    13
  including commercial applications, and to alter it and redistribute it
icculus@0
    14
  freely, subject to the following restrictions:
icculus@0
    15
icculus@0
    16
  1. The origin of this software must not be misrepresented; you must not
icculus@0
    17
     claim that you wrote the original software. If you use this software
icculus@0
    18
     in a product, an acknowledgment in the product documentation would be
icculus@0
    19
     appreciated but is not required.
icculus@0
    20
  2. Altered source versions must be plainly marked as such, and must not be
icculus@0
    21
     misrepresented as being the original software.
icculus@0
    22
  3. This notice may not be removed or altered from any source distribution.
icculus@0
    23
icculus@0
    24
  L. Peter Deutsch
icculus@0
    25
  ghost@aladdin.com
icculus@0
    26
icculus@0
    27
 */
icculus@0
    28
/* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */
icculus@0
    29
/*
icculus@0
    30
  Independent implementation of MD5 (RFC 1321).
icculus@0
    31
icculus@0
    32
  This code implements the MD5 Algorithm defined in RFC 1321, whose
icculus@0
    33
  text is available at
icculus@0
    34
	http://www.ietf.org/rfc/rfc1321.txt
icculus@0
    35
  The code is derived from the text of the RFC, including the test suite
icculus@0
    36
  (section A.5) but excluding the rest of Appendix A.  It does not include
icculus@0
    37
  any code or documentation that is identified in the RFC as being
icculus@0
    38
  copyrighted.
icculus@0
    39
icculus@0
    40
  The original and principal author of md5.c is L. Peter Deutsch
icculus@0
    41
  <ghost@aladdin.com>.  Other authors are noted in the change history
icculus@0
    42
  that follows (in reverse chronological order):
icculus@0
    43
icculus@0
    44
  2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
icculus@0
    45
	either statically or dynamically; added missing #include <string.h>
icculus@0
    46
	in library.
icculus@0
    47
  2002-03-11 lpd Corrected argument list for main(), and added int return
icculus@0
    48
	type, in test program and T value program.
icculus@0
    49
  2002-02-21 lpd Added missing #include <stdio.h> in test program.
icculus@0
    50
  2000-07-03 lpd Patched to eliminate warnings about "constant is
icculus@0
    51
	unsigned in ANSI C, signed in traditional"; made test program
icculus@0
    52
	self-checking.
icculus@0
    53
  1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
icculus@0
    54
  1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
icculus@0
    55
  1999-05-03 lpd Original version.
icculus@0
    56
 */
icculus@0
    57
icculus@0
    58
#include <string.h>
icculus@0
    59
icculus@0
    60
#include "md5.h"
icculus@0
    61
icculus@0
    62
#undef BYTE_ORDER	/* 1 = big-endian, -1 = little-endian, 0 = unknown */
icculus@0
    63
//#ifdef ARCH_IS_BIG_ENDIAN
icculus@0
    64
//#  define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
icculus@0
    65
//#else
icculus@0
    66
//#  define BYTE_ORDER 0
icculus@0
    67
//#endif
icculus@0
    68
#if PLATFORM_BIGENDIAN
icculus@0
    69
#  define BYTE_ORDER 1
icculus@0
    70
#else
icculus@0
    71
#  define BYTE_ORDER -1
icculus@0
    72
#endif
icculus@0
    73
icculus@0
    74
#define T_MASK ((uint32_t)~0)
icculus@0
    75
#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
icculus@0
    76
#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
icculus@0
    77
#define T3    0x242070db
icculus@0
    78
#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
icculus@0
    79
#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
icculus@0
    80
#define T6    0x4787c62a
icculus@0
    81
#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
icculus@0
    82
#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
icculus@0
    83
#define T9    0x698098d8
icculus@0
    84
#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
icculus@0
    85
#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
icculus@0
    86
#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
icculus@0
    87
#define T13    0x6b901122
icculus@0
    88
#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
icculus@0
    89
#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
icculus@0
    90
#define T16    0x49b40821
icculus@0
    91
#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
icculus@0
    92
#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
icculus@0
    93
#define T19    0x265e5a51
icculus@0
    94
#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
icculus@0
    95
#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
icculus@0
    96
#define T22    0x02441453
icculus@0
    97
#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
icculus@0
    98
#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
icculus@0
    99
#define T25    0x21e1cde6
icculus@0
   100
#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
icculus@0
   101
#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
icculus@0
   102
#define T28    0x455a14ed
icculus@0
   103
#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
icculus@0
   104
#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
icculus@0
   105
#define T31    0x676f02d9
icculus@0
   106
#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
icculus@0
   107
#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
icculus@0
   108
#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
icculus@0
   109
#define T35    0x6d9d6122
icculus@0
   110
#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
icculus@0
   111
#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
icculus@0
   112
#define T38    0x4bdecfa9
icculus@0
   113
#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
icculus@0
   114
#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
icculus@0
   115
#define T41    0x289b7ec6
icculus@0
   116
#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
icculus@0
   117
#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
icculus@0
   118
#define T44    0x04881d05
icculus@0
   119
#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
icculus@0
   120
#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
icculus@0
   121
#define T47    0x1fa27cf8
icculus@0
   122
#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
icculus@0
   123
#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
icculus@0
   124
#define T50    0x432aff97
icculus@0
   125
#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
icculus@0
   126
#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
icculus@0
   127
#define T53    0x655b59c3
icculus@0
   128
#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
icculus@0
   129
#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
icculus@0
   130
#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
icculus@0
   131
#define T57    0x6fa87e4f
icculus@0
   132
#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
icculus@0
   133
#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
icculus@0
   134
#define T60    0x4e0811a1
icculus@0
   135
#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
icculus@0
   136
#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
icculus@0
   137
#define T63    0x2ad7d2bb
icculus@0
   138
#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
icculus@0
   139
icculus@0
   140
icculus@0
   141
static void
icculus@0
   142
MD5_process(MD5_CTX *pms, const uint8_t *data /*[64]*/)
icculus@0
   143
{
icculus@0
   144
    uint32_t
icculus@0
   145
	a = pms->abcd[0], b = pms->abcd[1],
icculus@0
   146
	c = pms->abcd[2], d = pms->abcd[3];
icculus@0
   147
    uint32_t t;
icculus@0
   148
#if BYTE_ORDER > 0
icculus@0
   149
    /* Define storage only for big-endian CPUs. */
icculus@0
   150
    uint32_t X[16];
icculus@0
   151
#else
icculus@0
   152
    /* Define storage for little-endian or both types of CPUs. */
icculus@0
   153
    uint32_t xbuf[16];
icculus@0
   154
    const uint32_t *X;
icculus@0
   155
#endif
icculus@0
   156
icculus@0
   157
    {
icculus@0
   158
#if BYTE_ORDER == 0
icculus@0
   159
	/*
icculus@0
   160
	 * Determine dynamically whether this is a big-endian or
icculus@0
   161
	 * little-endian machine, since we can use a more efficient
icculus@0
   162
	 * algorithm on the latter.
icculus@0
   163
	 */
icculus@0
   164
	static const int w = 1;
icculus@0
   165
icculus@0
   166
	if (*((const uint8_t *)&w)) /* dynamic little-endian */
icculus@0
   167
#endif
icculus@0
   168
#if BYTE_ORDER <= 0		/* little-endian */
icculus@0
   169
	{
icculus@0
   170
	    /*
icculus@0
   171
	     * On little-endian machines, we can process properly aligned
icculus@0
   172
	     * data without copying it.
icculus@0
   173
	     */
icculus@0
   174
	    if (!((data - (const uint8_t *)0) & 3)) {
icculus@0
   175
		/* data are properly aligned */
icculus@0
   176
		X = (const uint32_t *)data;
icculus@0
   177
	    } else {
icculus@0
   178
		/* not aligned */
icculus@0
   179
		memcpy(xbuf, data, 64);
icculus@0
   180
		X = xbuf;
icculus@0
   181
	    }
icculus@0
   182
	}
icculus@0
   183
#endif
icculus@0
   184
#if BYTE_ORDER == 0
icculus@0
   185
	else			/* dynamic big-endian */
icculus@0
   186
#endif
icculus@0
   187
#if BYTE_ORDER >= 0		/* big-endian */
icculus@0
   188
	{
icculus@0
   189
	    /*
icculus@0
   190
	     * On big-endian machines, we must arrange the bytes in the
icculus@0
   191
	     * right order.
icculus@0
   192
	     */
icculus@0
   193
	    const uint8_t *xp = data;
icculus@0
   194
	    int i;
icculus@0
   195
icculus@0
   196
#  if BYTE_ORDER == 0
icculus@0
   197
	    X = xbuf;		/* (dynamic only) */
icculus@0
   198
#  else
icculus@0
   199
#    define xbuf X		/* (static only) */
icculus@0
   200
#  endif
icculus@0
   201
	    for (i = 0; i < 16; ++i, xp += 4)
icculus@0
   202
		xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
icculus@0
   203
	}
icculus@0
   204
#endif
icculus@0
   205
    }
icculus@0
   206
icculus@0
   207
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
icculus@0
   208
icculus@0
   209
    /* Round 1. */
icculus@0
   210
    /* Let [abcd k s i] denote the operation
icculus@0
   211
       a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
icculus@0
   212
#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
icculus@0
   213
#define SET(a, b, c, d, k, s, Ti)\
icculus@0
   214
  t = a + F(b,c,d) + X[k] + Ti;\
icculus@0
   215
  a = ROTATE_LEFT(t, s) + b
icculus@0
   216
    /* Do the following 16 operations. */
icculus@0
   217
    SET(a, b, c, d,  0,  7,  T1);
icculus@0
   218
    SET(d, a, b, c,  1, 12,  T2);
icculus@0
   219
    SET(c, d, a, b,  2, 17,  T3);
icculus@0
   220
    SET(b, c, d, a,  3, 22,  T4);
icculus@0
   221
    SET(a, b, c, d,  4,  7,  T5);
icculus@0
   222
    SET(d, a, b, c,  5, 12,  T6);
icculus@0
   223
    SET(c, d, a, b,  6, 17,  T7);
icculus@0
   224
    SET(b, c, d, a,  7, 22,  T8);
icculus@0
   225
    SET(a, b, c, d,  8,  7,  T9);
icculus@0
   226
    SET(d, a, b, c,  9, 12, T10);
icculus@0
   227
    SET(c, d, a, b, 10, 17, T11);
icculus@0
   228
    SET(b, c, d, a, 11, 22, T12);
icculus@0
   229
    SET(a, b, c, d, 12,  7, T13);
icculus@0
   230
    SET(d, a, b, c, 13, 12, T14);
icculus@0
   231
    SET(c, d, a, b, 14, 17, T15);
icculus@0
   232
    SET(b, c, d, a, 15, 22, T16);
icculus@0
   233
#undef SET
icculus@0
   234
icculus@0
   235
     /* Round 2. */
icculus@0
   236
     /* Let [abcd k s i] denote the operation
icculus@0
   237
          a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
icculus@0
   238
#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
icculus@0
   239
#define SET(a, b, c, d, k, s, Ti)\
icculus@0
   240
  t = a + G(b,c,d) + X[k] + Ti;\
icculus@0
   241
  a = ROTATE_LEFT(t, s) + b
icculus@0
   242
     /* Do the following 16 operations. */
icculus@0
   243
    SET(a, b, c, d,  1,  5, T17);
icculus@0
   244
    SET(d, a, b, c,  6,  9, T18);
icculus@0
   245
    SET(c, d, a, b, 11, 14, T19);
icculus@0
   246
    SET(b, c, d, a,  0, 20, T20);
icculus@0
   247
    SET(a, b, c, d,  5,  5, T21);
icculus@0
   248
    SET(d, a, b, c, 10,  9, T22);
icculus@0
   249
    SET(c, d, a, b, 15, 14, T23);
icculus@0
   250
    SET(b, c, d, a,  4, 20, T24);
icculus@0
   251
    SET(a, b, c, d,  9,  5, T25);
icculus@0
   252
    SET(d, a, b, c, 14,  9, T26);
icculus@0
   253
    SET(c, d, a, b,  3, 14, T27);
icculus@0
   254
    SET(b, c, d, a,  8, 20, T28);
icculus@0
   255
    SET(a, b, c, d, 13,  5, T29);
icculus@0
   256
    SET(d, a, b, c,  2,  9, T30);
icculus@0
   257
    SET(c, d, a, b,  7, 14, T31);
icculus@0
   258
    SET(b, c, d, a, 12, 20, T32);
icculus@0
   259
#undef SET
icculus@0
   260
icculus@0
   261
     /* Round 3. */
icculus@0
   262
     /* Let [abcd k s t] denote the operation
icculus@0
   263
          a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
icculus@0
   264
#define H(x, y, z) ((x) ^ (y) ^ (z))
icculus@0
   265
#define SET(a, b, c, d, k, s, Ti)\
icculus@0
   266
  t = a + H(b,c,d) + X[k] + Ti;\
icculus@0
   267
  a = ROTATE_LEFT(t, s) + b
icculus@0
   268
     /* Do the following 16 operations. */
icculus@0
   269
    SET(a, b, c, d,  5,  4, T33);
icculus@0
   270
    SET(d, a, b, c,  8, 11, T34);
icculus@0
   271
    SET(c, d, a, b, 11, 16, T35);
icculus@0
   272
    SET(b, c, d, a, 14, 23, T36);
icculus@0
   273
    SET(a, b, c, d,  1,  4, T37);
icculus@0
   274
    SET(d, a, b, c,  4, 11, T38);
icculus@0
   275
    SET(c, d, a, b,  7, 16, T39);
icculus@0
   276
    SET(b, c, d, a, 10, 23, T40);
icculus@0
   277
    SET(a, b, c, d, 13,  4, T41);
icculus@0
   278
    SET(d, a, b, c,  0, 11, T42);
icculus@0
   279
    SET(c, d, a, b,  3, 16, T43);
icculus@0
   280
    SET(b, c, d, a,  6, 23, T44);
icculus@0
   281
    SET(a, b, c, d,  9,  4, T45);
icculus@0
   282
    SET(d, a, b, c, 12, 11, T46);
icculus@0
   283
    SET(c, d, a, b, 15, 16, T47);
icculus@0
   284
    SET(b, c, d, a,  2, 23, T48);
icculus@0
   285
#undef SET
icculus@0
   286
icculus@0
   287
     /* Round 4. */
icculus@0
   288
     /* Let [abcd k s t] denote the operation
icculus@0
   289
          a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
icculus@0
   290
#define I(x, y, z) ((y) ^ ((x) | ~(z)))
icculus@0
   291
#define SET(a, b, c, d, k, s, Ti)\
icculus@0
   292
  t = a + I(b,c,d) + X[k] + Ti;\
icculus@0
   293
  a = ROTATE_LEFT(t, s) + b
icculus@0
   294
     /* Do the following 16 operations. */
icculus@0
   295
    SET(a, b, c, d,  0,  6, T49);
icculus@0
   296
    SET(d, a, b, c,  7, 10, T50);
icculus@0
   297
    SET(c, d, a, b, 14, 15, T51);
icculus@0
   298
    SET(b, c, d, a,  5, 21, T52);
icculus@0
   299
    SET(a, b, c, d, 12,  6, T53);
icculus@0
   300
    SET(d, a, b, c,  3, 10, T54);
icculus@0
   301
    SET(c, d, a, b, 10, 15, T55);
icculus@0
   302
    SET(b, c, d, a,  1, 21, T56);
icculus@0
   303
    SET(a, b, c, d,  8,  6, T57);
icculus@0
   304
    SET(d, a, b, c, 15, 10, T58);
icculus@0
   305
    SET(c, d, a, b,  6, 15, T59);
icculus@0
   306
    SET(b, c, d, a, 13, 21, T60);
icculus@0
   307
    SET(a, b, c, d,  4,  6, T61);
icculus@0
   308
    SET(d, a, b, c, 11, 10, T62);
icculus@0
   309
    SET(c, d, a, b,  2, 15, T63);
icculus@0
   310
    SET(b, c, d, a,  9, 21, T64);
icculus@0
   311
#undef SET
icculus@0
   312
icculus@0
   313
     /* Then perform the following additions. (That is increment each
icculus@0
   314
        of the four registers by the value it had before this block
icculus@0
   315
        was started.) */
icculus@0
   316
    pms->abcd[0] += a;
icculus@0
   317
    pms->abcd[1] += b;
icculus@0
   318
    pms->abcd[2] += c;
icculus@0
   319
    pms->abcd[3] += d;
icculus@0
   320
}
icculus@0
   321
icculus@0
   322
void
icculus@0
   323
MD5_init(MD5_CTX *pms)
icculus@0
   324
{
icculus@0
   325
    pms->count[0] = pms->count[1] = 0;
icculus@0
   326
    pms->abcd[0] = 0x67452301;
icculus@0
   327
    pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
icculus@0
   328
    pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
icculus@0
   329
    pms->abcd[3] = 0x10325476;
icculus@0
   330
}
icculus@0
   331
icculus@0
   332
void
icculus@0
   333
MD5_append(MD5_CTX *pms, const uint8_t *data, int nbytes)
icculus@0
   334
{
icculus@0
   335
    const uint8_t *p = data;
icculus@0
   336
    int left = nbytes;
icculus@0
   337
    int offset = (pms->count[0] >> 3) & 63;
icculus@0
   338
    uint32_t nbits = (uint32_t)(nbytes << 3);
icculus@0
   339
icculus@0
   340
    if (nbytes <= 0)
icculus@0
   341
	return;
icculus@0
   342
icculus@0
   343
    /* Update the message length. */
icculus@0
   344
    pms->count[1] += nbytes >> 29;
icculus@0
   345
    pms->count[0] += nbits;
icculus@0
   346
    if (pms->count[0] < nbits)
icculus@0
   347
	pms->count[1]++;
icculus@0
   348
icculus@0
   349
    /* Process an initial partial block. */
icculus@0
   350
    if (offset) {
icculus@0
   351
	int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
icculus@0
   352
icculus@0
   353
	memcpy(pms->buf + offset, p, copy);
icculus@0
   354
	if (offset + copy < 64)
icculus@0
   355
	    return;
icculus@0
   356
	p += copy;
icculus@0
   357
	left -= copy;
icculus@0
   358
	MD5_process(pms, pms->buf);
icculus@0
   359
    }
icculus@0
   360
icculus@0
   361
    /* Process full blocks. */
icculus@0
   362
    for (; left >= 64; p += 64, left -= 64)
icculus@0
   363
	MD5_process(pms, p);
icculus@0
   364
icculus@0
   365
    /* Process a final partial block. */
icculus@0
   366
    if (left)
icculus@0
   367
	memcpy(pms->buf, p, left);
icculus@0
   368
}
icculus@0
   369
icculus@0
   370
void
icculus@0
   371
MD5_finish(MD5_CTX *pms, uint8_t digest[16])
icculus@0
   372
{
icculus@0
   373
    const uint8_t pad[64] = {
icculus@0
   374
	0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
icculus@0
   375
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
icculus@0
   376
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
icculus@0
   377
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
icculus@0
   378
    };
icculus@0
   379
    uint8_t data[8];
icculus@0
   380
    int i;
icculus@0
   381
icculus@0
   382
    /* Save the length before padding. */
icculus@0
   383
    for (i = 0; i < 8; ++i)
icculus@0
   384
	data[i] = (uint8_t)(pms->count[i >> 2] >> ((i & 3) << 3));
icculus@0
   385
    /* Pad to 56 bytes mod 64. */
icculus@0
   386
    MD5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
icculus@0
   387
    /* Append the length. */
icculus@0
   388
    MD5_append(pms, data, 8);
icculus@0
   389
    for (i = 0; i < 16; ++i)
icculus@0
   390
	digest[i] = (uint8_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
icculus@0
   391
}
icculus@0
   392
icculus@0
   393
// end of md5.c ...
icculus@0
   394