Created
August 7, 2014 13:23
-
-
Save kaworu/3dbefcdca9d8972a3d9c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* md2.c | |
* | |
* "Naive" [MD2](https://tools.ietf.org/html/rfc1319)) implementation for | |
* self-educating purpose, please do *not* use it. | |
* | |
* License: CC0, see https://creativecommons.org/publicdomain/zero/1.0/ | |
*/ | |
#include <assert.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <strings.h> | |
struct md2_ctx { | |
unsigned char checksum[16]; | |
unsigned char state[16]; | |
unsigned char chunk[16]; | |
size_t clen; /* current chunk data length */ | |
}; | |
void md2_ctx_init(struct md2_ctx *ctx); | |
void md2_ctx_feed(struct md2_ctx *ctx, const unsigned char *buf, size_t buflen); | |
void md2_ctx_finalize(struct md2_ctx *ctx, unsigned char *digest); | |
/** | |
* read stdin to feed the md2_ctx, output the digest (in hex) on stdout. | |
*/ | |
int | |
main(int argc, char **argv) | |
{ | |
struct md2_ctx ctx; | |
unsigned char buf[BUFSIZ]; | |
unsigned char digest[16]; | |
size_t len; | |
md2_ctx_init(&ctx); | |
while ((len = fread(buf, 1, sizeof(buf), stdin))) { | |
md2_ctx_feed(&ctx, buf, len); | |
} | |
if (ferror(stdin) != 0) | |
return (EXIT_FAILURE); | |
md2_ctx_finalize(&ctx, digest); | |
for (int i = 0; i < 16; i++) | |
(void)printf("%02x", digest[i]); | |
(void)printf("\n"); | |
return (EXIT_SUCCESS); | |
} | |
/* Taken from https://en.wikipedia.org/wiki/MD2_(cryptography) */ | |
static const unsigned char SBox[256] = { | |
0x29, 0x2E, 0x43, 0xC9, 0xA2, 0xD8, 0x7C, 0x01, 0x3D, 0x36, 0x54, 0xA1, 0xEC, 0xF0, 0x06, 0x13, | |
0x62, 0xA7, 0x05, 0xF3, 0xC0, 0xC7, 0x73, 0x8C, 0x98, 0x93, 0x2B, 0xD9, 0xBC, 0x4C, 0x82, 0xCA, | |
0x1E, 0x9B, 0x57, 0x3C, 0xFD, 0xD4, 0xE0, 0x16, 0x67, 0x42, 0x6F, 0x18, 0x8A, 0x17, 0xE5, 0x12, | |
0xBE, 0x4E, 0xC4, 0xD6, 0xDA, 0x9E, 0xDE, 0x49, 0xA0, 0xFB, 0xF5, 0x8E, 0xBB, 0x2F, 0xEE, 0x7A, | |
0xA9, 0x68, 0x79, 0x91, 0x15, 0xB2, 0x07, 0x3F, 0x94, 0xC2, 0x10, 0x89, 0x0B, 0x22, 0x5F, 0x21, | |
0x80, 0x7F, 0x5D, 0x9A, 0x5A, 0x90, 0x32, 0x27, 0x35, 0x3E, 0xCC, 0xE7, 0xBF, 0xF7, 0x97, 0x03, | |
0xFF, 0x19, 0x30, 0xB3, 0x48, 0xA5, 0xB5, 0xD1, 0xD7, 0x5E, 0x92, 0x2A, 0xAC, 0x56, 0xAA, 0xC6, | |
0x4F, 0xB8, 0x38, 0xD2, 0x96, 0xA4, 0x7D, 0xB6, 0x76, 0xFC, 0x6B, 0xE2, 0x9C, 0x74, 0x04, 0xF1, | |
0x45, 0x9D, 0x70, 0x59, 0x64, 0x71, 0x87, 0x20, 0x86, 0x5B, 0xCF, 0x65, 0xE6, 0x2D, 0xA8, 0x02, | |
0x1B, 0x60, 0x25, 0xAD, 0xAE, 0xB0, 0xB9, 0xF6, 0x1C, 0x46, 0x61, 0x69, 0x34, 0x40, 0x7E, 0x0F, | |
0x55, 0x47, 0xA3, 0x23, 0xDD, 0x51, 0xAF, 0x3A, 0xC3, 0x5C, 0xF9, 0xCE, 0xBA, 0xC5, 0xEA, 0x26, | |
0x2C, 0x53, 0x0D, 0x6E, 0x85, 0x28, 0x84, 0x09, 0xD3, 0xDF, 0xCD, 0xF4, 0x41, 0x81, 0x4D, 0x52, | |
0x6A, 0xDC, 0x37, 0xC8, 0x6C, 0xC1, 0xAB, 0xFA, 0x24, 0xE1, 0x7B, 0x08, 0x0C, 0xBD, 0xB1, 0x4A, | |
0x78, 0x88, 0x95, 0x8B, 0xE3, 0x63, 0xE8, 0x6D, 0xE9, 0xCB, 0xD5, 0xFE, 0x3B, 0x00, 0x1D, 0x39, | |
0xF2, 0xEF, 0xB7, 0x0E, 0x66, 0x58, 0xD0, 0xE4, 0xA6, 0x77, 0x72, 0xF8, 0xEB, 0x75, 0x4B, 0x0A, | |
0x31, 0x44, 0x50, 0xB4, 0x8F, 0xED, 0x1F, 0x1A, 0xDB, 0x99, 0x8D, 0x33, 0x9F, 0x11, 0x83, 0x14, | |
}; | |
static void md2_ctx_update(struct md2_ctx *ctx); | |
/** | |
* reset a md2_ctx state | |
*/ | |
void | |
md2_ctx_init(struct md2_ctx *ctx) | |
{ | |
assert(ctx != NULL); | |
bzero(ctx->checksum, sizeof(ctx->checksum)); | |
bzero(ctx->state, sizeof(ctx->state)); | |
ctx->clen = 0; | |
} | |
/** | |
* consume the input data in buf, call md2_ctx_update() for each chunk of 16 | |
* bytes available. | |
*/ | |
void | |
md2_ctx_feed(struct md2_ctx *ctx, const unsigned char *buf, size_t buflen) | |
{ | |
assert(ctx != NULL); | |
assert(buf != NULL); | |
for (const unsigned char *c = buf; c < buf + buflen; ++c) { | |
ctx->chunk[ctx->clen++] = *c; | |
if (ctx->clen == 16) | |
md2_ctx_update(ctx); | |
} | |
} | |
void | |
md2_ctx_update(struct md2_ctx *ctx) | |
{ | |
assert(ctx != NULL); | |
assert(ctx->clen == 16); | |
/* checksum update */ | |
unsigned char prev = ctx->checksum[15]; | |
for (int i = 0; i < 16; i++) { | |
ctx->checksum[i] ^= SBox[prev ^ ctx->chunk[i]]; | |
prev = ctx->checksum[i]; | |
} | |
/* state update */ | |
unsigned char x[48]; | |
/* x is: [ MD intermediate || chunk || MD intermediate XOR chunk ] */ | |
(void)memcpy(x, ctx->state, 16); | |
(void)memcpy(x + 16, ctx->chunk, 16); | |
for (int i = 0; i < 16; i++) | |
x[32 + i] = ctx->state[i] ^ ctx->chunk[i]; | |
unsigned char t = 0; | |
for (int p = 0; p < 18; p++) { /* 18 passes */ | |
for (int i = 0; i < 48; i++) { | |
t = x[i] = x[i] ^ SBox[t]; | |
} | |
t = (t + p) % 256; | |
} | |
(void)memcpy(ctx->state, x, 16); | |
bzero(x, sizeof(x)); /* XXX: should be explicit_bzero() */ | |
ctx->clen = 0; | |
} | |
/** | |
* finalize a md2_ctx after all data have been feeded. Add the padding, add the | |
* checksum and update the md. digest length MUST be at least 16. | |
*/ | |
void | |
md2_ctx_finalize(struct md2_ctx *ctx, unsigned char *digest) | |
{ | |
assert(ctx != NULL); | |
/* Append Padding Bytes §3.1 */ | |
unsigned char padlen = 16 - ctx->clen; | |
for (int i = 0; i < padlen; i++) | |
ctx->chunk[ctx->clen++] = padlen; | |
md2_ctx_update(ctx); | |
/* Append Checksum §3.2 */ | |
(void)memcpy(ctx->chunk, ctx->checksum, 16); | |
ctx->clen = 16; | |
md2_ctx_update(ctx); | |
(void)memcpy(digest, ctx->state, 16); | |
bzero(ctx, sizeof(struct md2_ctx)); /* XXX: should be explicit_bzero() */ | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment