2 * $Id: md5lib.c,v 1.2 2003/04/28 16:25:44 roberto Exp $
3 * Cryptographic and Hash functions for Lua
5 * @author Roberto Ierusalimschy
20 * Hash function. Returns a hash for a given string.
21 * @param message: arbitrary binary string.
22 * @return A 128-bit hash string.
24 static int lmd5 (lua_State
*L
) {
27 const char *message
= luaL_checklstring(L
, 1, &l
);
28 md5(message
, l
, buff
);
29 lua_pushlstring(L
, buff
, 16L);
35 * X-Or. Does a bit-a-bit exclusive-or of two strings.
36 * @param s1: arbitrary binary string.
37 * @param s2: arbitrary binary string with same length as s1.
38 * @return a binary string with same length as s1 and s2,
39 * where each bit is the exclusive-or of the corresponding bits in s1-s2.
41 static int ex_or (lua_State
*L
) {
43 const char *s1
= luaL_checklstring(L
, 1, &l1
);
44 const char *s2
= luaL_checklstring(L
, 2, &l2
);
46 luaL_argcheck( L
, l1
== l2
, 2, "lengths must be equal" );
48 while (l1
--) luaL_addchar(&b
, (*s1
++)^(*s2
++));
54 static void checkseed (lua_State
*L
) {
55 if (lua_isnone(L
, 3)) { /* no seed? */
56 time_t tm
= time(NULL
); /* for `random' seed */
57 lua_pushlstring(L
, (char *)&tm
, sizeof(tm
));
67 static int initblock (lua_State
*L
, const char *seed
, int lseed
, char *block
) {
69 const char *key
= luaL_checklstring(L
, 2, &lkey
);
71 luaL_error(L
, "key too long (> %d)", MAXKEY
);
72 memset(block
, 0, BLOCKSIZE
);
73 memcpy(block
, seed
, lseed
);
74 memcpy(block
+BLOCKSIZE
, key
, lkey
);
75 return (int)lkey
+BLOCKSIZE
;
79 static void codestream (lua_State
*L
, const char *msg
, size_t lmsg
,
80 char *block
, int lblock
) {
86 md5(block
, lblock
, code
);
87 for (i
=0; i
<BLOCKSIZE
&& lmsg
> 0; i
++, lmsg
--)
89 luaL_addlstring(&b
, code
, i
);
90 memcpy(block
, code
, i
); /* update seed */
96 static void decodestream (lua_State
*L
, const char *cypher
, size_t lcypher
,
97 char *block
, int lblock
) {
100 while (lcypher
> 0) {
101 char code
[BLOCKSIZE
];
103 md5(block
, lblock
, code
); /* update seed */
104 for (i
=0; i
<BLOCKSIZE
&& lcypher
> 0; i
++, lcypher
--)
105 code
[i
] ^= *cypher
++;
106 luaL_addlstring(&b
, code
, i
);
107 memcpy(block
, cypher
-i
, i
);
114 * Encrypts a string. Uses the hash function md5 in CFB (Cipher-feedback
116 * @param message: arbitrary binary string to be encrypted.
117 * @param key: arbitrary binary string to be used as a key.
118 * @param [seed]: optional arbitrary binary string to be used as a seed.
119 * if no seed is provided, the function uses the result of
120 * <code>time()</code> as a seed.
121 * @return The cyphertext (as a binary string).
123 static int crypt (lua_State
*L
) {
125 const char *msg
= luaL_checklstring(L
, 1, &lmsg
);
129 char block
[BLOCKSIZE
+MAXKEY
];
131 seed
= luaL_checklstring(L
, 3, &lseed
);
132 if (lseed
> BLOCKSIZE
)
133 luaL_error(L
, "seed too long (> %d)", BLOCKSIZE
);
134 /* put seed and seed length at the beginning of result */
135 block
[0] = (char)lseed
;
136 memcpy(block
+1, seed
, lseed
);
137 lua_pushlstring(L
, block
, lseed
+1); /* to concat with result */
138 lblock
= initblock(L
, seed
, lseed
, block
);
139 codestream(L
, msg
, lmsg
, block
, lblock
);
146 * Decrypts a string. For any message, key, and seed, we have that
147 * <code>decrypt(crypt(msg, key, seed), key) == msg</code>.
148 * @param cyphertext: message to be decrypted (this must be the result of
149 a previous call to <code>crypt</code>.
150 * @param key: arbitrary binary string to be used as a key.
151 * @return The plaintext.
153 static int decrypt (lua_State
*L
) {
155 const char *cyphertext
= luaL_checklstring(L
, 1, &lcyphertext
);
156 size_t lseed
= cyphertext
[0];
157 const char *seed
= cyphertext
+1;
159 char block
[BLOCKSIZE
+MAXKEY
];
160 luaL_argcheck(L
, lcyphertext
>= lseed
+1 && lseed
<= BLOCKSIZE
, 1,
161 "invalid cyphered string");
162 cyphertext
+= lseed
+1;
163 lcyphertext
-= lseed
+1;
164 lblock
= initblock(L
, seed
, lseed
, block
);
165 decodestream(L
, cyphertext
, lcyphertext
, block
, lblock
);
170 static struct luaL_Reg md5lib
[] = {
174 {"decrypt", decrypt
},
179 int luaopen_md5 (lua_State
*L
) {
180 luaL_openlib(L
, "md5", md5lib
, 0);