diff --git a/_cmptest/hmacdemo/hmac.go b/_cmptest/hmacdemo/hmac.go index 6d277096..e3d87f03 100644 --- a/_cmptest/hmacdemo/hmac.go +++ b/_cmptest/hmacdemo/hmac.go @@ -1,7 +1,15 @@ package main -import "crypto/hmac" +import ( + "crypto/hmac" + "crypto/sha1" + "fmt" + "io" +) func main() { - hmac.New(nil, []byte{'1', '2'}) + h := hmac.New(sha1.New, []byte("")) + io.WriteString(h, "The fog is getting thicker!") + io.WriteString(h, "And Leon's getting laaarger!") + fmt.Printf("%x", h.Sum(nil)) } diff --git a/c/openssl/hmac.go b/c/openssl/hmac.go index e95fc114..be86560c 100644 --- a/c/openssl/hmac.go +++ b/c/openssl/hmac.go @@ -6,7 +6,15 @@ import ( "github.com/goplus/llgo/c" ) -const EVP_MAX_MD_SIZE = 64 /* longest known is SHA512 */ +const ( + EVP_MAX_MD_SIZE = 64 /* longest known is SHA512 */ +) + +// ----------------------------------------------------------------------------- + +type EVP_MD struct { + Unused [0]byte +} // const EVP_MD *EVP_sha1(void) // @@ -43,9 +51,7 @@ func EVP_sha384() *EVP_MD //go:linkname EVP_sha512 C.EVP_sha512 func EVP_sha512() *EVP_MD -type EVP_MD struct { - Unused [0]byte -} +// ----------------------------------------------------------------------------- type HMAC_CTX struct { Unused [0]byte @@ -115,3 +121,5 @@ func (c *HMAC_CTX) Copy(sctx *HMAC_CTX) c.Int { return 0 } // // llgo:link (*HMAC_CTX).SetFlags C.HMAC_CTX_set_flags func (c *HMAC_CTX) SetFlags(flags c.Ulong) {} + +// ----------------------------------------------------------------------------- diff --git a/internal/lib/crypto/hmac/hmac.go b/internal/lib/crypto/hmac/hmac.go index e86bbb2a..120775b5 100644 --- a/internal/lib/crypto/hmac/hmac.go +++ b/internal/lib/crypto/hmac/hmac.go @@ -2,91 +2,10 @@ package hmac // llgo:skipall import ( - "bytes" - "fmt" + "crypto/subtle" "hash" - "unsafe" - - "github.com/goplus/llgo/c" - "github.com/goplus/llgo/c/openssl" ) -type marshalable interface { - MarshalBinary() ([]byte, error) - UnmarshalBinary([]byte) error -} - -type hmac struct { - opad, ipad []byte - outer, inner hash.Hash - // If marshaled is true, then opad and ipad do not contain a padded - // copy of the key, but rather the marshaled state of outer/inner after - // opad/ipad has been fed into it. - marshaled bool -} - -func (h *hmac) Sum(in []byte) []byte { - origLen := len(in) - in = h.inner.Sum(in) - - if h.marshaled { - if err := h.outer.(marshalable).UnmarshalBinary(h.opad); err != nil { - panic(err) - } - } else { - h.outer.Reset() - h.outer.Write(h.opad) - } - h.outer.Write(in[origLen:]) - return h.outer.Sum(in[:origLen]) -} - -func (h *hmac) Write(p []byte) (n int, err error) { - return h.inner.Write(p) -} - -func (h *hmac) Size() int { return h.outer.Size() } -func (h *hmac) BlockSize() int { return h.inner.BlockSize() } - -func (h *hmac) Reset() { - if h.marshaled { - if err := h.inner.(marshalable).UnmarshalBinary(h.ipad); err != nil { - panic(err) - } - return - } - h.inner.Reset() - h.inner.Write(h.ipad) - // If the underlying hash is marshalable, we can save some time by - // saving a copy of the hash state now, and restoring it on future - // calls to Reset and Sum instead of writing ipad/opad every time. - // - // If either hash is unmarshalable for whatever reason, - // it's safe to bail out here. - marshalableInner, innerOK := h.inner.(marshalable) - if !innerOK { - return - } - marshalableOuter, outerOK := h.outer.(marshalable) - if !outerOK { - return - } - imarshal, err := marshalableInner.MarshalBinary() - if err != nil { - return - } - h.outer.Reset() - h.outer.Write(h.opad) - omarshal, err := marshalableOuter.MarshalBinary() - if err != nil { - return - } - // Marshaling succeeded; save the marshaled state for later - h.ipad = imarshal - h.opad = omarshal - h.marshaled = true -} - // New returns a new HMAC hash using the given [hash.Hash] type and key. // New functions like sha256.New from [crypto/sha256] can be used as h. // h must return a new Hash every time it is called. @@ -94,50 +13,7 @@ func (h *hmac) Reset() { // the returned Hash does not implement [encoding.BinaryMarshaler] // or [encoding.BinaryUnmarshaler]. func New(h func() hash.Hash, key []byte) hash.Hash { - fmt.Println("My New") - return nil - if true { - hm := NewHMAC(h, key) - if hm != nil { - return hm - } - // BoringCrypto did not recognize h, so fall through to standard Go code. - } - hm := new(hmac) - hm.outer = h() - hm.inner = h() - unique := true - func() { - defer func() { - // The comparison might panic if the underlying types are not comparable. - _ = recover() - }() - if hm.outer == hm.inner { - unique = false - } - }() - if !unique { - panic("crypto/hmac: hash generation function does not produce unique values") - } - blocksize := hm.inner.BlockSize() - hm.ipad = make([]byte, blocksize) - hm.opad = make([]byte, blocksize) - if len(key) > blocksize { - // If key is too big, hash it. - hm.outer.Write(key) - key = hm.outer.Sum(nil) - } - copy(hm.ipad, key) - copy(hm.opad, key) - for i := range hm.ipad { - hm.ipad[i] ^= 0x36 - } - for i := range hm.opad { - hm.opad[i] ^= 0x5c - } - hm.inner.Write(hm.ipad) - - return hm + panic("todo") } // Equal compares two MACs for equality without leaking timing information. @@ -145,117 +21,5 @@ func Equal(mac1, mac2 []byte) bool { // We don't have to be constant time if the lengths of the MACs are // different as that suggests that a completely different hash function // was used. - return constantTimeCompare(mac1, mac2) == 1 -} - -func constantTimeCompare(x, y []byte) int { - if len(x) != len(y) { - return 0 - } - - var v byte - - for i := 0; i < len(x); i++ { - v |= x[i] ^ y[i] - } - - return constantTimeByteEq(v, 0) -} - -func constantTimeByteEq(x, y uint8) int { - return int((uint32(x^y) - 1) >> 31) -} - -type boringHMAC struct { - md *openssl.EVP_MD - ctx *openssl.HMAC_CTX - ctx2 *openssl.HMAC_CTX - size int - blockSize int - key []byte - sum []byte -} - -func (h *boringHMAC) Reset() { - if h.ctx != nil { - h.ctx.Free() - } - h.ctx = openssl.NewHMAC_CTX() - if h.ctx == nil { - panic("NewHMAC_CTX fail") - } - ret := h.ctx.Init(unsafe.Pointer(unsafe.SliceData(h.key)), c.Int(len(h.key)), h.md) - if ret == 0 { - panic("boringcrypto: HMAC_Init failed") - } - if c.Int(h.ctx.Size()) != c.Int(h.size) { - println("boringcrypto: HMAC size:", h.ctx.Size(), "!=", h.size) - panic("boringcrypto: HMAC size mismatch") - } - h.sum = nil -} - -func (h *boringHMAC) Write(p []byte) (int, error) { - if len(p) > 0 { - h.ctx.UpdateBytes(p) - } - //runtime.KeepAlive(h) - return len(p), nil -} - -func (h *boringHMAC) Size() int { - return h.size -} - -func (h *boringHMAC) BlockSize() int { - return h.blockSize -} - -func (h *boringHMAC) Sum(in []byte) []byte { - if h.sum == nil { - size := h.Size() - h.sum = make([]byte, size) - } - // Make copy of context because Go hash.Hash mandates - // that Sum has no effect on the underlying stream. - // In particular it is OK to Sum, then Write more, then Sum again, - // and the second Sum acts as if the first didn't happen. - h.ctx2 = openssl.NewHMAC_CTX() - if h.ctx2 == nil { - panic("NewHMAC_CTX fail") - } - ret := h.ctx.Copy(h.ctx2) - if ret == 0 { - panic("boringcrypto: HMAC_CTX_copy_ex failed") - } - var lenSum c.Uint = c.Uint(len(h.sum)) - h.ctx2.Final(&h.sum[0], &lenSum) - return append(in, h.sum...) -} - -func NewHMAC(h func() hash.Hash, key []byte) hash.Hash { - if h == nil { - panic("h == nil") - } - ch := h() - if ch == nil { - panic("ch == nil") - } - md := hashToMD(ch) - if md == nil { - panic("md == nil") - } - hkey := bytes.Clone(key) - hmac := &boringHMAC{ - md: md, - size: ch.Size(), - blockSize: ch.BlockSize(), - key: hkey, - } - hmac.Reset() - return hmac -} - -func hashToMD(h hash.Hash) *openssl.EVP_MD { - return openssl.EVP_sha1() + return subtle.ConstantTimeCompare(mac1, mac2) == 1 } diff --git a/internal/lib/internal/fmtsort/sort.go b/internal/lib/internal/fmtsort/sort.go new file mode 100644 index 00000000..13456a45 --- /dev/null +++ b/internal/lib/internal/fmtsort/sort.go @@ -0,0 +1,220 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package fmtsort provides a general stable ordering mechanism +// for maps, on behalf of the fmt and text/template packages. +// It is not guaranteed to be efficient and works only for types +// that are valid map keys. +package fmtsort + +// llgo:skipall +import ( + "reflect" + "sort" +) + +// Note: Throughout this package we avoid calling reflect.Value.Interface as +// it is not always legal to do so and it's easier to avoid the issue than to face it. + +// SortedMap represents a map's keys and values. The keys and values are +// aligned in index order: Value[i] is the value in the map corresponding to Key[i]. +type SortedMap struct { + Key []reflect.Value + Value []reflect.Value +} + +func (o *SortedMap) Len() int { return len(o.Key) } +func (o *SortedMap) Less(i, j int) bool { return compare(o.Key[i], o.Key[j]) < 0 } +func (o *SortedMap) Swap(i, j int) { + o.Key[i], o.Key[j] = o.Key[j], o.Key[i] + o.Value[i], o.Value[j] = o.Value[j], o.Value[i] +} + +// Sort accepts a map and returns a SortedMap that has the same keys and +// values but in a stable sorted order according to the keys, modulo issues +// raised by unorderable key values such as NaNs. +// +// The ordering rules are more general than with Go's < operator: +// +// - when applicable, nil compares low +// - ints, floats, and strings order by < +// - NaN compares less than non-NaN floats +// - bool compares false before true +// - complex compares real, then imag +// - pointers compare by machine address +// - channel values compare by machine address +// - structs compare each field in turn +// - arrays compare each element in turn. +// Otherwise identical arrays compare by length. +// - interface values compare first by reflect.Type describing the concrete type +// and then by concrete value as described in the previous rules. +func Sort(mapValue reflect.Value) *SortedMap { + if mapValue.Type().Kind() != reflect.Map { + return nil + } + // Note: this code is arranged to not panic even in the presence + // of a concurrent map update. The runtime is responsible for + // yelling loudly if that happens. See issue 33275. + n := mapValue.Len() + key := make([]reflect.Value, 0, n) + value := make([]reflect.Value, 0, n) + iter := mapValue.MapRange() + for iter.Next() { + key = append(key, iter.Key()) + value = append(value, iter.Value()) + } + sorted := &SortedMap{ + Key: key, + Value: value, + } + sort.Stable(sorted) + return sorted +} + +// compare compares two values of the same type. It returns -1, 0, 1 +// according to whether a > b (1), a == b (0), or a < b (-1). +// If the types differ, it returns -1. +// See the comment on Sort for the comparison rules. +func compare(aVal, bVal reflect.Value) int { + aType, bType := aVal.Type(), bVal.Type() + if aType != bType { + return -1 // No good answer possible, but don't return 0: they're not equal. + } + switch aVal.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + a, b := aVal.Int(), bVal.Int() + switch { + case a < b: + return -1 + case a > b: + return 1 + default: + return 0 + } + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + a, b := aVal.Uint(), bVal.Uint() + switch { + case a < b: + return -1 + case a > b: + return 1 + default: + return 0 + } + case reflect.String: + a, b := aVal.String(), bVal.String() + switch { + case a < b: + return -1 + case a > b: + return 1 + default: + return 0 + } + case reflect.Float32, reflect.Float64: + return floatCompare(aVal.Float(), bVal.Float()) + case reflect.Complex64, reflect.Complex128: + a, b := aVal.Complex(), bVal.Complex() + if c := floatCompare(real(a), real(b)); c != 0 { + return c + } + return floatCompare(imag(a), imag(b)) + case reflect.Bool: + a, b := aVal.Bool(), bVal.Bool() + switch { + case a == b: + return 0 + case a: + return 1 + default: + return -1 + } + case reflect.Pointer, reflect.UnsafePointer: + a, b := aVal.Pointer(), bVal.Pointer() + switch { + case a < b: + return -1 + case a > b: + return 1 + default: + return 0 + } + case reflect.Chan: + if c, ok := nilCompare(aVal, bVal); ok { + return c + } + ap, bp := aVal.Pointer(), bVal.Pointer() + switch { + case ap < bp: + return -1 + case ap > bp: + return 1 + default: + return 0 + } + case reflect.Struct: + for i := 0; i < aVal.NumField(); i++ { + if c := compare(aVal.Field(i), bVal.Field(i)); c != 0 { + return c + } + } + return 0 + case reflect.Array: + for i := 0; i < aVal.Len(); i++ { + if c := compare(aVal.Index(i), bVal.Index(i)); c != 0 { + return c + } + } + return 0 + case reflect.Interface: + if c, ok := nilCompare(aVal, bVal); ok { + return c + } + c := compare(reflect.ValueOf(aVal.Elem().Type()), reflect.ValueOf(bVal.Elem().Type())) + if c != 0 { + return c + } + return compare(aVal.Elem(), bVal.Elem()) + default: + // Certain types cannot appear as keys (maps, funcs, slices), but be explicit. + panic("bad type in compare: " + aType.String()) + } +} + +// nilCompare checks whether either value is nil. If not, the boolean is false. +// If either value is nil, the boolean is true and the integer is the comparison +// value. The comparison is defined to be 0 if both are nil, otherwise the one +// nil value compares low. Both arguments must represent a chan, func, +// interface, map, pointer, or slice. +func nilCompare(aVal, bVal reflect.Value) (int, bool) { + if aVal.IsNil() { + if bVal.IsNil() { + return 0, true + } + return -1, true + } + if bVal.IsNil() { + return 1, true + } + return 0, false +} + +// floatCompare compares two floating-point values. NaNs compare low. +func floatCompare(a, b float64) int { + switch { + case isNaN(a): + return -1 // No good answer if b is a NaN so don't bother checking. + case isNaN(b): + return 1 + case a < b: + return -1 + case a > b: + return 1 + } + return 0 +} + +func isNaN(a float64) bool { + return a != a +}