md5.c 3.94 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/* 
 * Cryptographic API.
 *
 * MD5 Message Digest Algorithm (RFC1321).
 *
 * Derived from cryptoapi implementation, originally based on the
 * public domain implementation written by Colin Plumb in 1993.
 *
 * Copyright (c) Cryptoapi developers.
 * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
 * 
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option) 
 * any later version.
 *
 */
18
#include <crypto/internal/hash.h>
Max Vozeler's avatar
Max Vozeler committed
19
#include <crypto/md5.h>
Linus Torvalds's avatar
Linus Torvalds committed
20 21 22
#include <linux/init.h>
#include <linux/module.h>
#include <linux/string.h>
23
#include <linux/types.h>
24
#include <linux/cryptohash.h>
Linus Torvalds's avatar
Linus Torvalds committed
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
#include <asm/byteorder.h>

/* XXX: this stuff can be optimized */
static inline void le32_to_cpu_array(u32 *buf, unsigned int words)
{
	while (words--) {
		__le32_to_cpus(buf);
		buf++;
	}
}

static inline void cpu_to_le32_array(u32 *buf, unsigned int words)
{
	while (words--) {
		__cpu_to_le32s(buf);
		buf++;
	}
}

Max Vozeler's avatar
Max Vozeler committed
44
static inline void md5_transform_helper(struct md5_state *ctx)
Linus Torvalds's avatar
Linus Torvalds committed
45 46 47 48 49
{
	le32_to_cpu_array(ctx->block, sizeof(ctx->block) / sizeof(u32));
	md5_transform(ctx->hash, ctx->block);
}

50
static int md5_init(struct shash_desc *desc)
Linus Torvalds's avatar
Linus Torvalds committed
51
{
Max Vozeler's avatar
Max Vozeler committed
52
	struct md5_state *mctx = shash_desc_ctx(desc);
Linus Torvalds's avatar
Linus Torvalds committed
53 54 55 56 57 58

	mctx->hash[0] = 0x67452301;
	mctx->hash[1] = 0xefcdab89;
	mctx->hash[2] = 0x98badcfe;
	mctx->hash[3] = 0x10325476;
	mctx->byte_count = 0;
59 60

	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
61 62
}

63
static int md5_update(struct shash_desc *desc, const u8 *data, unsigned int len)
Linus Torvalds's avatar
Linus Torvalds committed
64
{
Max Vozeler's avatar
Max Vozeler committed
65
	struct md5_state *mctx = shash_desc_ctx(desc);
Linus Torvalds's avatar
Linus Torvalds committed
66 67 68 69 70 71 72
	const u32 avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f);

	mctx->byte_count += len;

	if (avail > len) {
		memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
		       data, len);
73
		return 0;
Linus Torvalds's avatar
Linus Torvalds committed
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
	}

	memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
	       data, avail);

	md5_transform_helper(mctx);
	data += avail;
	len -= avail;

	while (len >= sizeof(mctx->block)) {
		memcpy(mctx->block, data, sizeof(mctx->block));
		md5_transform_helper(mctx);
		data += sizeof(mctx->block);
		len -= sizeof(mctx->block);
	}

	memcpy(mctx->block, data, len);
91 92

	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
93 94
}

95
static int md5_final(struct shash_desc *desc, u8 *out)
Linus Torvalds's avatar
Linus Torvalds committed
96
{
Max Vozeler's avatar
Max Vozeler committed
97
	struct md5_state *mctx = shash_desc_ctx(desc);
Linus Torvalds's avatar
Linus Torvalds committed
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
	const unsigned int offset = mctx->byte_count & 0x3f;
	char *p = (char *)mctx->block + offset;
	int padding = 56 - (offset + 1);

	*p++ = 0x80;
	if (padding < 0) {
		memset(p, 0x00, padding + sizeof (u64));
		md5_transform_helper(mctx);
		p = (char *)mctx->block;
		padding = 56;
	}

	memset(p, 0, padding);
	mctx->block[14] = mctx->byte_count << 3;
	mctx->block[15] = mctx->byte_count >> 29;
	le32_to_cpu_array(mctx->block, (sizeof(mctx->block) -
	                  sizeof(u64)) / sizeof(u32));
	md5_transform(mctx->hash, mctx->block);
	cpu_to_le32_array(mctx->hash, sizeof(mctx->hash) / sizeof(u32));
	memcpy(out, mctx->hash, sizeof(mctx->hash));
	memset(mctx, 0, sizeof(*mctx));
119 120

	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
121 122
}

Max Vozeler's avatar
Max Vozeler committed
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
static int md5_export(struct shash_desc *desc, void *out)
{
	struct md5_state *ctx = shash_desc_ctx(desc);

	memcpy(out, ctx, sizeof(*ctx));
	return 0;
}

static int md5_import(struct shash_desc *desc, const void *in)
{
	struct md5_state *ctx = shash_desc_ctx(desc);

	memcpy(ctx, in, sizeof(*ctx));
	return 0;
}

139 140 141 142 143
static struct shash_alg alg = {
	.digestsize	=	MD5_DIGEST_SIZE,
	.init		=	md5_init,
	.update		=	md5_update,
	.final		=	md5_final,
Max Vozeler's avatar
Max Vozeler committed
144 145 146
	.export		=	md5_export,
	.import		=	md5_import,
	.descsize	=	sizeof(struct md5_state),
Herbert Xu's avatar
Herbert Xu committed
147
	.statesize	=	sizeof(struct md5_state),
148 149 150 151 152 153
	.base		=	{
		.cra_name	=	"md5",
		.cra_flags	=	CRYPTO_ALG_TYPE_SHASH,
		.cra_blocksize	=	MD5_HMAC_BLOCK_SIZE,
		.cra_module	=	THIS_MODULE,
	}
Linus Torvalds's avatar
Linus Torvalds committed
154 155
};

156
static int __init md5_mod_init(void)
Linus Torvalds's avatar
Linus Torvalds committed
157
{
158
	return crypto_register_shash(&alg);
Linus Torvalds's avatar
Linus Torvalds committed
159 160
}

161
static void __exit md5_mod_fini(void)
Linus Torvalds's avatar
Linus Torvalds committed
162
{
163
	crypto_unregister_shash(&alg);
Linus Torvalds's avatar
Linus Torvalds committed
164 165
}

166 167
module_init(md5_mod_init);
module_exit(md5_mod_fini);
Linus Torvalds's avatar
Linus Torvalds committed
168 169 170

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("MD5 Message Digest Algorithm");