From 43070412f752943fc3a66349e2493712d76d88e5 Mon Sep 17 00:00:00 2001 From: joe-conigliaro Date: Thu, 18 Jul 2019 18:50:05 +1000 Subject: [PATCH] implement crypto.sha256 + some crypto cleanup --- vlib/crypto/md5/md5.v | 2 +- vlib/crypto/md5/md5block_generic.v | 1 + vlib/crypto/sha1/sha1.v | 4 +- vlib/crypto/sha256/sha256.v | 218 +++++++++++++++++++++++ vlib/crypto/sha256/sha256_test.v | 9 + vlib/crypto/sha256/sha256block_generic.v | 158 ++++++++++++++++ vlib/crypto/sha512/sha512.v | 68 ++++--- vlib/crypto/sha512/sha512block_generic.v | 2 + 8 files changed, 424 insertions(+), 38 deletions(-) create mode 100644 vlib/crypto/sha256/sha256.v create mode 100644 vlib/crypto/sha256/sha256_test.v create mode 100644 vlib/crypto/sha256/sha256block_generic.v diff --git a/vlib/crypto/md5/md5.v b/vlib/crypto/md5/md5.v index 9870a4271f..4d669447d4 100644 --- a/vlib/crypto/md5/md5.v +++ b/vlib/crypto/md5/md5.v @@ -48,7 +48,7 @@ fn (d mut Digest) reset() { d.len = u64(0) } -// new returns a new hash.Hash computing the MD5 checksum. +// new returns a new Digest (implementing hash.Hash) computing the MD5 checksum. pub fn new() *Digest { mut d := &Digest{} d.reset() diff --git a/vlib/crypto/md5/md5block_generic.v b/vlib/crypto/md5/md5block_generic.v index c22e431429..16735f1be0 100644 --- a/vlib/crypto/md5/md5block_generic.v +++ b/vlib/crypto/md5/md5block_generic.v @@ -17,6 +17,7 @@ fn block_generic(dig &Digest, p []byte) { mut b := dig.s[1] mut c := dig.s[2] mut d := dig.s[3] + for i := 0; i <= p.len-BlockSize; i += BlockSize { mut q := p.right(i) q = q.left(BlockSize) diff --git a/vlib/crypto/sha1/sha1.v b/vlib/crypto/sha1/sha1.v index ab1d23a223..b513831c3d 100644 --- a/vlib/crypto/sha1/sha1.v +++ b/vlib/crypto/sha1/sha1.v @@ -143,9 +143,9 @@ pub fn sum(data []byte) []byte { } fn block(dig &Digest, p []byte) { - // For now just use block_generic until we have specific + // For now just use block_generic until we have specific // architecture optimized versions - block_generic(dig, p) + block_generic(dig, p) } pub fn (d &Digest) size() int { return Size } diff --git a/vlib/crypto/sha256/sha256.v b/vlib/crypto/sha256/sha256.v new file mode 100644 index 0000000000..adb0e64614 --- /dev/null +++ b/vlib/crypto/sha256/sha256.v @@ -0,0 +1,218 @@ +// 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 sha256 implements the SHA224 and SHA256 hash algorithms as defined +// in FIPS 180-4. + +// Adaped from https://github.com/golang/go/tree/master/src/crypto/sha256 + +module sha256 + +import math +import encoding.binary + +const ( + // The size of a SHA256 checksum in bytes. + Size = 32 + // The size of a SHA224 checksum in bytes. + Size224 = 28 + // The blocksize of SHA256 and SHA224 in bytes. + BlockSize = 64 +) + +const ( + Chunk = 64 + Init0 = 0x6A09E667 + Init1 = 0xBB67AE85 + Init2 = 0x3C6EF372 + Init3 = 0xA54FF53A + Init4 = 0x510E527F + Init5 = 0x9B05688C + Init6 = 0x1F83D9AB + Init7 = 0x5BE0CD19 + Init0_224 = 0xC1059ED8 + Init1_224 = 0x367CD507 + Init2_224 = 0x3070DD17 + Init3_224 = 0xF70E5939 + Init4_224 = 0xFFC00B31 + Init5_224 = 0x68581511 + Init6_224 = 0x64F98FA7 + Init7_224 = 0xBEFA4FA4 +) + +// digest represents the partial evaluation of a checksum. +struct Digest { +mut: + h []u32 + x []byte + nx int + len u64 + is224 bool // mark if this digest is SHA-224 +} + +fn (d &Digest) reset() { + d.h = [u32(0); 8] + d.x = [byte(0); Chunk] + if !d.is224 { + 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.h[5] = u32(Init5) + d.h[6] = u32(Init6) + d.h[7] = u32(Init7) + } else { + d.h[0] = u32(Init0_224) + d.h[1] = u32(Init1_224) + d.h[2] = u32(Init2_224) + d.h[3] = u32(Init3_224) + d.h[4] = u32(Init4_224) + d.h[5] = u32(Init5_224) + d.h[6] = u32(Init6_224) + d.h[7] = u32(Init7_224) + } + d.nx = 0 + d.len = u64(0) +} + +// new returns a new Digest (implementing hash.Hash) computing the SHA256 checksum. +pub fn new() *Digest { + mut d := &Digest{} + d.reset() + return d +} + +// new224 returns a new Digest (implementing hash.Hash) computing the SHA224 checksum. +pub fn new224() *Digest { + mut d := &Digest{} + d.is224 = true + d.reset() + return d +} + +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(10))) + v2 := w[i-15] + t2 := (bits.rotate_left_32(v2, -7)) ^ (bits.rotate_left_32(v2, -18)) ^ u32((v2 >> u32(3))) + w[i] = t1 + w[i-7] + t2 + w[i-16] + } + + mut a := h0 + mut b := h1 + mut c := h2 + mut d := h3 + mut e := h4 + mut f := h5 + mut g := h6 + mut h := h7 + + for i := 0; i < 64; i++ { + t1 := h + ((bits.rotate_left_32(e, -6)) ^ (bits.rotate_left_32(e, -11)) ^ (bits.rotate_left_32(e, -25))) + ((e & f) ^ (~e & g)) + u32(_K[i]) + w[i] + + t2 := ((bits.rotate_left_32(a, -2)) ^ (bits.rotate_left_32(a, -13)) ^ (bits.rotate_left_32(a, -22))) + ((a & b) ^ (a & c) ^ (b & c)) + + h = g + g = f + f = e + e = d + t1 + d = c + c = b + b = a + a = t1 + t2 + } + + h0 += a + h1 += b + h2 += c + h3 += d + h4 += e + h5 += f + h6 += g + h7 += h + + 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 + dig.h[5] = h5 + dig.h[6] = h6 + dig.h[7] = h7 +} diff --git a/vlib/crypto/sha512/sha512.v b/vlib/crypto/sha512/sha512.v index d28a57a458..8a411892f4 100644 --- a/vlib/crypto/sha512/sha512.v +++ b/vlib/crypto/sha512/sha512.v @@ -5,7 +5,7 @@ // Package sha512 implements the SHA-384, SHA-512, SHA-512/224, and SHA-512/256 // hash algorithms as defined in FIPS 180-4. -// Adaped from https://github.com/golang/go/tree/master/src/crypto/sha256 +// Adaped from https://github.com/golang/go/tree/master/src/crypto/sha512 module sha512 @@ -65,8 +65,6 @@ const ( // digest represents the partial evaluation of a checksum. struct Digest { - // h [8]uint64 - // x [chunk]byte mut: h []u64 x []byte @@ -123,8 +121,8 @@ mut: // Note: when u64 const is working remove this and uncomment above fn (d mut Digest) reset() { - d.h = [u64(0); 8] - d.x = [byte(0); Chunk] + d.h = [u64(0); 8] + d.x = [byte(0); Chunk] switch d.function { case crypto.Hash.SHA384: d.h[0] = u64(0xcbbb9d5dc1059ed8) @@ -154,14 +152,14 @@ fn (d mut Digest) reset() { d.h[6] = u64(0x2b0199fc2c85b8aa) d.h[7] = u64(0x0eb72ddc81c52ca2) default: - d.h[0] = u64(0x6a09e667f3bcc908) - d.h[1] = u64(0xbb67ae8584caa73b) - d.h[2] = u64(0x3c6ef372fe94f82b) - d.h[3] = u64(0xa54ff53a5f1d36f1) - d.h[4] = u64(0x510e527fade682d1) - d.h[5] = u64(0x9b05688c2b3e6c1f) - d.h[6] = u64(0x1f83d9abfb41bd6b) - d.h[7] = u64(0x5be0cd19137e2179) + d.h[0] = u64(0x6a09e667f3bcc908) + d.h[1] = u64(0xbb67ae8584caa73b) + d.h[2] = u64(0x3c6ef372fe94f82b) + d.h[3] = u64(0xa54ff53a5f1d36f1) + d.h[4] = u64(0x510e527fade682d1) + d.h[5] = u64(0x9b05688c2b3e6c1f) + d.h[6] = u64(0x1f83d9abfb41bd6b) + d.h[7] = u64(0x5be0cd19137e2179) } d.nx = 0 d.len = u64(0) @@ -173,22 +171,22 @@ fn _new(hash crypto.Hash) *Digest { return d } -// new returns a new hash.Hash computing the SHA-512 checksum. +// new returns a new Digest (implementing hash.Hash) computing the SHA-512 checksum. pub fn new() *Digest { return _new(crypto.Hash.SHA512) } -// new512_224 returns a new hash.Hash computing the SHA-512/224 checksum. +// new512_224 returns a new Digest (implementing hash.Hash) computing the SHA-512/224 checksum. fn new512_224() *Digest { return _new(crypto.Hash.SHA512_224) } -// new512_256 returns a new hash.Hash computing the SHA-512/256 checksum. +// new512_256 returns a new Digest (implementing hash.Hash) computing the SHA-512/256 checksum. fn new512_256() *Digest { return _new(crypto.Hash.SHA512_256) } -// new384 returns a new hash.Hash computing the SHA-384 checksum. +// new384 returns a new Digest (implementing hash.Hash) computing the SHA-384 checksum. fn new384() *Digest { return _new(crypto.Hash.SHA384) } @@ -237,22 +235,22 @@ fn (d mut Digest) sum(b_in mut []byte) []byte { switch d0.function { case crypto.Hash.SHA384: for b in hash.left(Size384) { - b_in << b - } + b_in << b + } case crypto.Hash.SHA512_224: for b in hash.left(Size224) { - b_in << b - } + b_in << b + } case crypto.Hash.SHA512_256: for b in hash.left(Size256) { - b_in << b - } + b_in << b + } default: for b in hash { - b_in << b - } + b_in << b + } } - return *b_in + return *b_in } fn (d mut Digest) checksum() []byte { @@ -261,8 +259,8 @@ fn (d mut Digest) checksum() []byte { mut tmp := [byte(0); 128] tmp[0] = 0x80 - if int(len)%128 < 112 { - d.write(tmp.left(112-int(len)%128)) + if int(len)%128 < 112 { + d.write(tmp.left(112-int(len)%128)) } else { d.write(tmp.left(128+112-int(len)%128)) } @@ -271,7 +269,7 @@ fn (d mut Digest) checksum() []byte { len <<= u64(3) binary.big_endian_put_u64(tmp, u64(0)) // upper 64 bits are always zero, because len variable has type u64 - binary.big_endian_put_u64(tmp.right(8), len) + binary.big_endian_put_u64(tmp.right(8), len) d.write(tmp.left(16)) if d.nx != 0 { @@ -280,7 +278,7 @@ fn (d mut Digest) checksum() []byte { mut digest := [byte(0); Size] - binary.big_endian_put_u64(digest, d.h[0]) + binary.big_endian_put_u64(digest, d.h[0]) binary.big_endian_put_u64(digest.right(8), d.h[1]) binary.big_endian_put_u64(digest.right(16), d.h[2]) binary.big_endian_put_u64(digest.right(24), d.h[3]) @@ -306,7 +304,7 @@ pub fn sum384(data []byte) []byte { mut d := _new(crypto.Hash.SHA384) d.write(data) sum := d.checksum() - sum384 := sum.left(Size384) + sum384 := sum.left(Size384) return sum384 } @@ -315,7 +313,7 @@ pub fn sum512_224(data []byte) []byte { mut d := _new(crypto.Hash.SHA512_224) d.write(data) sum := d.checksum() - sum224 := sum.left(Size224) + sum224 := sum.left(Size224) return sum224 } @@ -324,14 +322,14 @@ pub fn sum512_256(data []byte) []byte { mut d := _new(crypto.Hash.SHA512_256) d.write(data) sum := d.checksum() - sum256 := sum.left(Size256) + sum256 := sum.left(Size256) return sum256 } fn block(dig &Digest, p []byte) { - // For now just use block_generic until we have specific + // For now just use block_generic until we have specific // architecture optimized versions - block_generic(dig, p) + block_generic(dig, p) } pub fn (d &Digest) size() int { diff --git a/vlib/crypto/sha512/sha512block_generic.v b/vlib/crypto/sha512/sha512block_generic.v index 3171649680..8ba2b288d4 100644 --- a/vlib/crypto/sha512/sha512block_generic.v +++ b/vlib/crypto/sha512/sha512block_generic.v @@ -180,6 +180,7 @@ fn block_generic(dig &Digest, p []byte) { ] mut w := [u64(0); 80] + mut h0 := dig.h[0] mut h1 := dig.h[1] mut h2 := dig.h[2] @@ -188,6 +189,7 @@ fn block_generic(dig &Digest, p []byte) { mut h5 := dig.h[5] mut h6 := dig.h[6] mut h7 := dig.h[7] + for p.len >= Chunk { for i := 0; i < 16; i++ { j := i * 8