Skip to content

Commit

Permalink
refactor pure SHA3 API
Browse files Browse the repository at this point in the history
  • Loading branch information
qmuntal committed Dec 19, 2024
1 parent 77726dd commit 029af55
Show file tree
Hide file tree
Showing 4 changed files with 591 additions and 440 deletions.
197 changes: 0 additions & 197 deletions cng/hash.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
"crypto"
"hash"
"runtime"
"slices"
"unsafe"

"github.com/microsoft/go-crypto-winnative/internal/bcrypt"
Expand Down Expand Up @@ -85,27 +84,6 @@ func SHA512(p []byte) (sum [64]byte) {
return
}

func SHA3_256(p []byte) (sum [32]byte) {
if err := hashOneShot(bcrypt.SHA3_256_ALGORITHM, p, sum[:]); err != nil {
panic("bcrypt: SHA3_256 failed")
}
return
}

func SHA3_384(p []byte) (sum [48]byte) {
if err := hashOneShot(bcrypt.SHA3_384_ALGORITHM, p, sum[:]); err != nil {
panic("bcrypt: SHA3_384 failed")
}
return
}

func SHA3_512(p []byte) (sum [64]byte) {
if err := hashOneShot(bcrypt.SHA3_512_ALGORITHM, p, sum[:]); err != nil {
panic("bcrypt: SHA3_512 failed")
}
return
}

