From a7529b7b0536be7a637dc54c8ee937e73c3869a6 Mon Sep 17 00:00:00 2001 From: joe-conigliaro Date: Tue, 16 Jul 2019 01:49:01 +1000 Subject: [PATCH] sha1 implementation + helper funcs --- vlib/builtin/array.v | 8 ++ vlib/builtin/string.v | 8 ++ vlib/crypto/sha1/sha1.v | 147 ++++++++++++++++++++++++++++++++++ vlib/crypto/sha1/sha1_test.v | 5 ++ vlib/crypto/sha1/sha1block.v | 117 +++++++++++++++++++++++++++ vlib/encoding/binary/binary.v | 93 +++++++++++++++++++++ vlib/hash/crc32/crc32.v | 11 ++- vlib/hash/hash.v | 21 +++++ vlib/math/bits/bits.v | 47 +++++++++++ 9 files changed, 454 insertions(+), 3 deletions(-) create mode 100644 vlib/crypto/sha1/sha1.v create mode 100644 vlib/crypto/sha1/sha1_test.v create mode 100644 vlib/crypto/sha1/sha1block.v create mode 100644 vlib/encoding/binary/binary.v create mode 100644 vlib/hash/hash.v create mode 100644 vlib/math/bits/bits.v diff --git a/vlib/builtin/array.v b/vlib/builtin/array.v index 0b9e1e999d..4f7769e9f5 100644 --- a/vlib/builtin/array.v +++ b/vlib/builtin/array.v @@ -225,3 +225,11 @@ fn free(a voidptr) { C.free(a) } +pub fn (b []byte) hex() string { + mut hex := malloc(b.len*2+1) + mut ptr := &hex[0] + for i := 0; i < b.len ; i++ { + ptr += C.sprintf(ptr, '%02X', b[i]) + } + return string(hex) +} diff --git a/vlib/builtin/string.v b/vlib/builtin/string.v index e38447b8f8..47d224df3f 100644 --- a/vlib/builtin/string.v +++ b/vlib/builtin/string.v @@ -812,3 +812,11 @@ pub fn (s string) hash() int { return h } +pub fn (s string) bytes() []byte { + if s.len == 0 { + return []byte + } + mut buf := [byte(0); s.len] + C.memcpy(buf.data, s.str, s.len) + return buf +} diff --git a/vlib/crypto/sha1/sha1.v b/vlib/crypto/sha1/sha1.v new file mode 100644 index 0000000000..8c93eee056 --- /dev/null +++ b/vlib/crypto/sha1/sha1.v @@ -0,0 +1,147 @@ +// Copyright (c) 2019 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license +// that can be found in the LICENSE file. + +// Package sha1 implements the SHA-1 hash algorithm as defined in RFC 3174. +// +// SHA-1 is cryptographically broken and should not be used for secure +// applications. +// Adapted from: https://github.com/golang/go/blob/master/src/crypto/sha1 +module sha1 + +import math +import encoding.binary + + +const( + // The size of a SHA-1 checksum in bytes. + Size = 20 + // The blocksize of SHA-1 in bytes. + BlockSize = 64 +) + +const ( + Chunk = 64 + Init0 = 0x67452301 + Init1 = 0xEFCDAB89 + Init2 = 0x98BADCFE + Init3 = 0x10325476 + Init4 = 0xC3D2E1F0 +) + +// digest represents the partial evaluation of a checksum. +struct Digest { +mut: + h []u32 + x []byte + nx int + len u64 +} + +fn (d mut Digest) reset() { + d.x = [byte(0); Chunk] + d.h = [u32(0); 5] + d.h[0] = u32(Init0) + d.h[1] = u32(Init1) + d.h[2] = u32(Init2) + d.h[3] = u32(Init3) + d.h[4] = u32(Init4) + d.nx = 0 + d.len = u64(0) +} + +// New returns a new Digest (implementing hash.Hash) computing the SHA1 checksum. +pub fn new() &Digest { + mut d := &Digest{} + d.reset() + return d +} + +pub fn (d mut Digest) write(p []byte) ?int { + nn := p.len + d.len += u64(nn) + + if d.nx > 0 { + n := int(math.min(f64(d.x.len), f64(p.len))) + for i:=0; i= p.len { + p = []byte + } else { + p = p.right(n) + } + } + if p.len >= Chunk { + n := p.len &~ (Chunk - 1) + block(d, p.left(n)) + if n >= p.len { + p = []byte + } else { + p = p.right(n) + } + } + if p.len > 0 { + d.nx = int(math.min(f64(d.x.len), f64(p.len))) + for i:=0; i= Chunk { + // Can interlace the computation of w with the + // rounds below if needed for speed. + for i := 0; i < 16; i++ { + j := i * 4 + w[i] = u32(u32(p[j])<>u32(32-1)) + f := b&c | (~b)&d + t := bits.rotate_left_32(a, 5) + f + e + w[i&0xf] + u32(_K0) + e = d + d = c + c = bits.rotate_left_32(b, 30) + b = a + a = t + i++ + } + for i < 40 { + tmp := w[(i-3)&0xf] ^ w[(i-8)&0xf] ^ w[(i-14)&0xf] ^ w[(i)&0xf] + w[i&0xf] = u32(tmp<>u32(32-1)) + f := b ^ c ^ d + t := bits.rotate_left_32(a, 5) + f + e + w[i&0xf] + u32(_K1) + e = d + d = c + c = bits.rotate_left_32(b, 30) + b = a + a = t + i++ + } + for i < 60 { + tmp := w[(i-3)&0xf] ^ w[(i-8)&0xf] ^ w[(i-14)&0xf] ^ w[(i)&0xf] + w[i&0xf] = u32(tmp<>u32(32-1)) + f := ((b | c) & d) | (b & c) + t := bits.rotate_left_32(a, 5) + f + e + w[i&0xf] + u32(_K2) + + e = d + d = c + c = bits.rotate_left_32(b, 30) + b = a + a = t + + i++ + } + for i < 80 { + tmp := w[(i-3)&0xf] ^ w[(i-8)&0xf] ^ w[(i-14)&0xf] ^ w[(i)&0xf] + w[i&0xf] = u32(tmp<>u32(32-1)) + f := b ^ c ^ d + t := bits.rotate_left_32(a, 5) + f + e + w[i&0xf] + u32(_K3) + e = d + d = c + c = bits.rotate_left_32(b, 30) + b = a + a = t + i++ + } + + h0 += a + h1 += b + h2 += c + h3 += d + h4 += e + + if Chunk >= p.len { + p = []byte + } else { + p = p.right(Chunk) + } + + } + + dig.h[0] = h0 + dig.h[1] = h1 + dig.h[2] = h2 + dig.h[3] = h3 + dig.h[4] = h4 +} diff --git a/vlib/encoding/binary/binary.v b/vlib/encoding/binary/binary.v new file mode 100644 index 0000000000..db15aea4f1 --- /dev/null +++ b/vlib/encoding/binary/binary.v @@ -0,0 +1,93 @@ +// Copyright (c) 2019 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license +// that can be found in the LICENSE file. + +module binary + + +// Little Endian +pub fn little_endian_endian_u16(b []byte) u16 { + _ := b[1] // bounds check + return u16(b[0]) | u16(u16(b[1])<> u16(8)) +} + +pub fn little_endian_u32(b []byte) u32 { + _ := b[3] // bounds check + return u32(b[0]) | u32(u32(b[1])<> u32(8)) + b[2] = byte(v >> u32(16)) + b[3] = byte(v >> u32(24)) +} + +pub fn little_endian_u64(b []byte) u64 { + _ := b[7] // bounds check + return u64(b[0]) | u64(u64(b[1])<> u64(8)) + b[2] = byte(v >> u64(16)) + b[3] = byte(v >> u64(24)) + b[4] = byte(v >> u64(32)) + b[5] = byte(v >> u64(40)) + b[6] = byte(v >> u64(48)) + b[7] = byte(v >> u64(56)) +} + +// Big Endian +pub fn big_endian_u16(b []byte) u16 { + _ := b[1] // bounds check + return u16(b[1]) | u16(u16(b[0])<> u16(8)) + b[1] = byte(v) +} + +pub fn big_endian_u32(b []byte) u32 { + _ := b[3] // bounds check + return u32(b[3]) | u32(u32(b[2])<> u32(24)) + b[1] = byte(v >> u32(16)) + b[2] = byte(v >> u32(8)) + b[3] = byte(v) +} + +pub fn big_endian_u64(b []byte) u64 { + _ := b[7] // bounds check + return u64(b[7]) | u64(u64(b[6])<> u64(56)) + b[1] = byte(v >> u64(48)) + b[2] = byte(v >> u64(40)) + b[3] = byte(v >> u64(32)) + b[4] = byte(v >> u64(24)) + b[5] = byte(v >> u64(16)) + b[6] = byte(v >> u64(8)) + b[7] = byte(v) +} \ No newline at end of file diff --git a/vlib/hash/crc32/crc32.v b/vlib/hash/crc32/crc32.v index 606f839abe..b92bf04c51 100644 --- a/vlib/hash/crc32/crc32.v +++ b/vlib/hash/crc32/crc32.v @@ -13,6 +13,11 @@ const ( Koopman = 0xeb31d82e ) +// The size of a CRC-32 checksum in bytes. +const ( + Size = 4 +) + struct Crc32 { mut: table []u32 @@ -32,7 +37,7 @@ fn(c mut Crc32) generate_table(poly int) { } } -fn(c &Crc32) sum_32(s string) u32 { +fn(c &Crc32) sum32(s string) u32 { mut crc := ~u32(0) for i := 0; i < s.len; i++ { crc = c.table[byte(crc)^s[i]] ^ u32(crc >> u32(8)) @@ -41,7 +46,7 @@ fn(c &Crc32) sum_32(s string) u32 { } pub fn(c &Crc32) checksum(s string) u32 { - return c.sum_32(s) + return c.sum32(s) } // pass the polinomial to use @@ -54,6 +59,6 @@ pub fn new(poly int) *Crc32 { // calculate crc32 using IEEE pub fn sum(s string) u32 { mut c := new(IEEE) - return c.sum_32(s) + return c.sum32(s) } diff --git a/vlib/hash/hash.v b/vlib/hash/hash.v new file mode 100644 index 0000000000..cf9e2c1b79 --- /dev/null +++ b/vlib/hash/hash.v @@ -0,0 +1,21 @@ +// Copyright (c) 2019 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license +// that can be found in the LICENSE file. + +module hash + +interface Hash { + // Sum appends the current hash to b and returns the resulting array. + // It does not change the underlying hash state. + sum(b []byte) []byte + size() int + block_size() int +} + +interface Hash32 { + sum32() uint32 +} + +interface Hash64 { + sum64() uint64 +} diff --git a/vlib/math/bits/bits.v b/vlib/math/bits/bits.v new file mode 100644 index 0000000000..b4cfe8d7fa --- /dev/null +++ b/vlib/math/bits/bits.v @@ -0,0 +1,47 @@ +// Copyright (c) 2019 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license +// that can be found in the LICENSE file. + +module bits + +// --- RotateLeft --- + +// rotate_left_8 returns the value of x rotated left by (k mod 8) bits. +// To rotate x right by k bits, call rotate_left_8(x, -k). +// +// This function's execution time does not depend on the inputs. +pub fn rotate_left_8(x u8, k int) u8 { + n := u8(8) + s := u8(k) & u8(n - u8(1)) + return u8((x<>(n-s))) +} + +// rotate_left_16 returns the value of x rotated left by (k mod 16) bits. +// To rotate x right by k bits, call rotate_left_16(x, -k). +// +// This function's execution time does not depend on the inputs. +pub fn rotate_left_16(x u16, k int) u16 { + n := u16(16) + s := u16(k) & (n - u16(1)) + return u16((x<>(n-s))) +} + +// rotate_left_32 returns the value of x rotated left by (k mod 32) bits. +// To rotate x right by k bits, call rotate_left_32(x, -k). +// +// This function's execution time does not depend on the inputs. +pub fn rotate_left_32(x u32, k int) u32 { + n := u32(32) + s := u32(k) & (n - u32(1)) + return u32(u32(x<>(n-s))) +} + +// rotate_left_64 returns the value of x rotated left by (k mod 64) bits. +// To rotate x right by k bits, call rotate_left_64(x, -k). +// +// This function's execution time does not depend on the inputs. +pub fn rotate_left_64(x u64, k int) u64 { + n := u64(64) + s := u64(k) & (n - u64(1)) + return u64(u64(x<>(n-s))) +} \ No newline at end of file