From 55b8a9acb95bcde23bf53e0551698680877cce3a Mon Sep 17 00:00:00 2001 From: joe-conigliaro Date: Wed, 17 Jul 2019 19:00:15 +1000 Subject: [PATCH] crypto.sha512 --- vlib/crypto/crypto.v | 23 ++ vlib/crypto/md5/md5.v | 15 +- vlib/crypto/md5/md5block_generic.v | 6 +- vlib/crypto/sha1/sha1.v | 12 +- vlib/crypto/sha1/sha1block_generic.v | 4 +- vlib/crypto/sha512/sha512.v | 350 +++++++++++++++++++++++ vlib/crypto/sha512/sha512_test.v | 9 + vlib/crypto/sha512/sha512block_generic.v | 254 ++++++++++++++++ 8 files changed, 662 insertions(+), 11 deletions(-) create mode 100644 vlib/crypto/crypto.v create mode 100644 vlib/crypto/sha512/sha512.v create mode 100644 vlib/crypto/sha512/sha512_test.v create mode 100644 vlib/crypto/sha512/sha512block_generic.v diff --git a/vlib/crypto/crypto.v b/vlib/crypto/crypto.v new file mode 100644 index 0000000000..a86f86b3d9 --- /dev/null +++ b/vlib/crypto/crypto.v @@ -0,0 +1,23 @@ +module crypto + +enum Hash { + MD4 + MD5 + SHA1 + SHA224 + SHA256 + SHA384 + SHA512 + MD5SHA1 + RIPEMD160 + SHA3_224 + SHA3_256 + SHA3_384 + SHA3_512 + SHA512_224 + SHA512_256 + BLAKE2s_256 + BLAKE2b_256 + BLAKE2b_384 + BLAKE2b_512 +} diff --git a/vlib/crypto/md5/md5.v b/vlib/crypto/md5/md5.v index 0d170253d6..b17a8f5e12 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 hash.Hash computing the MD5 checksum. pub fn new() *Digest { mut d := &Digest{} d.reset() @@ -65,7 +65,7 @@ pub fn (d mut Digest) write(p []byte) ?int { } d.nx += n if d.nx == BlockSize { - block_generic(d, d.x) + block(d, d.x) d.nx = 0 } if n >= p.len { @@ -76,7 +76,7 @@ pub fn (d mut Digest) write(p []byte) ?int { } if p.len >= BlockSize { n := p.len &~ (BlockSize - 1) - block_generic(d, p.left(n)) + block(d, p.left(n)) if n >= p.len { p = []byte } else { @@ -130,14 +130,19 @@ pub fn (d mut Digest) checksum() []byte { return digest } -// Sum returns the MD5 checksum of the data. -// pub fn Sum(data []byte) [Size]byte { +// sum returns the MD5 checksum of the data. pub fn sum(data []byte) []byte { mut d := new() d.write(data) return d.checksum() } +fn block(dig &Digest, p []byte) { + // For now just use block_generic until we have specific + // architecture optimized versions + block_generic(dig, p) +} + pub fn (d &Digest) size() int { return Size } pub fn (d &Digest) block_size() int { return BlockSize } \ No newline at end of file diff --git a/vlib/crypto/md5/md5block_generic.v b/vlib/crypto/md5/md5block_generic.v index 86611faa03..c22e431429 100644 --- a/vlib/crypto/md5/md5block_generic.v +++ b/vlib/crypto/md5/md5block_generic.v @@ -2,7 +2,9 @@ // Use of this source code is governed by an MIT license // that can be found in the LICENSE file. -// This is a generic implementation with no arch optimizations +// This is the generic version with no architecture optimizations. +// In its own file so that an architecture +// optimized verision can be substituted module md5 @@ -126,4 +128,4 @@ fn block_generic(dig &Digest, p []byte) { dig.s[1] = b dig.s[2] = c dig.s[3] = d -} \ No newline at end of file +} diff --git a/vlib/crypto/sha1/sha1.v b/vlib/crypto/sha1/sha1.v index cd8aab0227..61f5f6bcd9 100644 --- a/vlib/crypto/sha1/sha1.v +++ b/vlib/crypto/sha1/sha1.v @@ -51,7 +51,7 @@ fn (d mut Digest) reset() { d.len = u64(0) } -// New returns a new Digest (implementing hash.Hash) computing the SHA1 checksum. +// new returns a new Digest (implementing hash.Hash) computing the SHA1 checksum. pub fn new() &Digest { mut d := &Digest{} d.reset() @@ -69,7 +69,7 @@ pub fn (d mut Digest) write(p []byte) ?int { } d.nx += n if d.nx == Chunk { - block_generic(d, d.x) + block(d, d.x) d.nx = 0 } if n >= p.len { @@ -80,7 +80,7 @@ pub fn (d mut Digest) write(p []byte) ?int { } if p.len >= Chunk { n := p.len &~ (Chunk - 1) - block_generic(d, p.left(n)) + block(d, p.left(n)) if n >= p.len { p = []byte } else { @@ -142,6 +142,12 @@ pub fn sum(data []byte) []byte { return d.checksum() } +fn block(dig &Digest, p []byte) { + // For now just use block_generic until we have specific + // architecture optimized versions + block_generic(dig, p) +} + pub fn (d &Digest) size() int { return Size } pub fn (d &Digest) block_size() int { return BlockSize } \ No newline at end of file diff --git a/vlib/crypto/sha1/sha1block_generic.v b/vlib/crypto/sha1/sha1block_generic.v index c96b8fb6e3..48cee2cd77 100644 --- a/vlib/crypto/sha1/sha1block_generic.v +++ b/vlib/crypto/sha1/sha1block_generic.v @@ -2,7 +2,9 @@ // Use of this source code is governed by an MIT license // that can be found in the LICENSE file. -// This is a generic implementation with no arch optimizations +// This is the generic version with no architecture optimizations. +// In its own file so that an architecture +// optimized verision can be substituted module sha1 diff --git a/vlib/crypto/sha512/sha512.v b/vlib/crypto/sha512/sha512.v new file mode 100644 index 0000000000..d28a57a458 --- /dev/null +++ b/vlib/crypto/sha512/sha512.v @@ -0,0 +1,350 @@ +// 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 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 + +module sha512 + +import math +import crypto +import encoding.binary + +const ( + // Size is the size, in bytes, of a SHA-512 checksum. + Size = 64 + // Size224 is the size, in bytes, of a SHA-512/224 checksum. + Size224 = 28 + // Size256 is the size, in bytes, of a SHA-512/256 checksum. + Size256 = 32 + // Size384 is the size, in bytes, of a SHA-384 checksum. + Size384 = 48 + // BlockSize is the block size, in bytes, of the SHA-512/224, + // SHA-512/256, SHA-384 and SHA-512 hash functions. + BlockSize = 128 +) + +const ( + Chunk = 128 + Init0 = 0x6a09e667f3bcc908 + Init1 = 0xbb67ae8584caa73b + Init2 = 0x3c6ef372fe94f82b + Init3 = 0xa54ff53a5f1d36f1 + Init4 = 0x510e527fade682d1 + Init5 = 0x9b05688c2b3e6c1f + Init6 = 0x1f83d9abfb41bd6b + Init7 = 0x5be0cd19137e2179 + Init0_224 = 0x8c3d37c819544da2 + Init1_224 = 0x73e1996689dcd4d6 + Init2_224 = 0x1dfab7ae32ff9c82 + Init3_224 = 0x679dd514582f9fcf + Init4_224 = 0x0f6d2b697bd44da8 + Init5_224 = 0x77e36f7304c48942 + Init6_224 = 0x3f9d85a86a1d36c8 + Init7_224 = 0x1112e6ad91d692a1 + Init0_256 = 0x22312194fc2bf72c + Init1_256 = 0x9f555fa3c84c64c2 + Init2_256 = 0x2393b86b6f53b151 + Init3_256 = 0x963877195940eabd + Init4_256 = 0x96283ee2a88effe3 + Init5_256 = 0xbe5e1e2553863992 + Init6_256 = 0x2b0199fc2c85b8aa + Init7_256 = 0x0eb72ddc81c52ca2 + Init0_384 = 0xcbbb9d5dc1059ed8 + Init1_384 = 0x629a292a367cd507 + Init2_384 = 0x9159015a3070dd17 + Init3_384 = 0x152fecd8f70e5939 + Init4_384 = 0x67332667ffc00b31 + Init5_384 = 0x8eb44a8768581511 + Init6_384 = 0xdb0c2e0d64f98fa7 + Init7_384 = 0x47b5481dbefa4fa4 +) + +// digest represents the partial evaluation of a checksum. +struct Digest { + // h [8]uint64 + // x [chunk]byte +mut: + h []u64 + x []byte + nx int + len u64 + function crypto.Hash +} + +// Note: when u64 const is working uncomment this and remove reset() below +// fn (d mut Digest) reset() { +// d.h = [u64(0); 8] +// d.x = [byte(0); Chunk] +// switch d.function { +// case crypto.Hash.SHA384: +// d.h[0] = u64(Init0_384) +// d.h[1] = u64(Init1_384) +// d.h[2] = u64(Init2_384) +// d.h[3] = u64(Init3_384) +// d.h[4] = u64(Init4_384) +// d.h[5] = u64(Init5_384) +// d.h[6] = u64(Init6_384) +// d.h[7] = u64(Init7_384) +// case crypto.Hash.SHA512_224: +// d.h[0] = u64(Init0_224) +// d.h[1] = u64(Init1_224) +// d.h[2] = u64(Init2_224) +// d.h[3] = u64(Init3_224) +// d.h[4] = u64(Init4_224) +// d.h[5] = u64(Init5_224) +// d.h[6] = u64(Init6_224) +// d.h[7] = u64(Init7_224) +// case crypto.Hash.SHA512_256: +// d.h[0] = u64(Init0_256) +// d.h[1] = u64(Init1_256) +// d.h[2] = u64(Init2_256) +// d.h[3] = u64(Init3_256) +// d.h[4] = u64(Init4_256) +// d.h[5] = u64(Init5_256) +// d.h[6] = u64(Init6_256) +// d.h[7] = u64(Init7_256) +// default: +// d.h[0] = u64(Init0) +// d.h[1] = u64(Init1) +// d.h[2] = u64(Init2) +// d.h[3] = u64(Init3) +// d.h[4] = u64(Init4) +// d.h[5] = u64(Init5) +// d.h[6] = u64(Init6) +// d.h[7] = u64(Init7) +// } +// d.nx = 0 +// d.len = u64(0) +// } + +// 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] + switch d.function { + case crypto.Hash.SHA384: + d.h[0] = u64(0xcbbb9d5dc1059ed8) + d.h[1] = u64(0x629a292a367cd507) + d.h[2] = u64(0x9159015a3070dd17) + d.h[3] = u64(0x152fecd8f70e5939) + d.h[4] = u64(0x67332667ffc00b31) + d.h[5] = u64(0x8eb44a8768581511) + d.h[6] = u64(0xdb0c2e0d64f98fa7) + d.h[7] = u64(0x47b5481dbefa4fa4) + case crypto.Hash.SHA512_224: + d.h[0] = u64(0x8c3d37c819544da2) + d.h[1] = u64(0x73e1996689dcd4d6) + d.h[2] = u64(0x1dfab7ae32ff9c82) + d.h[3] = u64(0x679dd514582f9fcf) + d.h[4] = u64(0x0f6d2b697bd44da8) + d.h[5] = u64(0x77e36f7304c48942) + d.h[6] = u64(0x3f9d85a86a1d36c8) + d.h[7] = u64(0x1112e6ad91d692a1) + case crypto.Hash.SHA512_256: + d.h[0] = u64(0x22312194fc2bf72c) + d.h[1] = u64(0x9f555fa3c84c64c2) + d.h[2] = u64(0x2393b86b6f53b151) + d.h[3] = u64(0x963877195940eabd) + d.h[4] = u64(0x96283ee2a88effe3) + d.h[5] = u64(0xbe5e1e2553863992) + 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.nx = 0 + d.len = u64(0) +} + +fn _new(hash crypto.Hash) *Digest { + mut d := &Digest{function: hash} + d.reset() + return d +} + +// new returns a new 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. +fn new512_224() *Digest { + return _new(crypto.Hash.SHA512_224) +} + +// new512_256 returns a new 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. +fn new384() *Digest { + return _new(crypto.Hash.SHA384) +} + +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 { + for i := 0; i < 16; i++ { + j := i * 8 + w[i] = u64(u64(u64(p[j])<>u64(19)) | u64(v1<>u64(61)) | u64(v1<> u64(6)) + v2 := w[i-15] + t2 := (u64(v2>>u64(1)) | u64(v2<>u64(8)) | u64(v2<> u64(7)) + + 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 < 80; i++ { + // t1 := h + (u64(u64(e>>u64(14)) | u64(e<>u64(18)) | u64(e<>u64(41)) | u64(e<>u64(14)) | u64(e<>u64(18)) | u64(e<>u64(41)) | u64(e<>u64(28)) | u64(a<>u64(34)) | u64(a<>u64(39)) | u64(a<= 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 +}