// NewMD4 returns a new MD4 hash.
func NewMD4() hash.Hash {
return newHashX(bcrypt.MD4_ALGORITHM, bcrypt.ALG_NONE_FLAG, nil)
Expand Down Expand Up @@ -136,21 +114,6 @@ func NewSHA512() hash.Hash {
return newHashX(bcrypt.SHA512_ALGORITHM, bcrypt.ALG_NONE_FLAG, nil)
}

// NewSHA3_256 returns a new SHA256 hash.
func NewSHA3_256() hash.Hash {
return newHashX(bcrypt.SHA3_256_ALGORITHM, bcrypt.ALG_NONE_FLAG, nil)
}

// NewSHA3_384 returns a new SHA384 hash.
func NewSHA3_384() hash.Hash {
return newHashX(bcrypt.SHA3_384_ALGORITHM, bcrypt.ALG_NONE_FLAG, nil)
}

// NewSHA3_512 returns a new SHA512 hash.
func NewSHA3_512() hash.Hash {
return newHashX(bcrypt.SHA3_512_ALGORITHM, bcrypt.ALG_NONE_FLAG, nil)
}

type hashAlgorithm struct {
handle bcrypt.ALG_HANDLE
id string
Expand Down Expand Up @@ -305,163 +268,3 @@ func (h *hashX) Sum(in []byte) []byte {
}
return append(in, h.buf...)
}

// SupportsSHAKE128 returns true if the SHAKE128 extendable output function is
// supported.
func SupportsSHAKE128() bool {
_, err := loadHash(bcrypt.CSHAKE128_ALGORITHM, bcrypt.ALG_NONE_FLAG)
return err == nil
}

// SupportsSHAKE256 returns true if the SHAKE256 extendable output function is
// supported.
func SupportsSHAKE256() bool {
_, err := loadHash(bcrypt.CSHAKE256_ALGORITHM, bcrypt.ALG_NONE_FLAG)
return err == nil
}

// SumSHAKE128 applies the SHAKE128 extendable output function to data and
// returns an output of the given length in bytes.
func SumSHAKE128(data []byte, length int) []byte {
out := make([]byte, length)
if err := hashOneShot(bcrypt.CSHAKE128_ALGORITHM, data, out); err != nil {
panic("bcrypt: CSHAKE128_ALGORITHM failed")
}
return out
}

// SumSHAKE256 applies the SHAKE256 extendable output function to data and
// returns an output of the given length in bytes.
func SumSHAKE256(data []byte, length int) []byte {
out := make([]byte, length)
if err := hashOneShot(bcrypt.CSHAKE256_ALGORITHM, data, out); err != nil {
panic("bcrypt: CSHAKE256_ALGORITHM failed")
}
return out
}

// SHAKE is an instance of a SHAKE extendable output function.
type SHAKE struct {
alg *hashAlgorithm
ctx bcrypt.HASH_HANDLE
n, s []byte
}

func newShake(id string, N, S []byte) *SHAKE {
alg, err := loadHash(id, bcrypt.ALG_NONE_FLAG)
if err != nil {
panic(err)
}
h := &SHAKE{alg: alg, n: slices.Clone(N), s: slices.Clone(S)}
err = bcrypt.CreateHash(h.alg.handle, &h.ctx, nil, nil, 0)
if err != nil {
panic(err)
}
if len(N) != 0 {
if err := bcrypt.SetProperty(bcrypt.HANDLE(h.ctx), utf16PtrFromString(bcrypt.FUNCTION_NAME_STRING), N, 0); err != nil {
panic(err)
}
}
if len(S) != 0 {
if err := bcrypt.SetProperty(bcrypt.HANDLE(h.ctx), utf16PtrFromString(bcrypt.CUSTOMIZATION_STRING), S, 0); err != nil {
panic(err)
}
}
runtime.SetFinalizer(h, (*SHAKE).finalize)
return h
}

// NewSHAKE128 creates a new SHAKE128 XOF.
func NewSHAKE128() *SHAKE {
return newShake(bcrypt.CSHAKE128_ALGORITHM, nil, nil)
}

// NewSHAKE256 creates a new SHAKE256 XOF.
func NewSHAKE256() *SHAKE {
return newShake(bcrypt.CSHAKE256_ALGORITHM, nil, nil)
}

// NewCSHAKE128 creates a new cSHAKE128 XOF.
//
// N is used to define functions based on cSHAKE, it can be empty when plain
// cSHAKE is desired. S is a customization byte string used for domain
// separation. When N and S are both empty, this is equivalent to NewSHAKE128.
func NewCSHAKE128(N, S []byte) *SHAKE {
return newShake(bcrypt.CSHAKE128_ALGORITHM, N, S)
}

// NewCSHAKE256 creates a new cSHAKE256 XOF.
//
// N is used to define functions based on cSHAKE, it can be empty when plain
// cSHAKE is desired. S is a customization byte string used for domain
// separation. When N and S are both empty, this is equivalent to NewSHAKE256.
func NewCSHAKE256(N, S []byte) *SHAKE {
return newShake(bcrypt.CSHAKE256_ALGORITHM, N, S)
}

func (h *SHAKE) finalize() {
bcrypt.DestroyHash(h.ctx)
}

// Write absorbs more data into the XOF's state.
//
// It panics if any output has already been read.
func (s *SHAKE) Write(p []byte) (n int, err error) {
if len(p) == 0 {
return 0, nil
}
defer runtime.KeepAlive(s)
for n < len(p) && err == nil {
nn := len32(p[n:])
err = bcrypt.HashData(s.ctx, p[n:n+nn], 0)
n += nn
}
if err != nil {
panic(err)
}
return len(p), nil
}

// Read squeezes more output from the XOF.
//
// Any call to Write after a call to Read will panic.
func (s *SHAKE) Read(p []byte) (n int, err error) {
if len(p) == 0 {
return 0, nil
}
defer runtime.KeepAlive(s)
for n < len(p) && err == nil {
nn := len32(p[n:])
err = bcrypt.FinishHash(s.ctx, p[n:n+nn], bcrypt.HASH_DONT_RESET_FLAG)
n += nn
}
if err != nil {
panic(err)
}
return len(p), nil
}

// Reset resets the XOF to its initial state.
func (s *SHAKE) Reset() {
defer runtime.KeepAlive(s)
bcrypt.DestroyHash(s.ctx)
err := bcrypt.CreateHash(s.alg.handle, &s.ctx, nil, nil, 0)
if err != nil {
panic(err)
}
if len(s.n) != 0 {
if err := bcrypt.SetProperty(bcrypt.HANDLE(s.ctx), utf16PtrFromString(bcrypt.FUNCTION_NAME_STRING), s.n, 0); err != nil {
panic(err)
}
}
if len(s.s) != 0 {
if err := bcrypt.SetProperty(bcrypt.HANDLE(s.ctx), utf16PtrFromString(bcrypt.CUSTOMIZATION_STRING), s.s, 0); err != nil {
panic(err)
}
}
}

// BlockSize returns the rate of the XOF.
func (s *SHAKE) BlockSize() int {
return int(s.alg.blockSize)
}
Loading

0 comments on commit 029af55

Please sign in to comment.