mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Added MD5 and crypto::safe_compare.
This commit is contained in:
@@ -1,2 +1,12 @@
|
||||
module std::crypto;
|
||||
|
||||
fn bool safe_compare(void* data1, void* data2, usz len)
|
||||
{
|
||||
char match = 0;
|
||||
for (usz i = 0; i < len; i++)
|
||||
{
|
||||
match = match | (mem::@volatile_load(((char*)data1)[i]) ^ mem::@volatile_load(((char*)data2)[i]));
|
||||
}
|
||||
return match == 0;
|
||||
}
|
||||
|
||||
|
||||
217
lib/std/hash/md5.c3
Normal file
217
lib/std/hash/md5.c3
Normal file
@@ -0,0 +1,217 @@
|
||||
module std::hash::md5;
|
||||
import std::bits;
|
||||
|
||||
struct Md5
|
||||
{
|
||||
uint lo, hi;
|
||||
uint a, b, c, d;
|
||||
char[64] buffer;
|
||||
uint[16] block;
|
||||
}
|
||||
|
||||
fn char[16] hash(char[] data)
|
||||
{
|
||||
Md5 md5;
|
||||
md5.init();
|
||||
md5.update(data);
|
||||
return md5.final();
|
||||
}
|
||||
|
||||
fn void Md5.init(&self)
|
||||
{
|
||||
self.a = 0x67452301;
|
||||
self.b = 0xefcdab89;
|
||||
self.c = 0x98badcfe;
|
||||
self.d = 0x10325476;
|
||||
|
||||
self.lo = 0;
|
||||
self.hi = 0;
|
||||
}
|
||||
|
||||
|
||||
fn void Md5.update(&ctx, char[] data)
|
||||
{
|
||||
uint saved_lo = ctx.lo;
|
||||
if ((ctx.lo = (saved_lo + data.len) & 0x1fffffff) < saved_lo) ctx.hi++;
|
||||
ctx.hi += data.len >> 29;
|
||||
|
||||
usz used = (usz)saved_lo & 0x3f;
|
||||
|
||||
if (used)
|
||||
{
|
||||
usz available = 64 - used;
|
||||
|
||||
if (data.len < available)
|
||||
{
|
||||
ctx.buffer[used:data.len] = data[..];
|
||||
return;
|
||||
}
|
||||
ctx.buffer[used:available] = data[:available];
|
||||
data = data[available..];
|
||||
body(ctx, &ctx.buffer, 64);
|
||||
}
|
||||
|
||||
if (data.len >= 64)
|
||||
{
|
||||
data = body(ctx, data, data.len & ~(usz)0x3f)[:data.len & 0x3f];
|
||||
}
|
||||
ctx.buffer[:data.len] = data[..];
|
||||
}
|
||||
|
||||
fn char[16] Md5.final(&ctx)
|
||||
{
|
||||
usz used = (usz)ctx.lo & 0x3f;
|
||||
ctx.buffer[used++] = 0x80;
|
||||
|
||||
usz available = 64 - used;
|
||||
|
||||
if (available < 8)
|
||||
{
|
||||
ctx.buffer[used:available] = 0;
|
||||
body(ctx, &ctx.buffer, 64);
|
||||
used = 0;
|
||||
available = 64;
|
||||
}
|
||||
ctx.buffer[used:available - 8] = 0;
|
||||
|
||||
ctx.lo <<= 3;
|
||||
ctx.buffer[56:4] = bitcast(ctx.lo, char[4])[..];
|
||||
ctx.buffer[60:4] = bitcast(ctx.hi, char[4])[..];
|
||||
|
||||
body(ctx, &ctx.buffer, 64);
|
||||
|
||||
char[16] res @noinit;
|
||||
res[0:4] = bitcast(ctx.a, char[4]);
|
||||
res[4:4] = bitcast(ctx.b, char[4]);
|
||||
res[8:4] = bitcast(ctx.c, char[4]);
|
||||
res[12:4] = bitcast(ctx.d, char[4]);
|
||||
*ctx = {};
|
||||
return res;
|
||||
}
|
||||
|
||||
module std::hash::md5 @private;
|
||||
|
||||
// Implementation
|
||||
macro @f(x, y, z) => z ^ (x & (y ^ z));
|
||||
macro @g(x, y, z) => y ^ (z & (x ^ y));
|
||||
macro @h(x, y, z) => (x ^ y) ^ z;
|
||||
macro @h2(x, y, z) => x ^ (y ^ z);
|
||||
macro @i(x, y, z) => y ^ (x | ~z);
|
||||
|
||||
macro @step(#f, &a, b, c, d, ptr, n, t, s)
|
||||
{
|
||||
*a += #f(b, c, d) + *(uint *)&ptr[n * 4] + t;
|
||||
*a = (*a << s) | ((*a & 0xffffffff) >> (32 - s));
|
||||
*a += b;
|
||||
}
|
||||
|
||||
|
||||
fn char* body(Md5* ctx, void* data, usz size)
|
||||
{
|
||||
char* ptr;
|
||||
uint a, b, c, d;
|
||||
uint saved_a, saved_b, saved_c, saved_d;
|
||||
ptr = data;
|
||||
a = ctx.a;
|
||||
b = ctx.b;
|
||||
c = ctx.c;
|
||||
d = ctx.d;
|
||||
|
||||
do
|
||||
{
|
||||
saved_a = a;
|
||||
saved_b = b;
|
||||
saved_c = c;
|
||||
saved_d = d;
|
||||
|
||||
/* Round 1 */
|
||||
@step(@f, a, b, c, d, ptr, 0, 0xd76aa478, 7) ;
|
||||
@step(@f, d, a, b, c, ptr, 1, 0xe8c7b756, 12) ;
|
||||
@step(@f, c, d, a, b, ptr, 2, 0x242070db, 17) ;
|
||||
@step(@f, b, c, d, a, ptr, 3, 0xc1bdceee, 22) ;
|
||||
@step(@f, a, b, c, d, ptr, 4, 0xf57c0faf, 7) ;
|
||||
@step(@f, d, a, b, c, ptr, 5, 0x4787c62a, 12) ;
|
||||
@step(@f, c, d, a, b, ptr, 6, 0xa8304613, 17) ;
|
||||
@step(@f, b, c, d, a, ptr, 7, 0xfd469501, 22) ;
|
||||
@step(@f, a, b, c, d, ptr, 8, 0x698098d8, 7) ;
|
||||
@step(@f, d, a, b, c, ptr, 9, 0x8b44f7af, 12) ;
|
||||
@step(@f, c, d, a, b, ptr, 10, 0xffff5bb1, 17);
|
||||
@step(@f, b, c, d, a, ptr, 11, 0x895cd7be, 22);
|
||||
@step(@f, a, b, c, d, ptr, 12, 0x6b901122, 7) ;
|
||||
@step(@f, d, a, b, c, ptr, 13, 0xfd987193, 12);
|
||||
@step(@f, c, d, a, b, ptr, 14, 0xa679438e, 17);
|
||||
@step(@f, b, c, d, a, ptr, 15, 0x49b40821, 22);
|
||||
|
||||
/* Round 2 */
|
||||
@step(@g, a, b, c, d, ptr, 1, 0xf61e2562, 5) ;
|
||||
@step(@g, d, a, b, c, ptr, 6, 0xc040b340, 9) ;
|
||||
@step(@g, c, d, a, b, ptr, 11, 0x265e5a51, 14);
|
||||
@step(@g, b, c, d, a, ptr, 0, 0xe9b6c7aa, 20) ;
|
||||
@step(@g, a, b, c, d, ptr, 5, 0xd62f105d, 5) ;
|
||||
@step(@g, d, a, b, c, ptr, 10, 0x02441453, 9) ;
|
||||
@step(@g, c, d, a, b, ptr, 15, 0xd8a1e681, 14);
|
||||
@step(@g, b, c, d, a, ptr, 4, 0xe7d3fbc8, 20) ;
|
||||
@step(@g, a, b, c, d, ptr, 9, 0x21e1cde6, 5) ;
|
||||
@step(@g, d, a, b, c, ptr, 14, 0xc33707d6, 9) ;
|
||||
@step(@g, c, d, a, b, ptr, 3, 0xf4d50d87, 14) ;
|
||||
@step(@g, b, c, d, a, ptr, 8, 0x455a14ed, 20) ;
|
||||
@step(@g, a, b, c, d, ptr, 13, 0xa9e3e905, 5) ;
|
||||
@step(@g, d, a, b, c, ptr, 2, 0xfcefa3f8, 9) ;
|
||||
@step(@g, c, d, a, b, ptr, 7, 0x676f02d9, 14) ;
|
||||
@step(@g, b, c, d, a, ptr, 12, 0x8d2a4c8a, 20);
|
||||
|
||||
/* Round 3 */
|
||||
@step(@h, a, b, c, d, ptr, 5, 0xfffa3942, 4);
|
||||
@step(@h2, d, a, b, c, ptr, 8, 0x8771f681, 11);
|
||||
@step(@h, c, d, a, b, ptr, 11, 0x6d9d6122, 16);
|
||||
@step(@h2, b, c, d, a, ptr, 14, 0xfde5380c, 23);
|
||||
@step(@h, a, b, c, d, ptr, 1, 0xa4beea44, 4);
|
||||
@step(@h2, d, a, b, c, ptr, 4, 0x4bdecfa9, 11);
|
||||
@step(@h, c, d, a, b, ptr, 7, 0xf6bb4b60, 16);
|
||||
@step(@h2, b, c, d, a, ptr, 10, 0xbebfbc70, 23);
|
||||
@step(@h, a, b, c, d, ptr, 13, 0x289b7ec6, 4) ;
|
||||
@step(@h2, d, a, b, c, ptr, 0, 0xeaa127fa, 11) ;
|
||||
@step(@h, c, d, a, b, ptr, 3, 0xd4ef3085, 16) ;
|
||||
@step(@h2, b, c, d, a, ptr, 6, 0x04881d05, 23) ;
|
||||
@step(@h, a, b, c, d, ptr, 9, 0xd9d4d039, 4) ;
|
||||
@step(@h2, d, a, b, c, ptr, 12, 0xe6db99e5, 11) ;
|
||||
@step(@h, c, d, a, b, ptr, 15, 0x1fa27cf8, 16) ;
|
||||
@step(@h2, b, c, d, a, ptr, 2, 0xc4ac5665, 23) ;
|
||||
|
||||
/* Round 4 */
|
||||
@step(@i, a, b, c, d, ptr, 0, 0xf4292244, 6) ;
|
||||
@step(@i, d, a, b, c, ptr, 7, 0x432aff97, 10) ;
|
||||
@step(@i, c, d, a, b, ptr, 14, 0xab9423a7, 15) ;
|
||||
@step(@i, b, c, d, a, ptr, 5, 0xfc93a039, 21) ;
|
||||
@step(@i, a, b, c, d, ptr, 12, 0x655b59c3, 6) ;
|
||||
@step(@i, d, a, b, c, ptr, 3, 0x8f0ccc92, 10) ;
|
||||
@step(@i, c, d, a, b, ptr, 10, 0xffeff47d, 15) ;
|
||||
@step(@i, b, c, d, a, ptr, 1, 0x85845dd1, 21) ;
|
||||
@step(@i, a, b, c, d, ptr, 8, 0x6fa87e4f, 6) ;
|
||||
@step(@i, d, a, b, c, ptr, 15, 0xfe2ce6e0, 10) ;
|
||||
@step(@i, c, d, a, b, ptr, 6, 0xa3014314, 15) ;
|
||||
@step(@i, b, c, d, a, ptr, 13, 0x4e0811a1, 21) ;
|
||||
@step(@i, a, b, c, d, ptr, 4, 0xf7537e82, 6) ;
|
||||
@step(@i, d, a, b, c, ptr, 11, 0xbd3af235, 10) ;
|
||||
@step(@i, c, d, a, b, ptr, 2, 0x2ad7d2bb, 15) ;
|
||||
@step(@i, b, c, d, a, ptr, 9, 0xeb86d391, 21) ;
|
||||
|
||||
a += saved_a;
|
||||
b += saved_b;
|
||||
c += saved_c;
|
||||
d += saved_d;
|
||||
|
||||
ptr += 64;
|
||||
|
||||
} while (size -= 64);
|
||||
|
||||
ctx.a = a;
|
||||
ctx.b = b;
|
||||
ctx.c = c;
|
||||
ctx.d = d;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -72,6 +72,7 @@
|
||||
- Add `io::wrap_bytes` for reading bytes with `io` functions.
|
||||
- Add `rnd` and `rand_in_range` default random functions.
|
||||
- Additional timezone related functions for `datetime`.
|
||||
- Added MD5 and crypto::safe_compare.
|
||||
|
||||
## 0.6.2 Change list
|
||||
|
||||
|
||||
41
test/unit/stdlib/hash/md5.c3
Normal file
41
test/unit/stdlib/hash/md5.c3
Normal file
@@ -0,0 +1,41 @@
|
||||
module std::hash::md5_test @test;
|
||||
import std::hash::md5;
|
||||
|
||||
|
||||
fn void test_md5_rfc()
|
||||
{
|
||||
Md5 md5;
|
||||
md5.init();
|
||||
assert (md5.final() == x'd41d8cd98f00b204e9800998ecf8427e');
|
||||
|
||||
md5.init();
|
||||
md5.update("a");
|
||||
assert (md5.final() == x'0cc175b9c0f1b6a831c399e269772661');
|
||||
|
||||
md5.init();
|
||||
md5.update("abc");
|
||||
assert (md5.final() == x'900150983cd24fb0d6963f7d28e17f72');
|
||||
|
||||
md5.init();
|
||||
md5.update("message ");
|
||||
md5.update("digest");
|
||||
assert(md5.final() == x'f96b697d7cb7938d525a2f31aaf161d0');
|
||||
|
||||
md5.init();
|
||||
md5.update("abcdefghijklmnopqrstuvwxyz");
|
||||
assert(md5.final() == x'c3fcd3d76192e4007dfb496cca67e13b');
|
||||
|
||||
md5.init();
|
||||
md5.update("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
|
||||
assert(md5.final() == x'd174ab98d277d9f5a5611c2c9f419d9f');
|
||||
|
||||
md5.init();
|
||||
md5.update("12345678901234567890123456789012345678901234567890123456789012345678901234567890");
|
||||
assert(md5.final() == x'57edf4a22be3c955ac49da2e2107b67a');
|
||||
|
||||
}
|
||||
|
||||
fn void test_md5_hash()
|
||||
{
|
||||
assert(md5::hash("12345678901234567890123456789012345678901234567890123456789012345678901234567890") == x'57edf4a22be3c955ac49da2e2107b67a');
|
||||
}
|
||||
Reference in New Issue
Block a user