From a2b5b9f97e66dbe9823e7bb3b1648795c5b4ff86 Mon Sep 17 00:00:00 2001 From: xushiwei Date: Tue, 6 Aug 2024 17:03:22 +0800 Subject: [PATCH 1/3] library (todo): crypto/hmac, internal/fmtsort --- _cmptest/hmacdemo/hmac.go | 12 +- c/openssl/hmac.go | 16 +- internal/lib/crypto/hmac/hmac.go | 242 +------------------------- internal/lib/internal/fmtsort/sort.go | 220 +++++++++++++++++++++++ 4 files changed, 245 insertions(+), 245 deletions(-) create mode 100644 internal/lib/internal/fmtsort/sort.go 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 +} From 29c74c09ce4e613ab333af50f71f5322403942dc Mon Sep 17 00:00:00 2001 From: xushiwei Date: Tue, 6 Aug 2024 17:19:31 +0800 Subject: [PATCH 2/3] library/README: crypto/hmac, crypto/subtle --- README.md | 2 ++ internal/build/build.go | 5 +++-- internal/lib/crypto/sha1/sha1.go | 16 ++++++++++++++++ internal/lib/crypto/sha256/sha224.go | 16 ++++++++++++++++ internal/lib/crypto/sha256/sha256.go | 16 ++++++++++++++++ internal/lib/crypto/sha512/sha384.go | 16 ++++++++++++++++ internal/lib/crypto/sha512/sha512.go | 16 ++++++++++++++++ internal/lib/crypto/subtle/xor.go | 22 ++++++++++++++++++++++ 8 files changed, 107 insertions(+), 2 deletions(-) create mode 100644 internal/lib/crypto/subtle/xor.go diff --git a/README.md b/README.md index dadba11c..b586c2ed 100644 --- a/README.md +++ b/README.md @@ -312,7 +312,9 @@ Here are the Go packages that can be imported correctly: * [crypto/sha1](https://pkg.go.dev/crypto/sha1) * [crypto/sha256](https://pkg.go.dev/crypto/sha256) * [crypto/sha512](https://pkg.go.dev/crypto/sha512) (partially) +* [crypto/hmac](https://pkg.go.dev/crypto/hmac) (partially) * [crypto/rand](https://pkg.go.dev/crypto/rand) (partially) +* [crypto/subtle](https://pkg.go.dev/crypto/subtle) (partially) * [regexp](https://pkg.go.dev/regexp) * [regexp/syntax](https://pkg.go.dev/regexp/syntax) * [go/token](https://pkg.go.dev/go/token) diff --git a/internal/build/build.go b/internal/build/build.go index 5e0128db..aa59250a 100644 --- a/internal/build/build.go +++ b/internal/build/build.go @@ -757,12 +757,13 @@ func findDylibDep(exe, lib string) string { type none struct{} var hasAltPkg = map[string]none{ + "crypto/hmac": {}, "crypto/md5": {}, + "crypto/rand": {}, "crypto/sha1": {}, "crypto/sha256": {}, "crypto/sha512": {}, - "crypto/hmac": {}, - "crypto/rand": {}, + "crypto/subtle": {}, "fmt": {}, "hash/crc32": {}, "internal/abi": {}, diff --git a/internal/lib/crypto/sha1/sha1.go b/internal/lib/crypto/sha1/sha1.go index d804ef10..3e82b36a 100644 --- a/internal/lib/crypto/sha1/sha1.go +++ b/internal/lib/crypto/sha1/sha1.go @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package sha1 // llgo:skipall diff --git a/internal/lib/crypto/sha256/sha224.go b/internal/lib/crypto/sha256/sha224.go index 79d9d0da..bcc78050 100644 --- a/internal/lib/crypto/sha256/sha224.go +++ b/internal/lib/crypto/sha256/sha224.go @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package sha256 import ( diff --git a/internal/lib/crypto/sha256/sha256.go b/internal/lib/crypto/sha256/sha256.go index 4e4dcb00..c12df32f 100644 --- a/internal/lib/crypto/sha256/sha256.go +++ b/internal/lib/crypto/sha256/sha256.go @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package sha256 // llgo:skipall diff --git a/internal/lib/crypto/sha512/sha384.go b/internal/lib/crypto/sha512/sha384.go index ecfd18d7..a30e2be6 100644 --- a/internal/lib/crypto/sha512/sha384.go +++ b/internal/lib/crypto/sha512/sha384.go @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package sha512 import ( diff --git a/internal/lib/crypto/sha512/sha512.go b/internal/lib/crypto/sha512/sha512.go index 57790485..7e658d6a 100644 --- a/internal/lib/crypto/sha512/sha512.go +++ b/internal/lib/crypto/sha512/sha512.go @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package sha512 // llgo:skipall diff --git a/internal/lib/crypto/subtle/xor.go b/internal/lib/crypto/subtle/xor.go new file mode 100644 index 00000000..0fdeab90 --- /dev/null +++ b/internal/lib/crypto/subtle/xor.go @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package subtle + +// llgo:skip XORBytes +import ( + _ "unsafe" +) From dbed8fefac85696d286ede36b8d6ea0b00b0ad49 Mon Sep 17 00:00:00 2001 From: xushiwei Date: Tue, 6 Aug 2024 18:49:24 +0800 Subject: [PATCH 3/3] library: crypto/hmac --- c/openssl/hmac.go | 34 +++++++++++++--------- cl/instr.go | 2 +- internal/lib/crypto/hmac/hmac.go | 49 +++++++++++++++++++++++++++++++- 3 files changed, 70 insertions(+), 15 deletions(-) diff --git a/c/openssl/hmac.go b/c/openssl/hmac.go index be86560c..12e3af05 100644 --- a/c/openssl/hmac.go +++ b/c/openssl/hmac.go @@ -65,30 +65,38 @@ func NewHMAC_CTX() *HMAC_CTX // OSSL_DEPRECATEDIN_3_0 void HMAC_CTX_free(HMAC_CTX *ctx); // // llgo:link (*HMAC_CTX).Free C.HMAC_CTX_free -func (c *HMAC_CTX) Free() {} +func (ctx *HMAC_CTX) Free() {} // OSSL_DEPRECATEDIN_3_0 size_t HMAC_size(const HMAC_CTX *e); // // llgo:link (*HMAC_CTX).Size C.HMAC_size -func (c *HMAC_CTX) Size() uintptr { return 0 } +func (ctx *HMAC_CTX) Size() uintptr { return 0 } // OSSL_DEPRECATEDIN_3_0 int HMAC_CTX_reset(HMAC_CTX *ctx); // // llgo:link (*HMAC_CTX).Reset C.HMAC_CTX_reset -func (c *HMAC_CTX) Reset() c.Int { return 0 } +func (ctx *HMAC_CTX) Reset() c.Int { return 0 } // OSSL_DEPRECATEDIN_1_1_0 __owur int HMAC_Init(HMAC_CTX *ctx, // const void *key, int len, // const EVP_MD *md); // // llgo:link (*HMAC_CTX).Init C.HMAC_Init -func (c *HMAC_CTX) Init(key unsafe.Pointer, len c.Int, md *EVP_MD) c.Int { return 0 } +func (ctx *HMAC_CTX) Init(key unsafe.Pointer, len c.Int, md *EVP_MD) c.Int { return 0 } + +func (ctx *HMAC_CTX) InitBytes(key []byte, md *EVP_MD) c.Int { + return ctx.Init(unsafe.Pointer(unsafe.SliceData(key)), c.Int(len(key)), md) +} + +func (ctx *HMAC_CTX) InitString(key string, md *EVP_MD) c.Int { + return ctx.Init(unsafe.Pointer(unsafe.StringData(key)), c.Int(len(key)), md) +} // OSSL_DEPRECATEDIN_3_0 int HMAC_Init_ex(HMAC_CTX *ctx, const void *key, int len, // const EVP_MD *md, ENGINE *impl); // // llgo:link (*HMAC_CTX).InitEx C.HMAC_Init_ex -func (c *HMAC_CTX) InitEx(key unsafe.Pointer, len c.Int, md *EVP_MD, impl unsafe.Pointer) c.Int { +func (ctx *HMAC_CTX) InitEx(key unsafe.Pointer, len c.Int, md *EVP_MD, impl unsafe.Pointer) c.Int { return 0 } @@ -96,30 +104,30 @@ func (c *HMAC_CTX) InitEx(key unsafe.Pointer, len c.Int, md *EVP_MD, impl unsafe // size_t len); // // llgo:link (*HMAC_CTX).Update C.HMAC_Update -func (c *HMAC_CTX) Update(data unsafe.Pointer, len uintptr) c.Int { return 0 } +func (ctx *HMAC_CTX) Update(data unsafe.Pointer, len uintptr) c.Int { return 0 } -func (c *HMAC_CTX) UpdateBytes(data []byte) c.Int { - return c.Update(unsafe.Pointer(unsafe.SliceData(data)), uintptr(len(data))) +func (ctx *HMAC_CTX) UpdateBytes(data []byte) c.Int { + return ctx.Update(unsafe.Pointer(unsafe.SliceData(data)), uintptr(len(data))) } -func (c *HMAC_CTX) UpdateString(data string) c.Int { - return c.Update(unsafe.Pointer(unsafe.StringData(data)), uintptr(len(data))) +func (ctx *HMAC_CTX) UpdateString(data string) c.Int { + return ctx.Update(unsafe.Pointer(unsafe.StringData(data)), uintptr(len(data))) } // OSSL_DEPRECATEDIN_3_0 int HMAC_Final(HMAC_CTX *ctx, unsigned char *md, // unsigned int *len); // // llgo:link (*HMAC_CTX).Final C.HMAC_Final -func (c *HMAC_CTX) Final(md *byte, len *c.Uint) c.Int { return 0 } +func (ctx *HMAC_CTX) Final(md *byte, len *c.Uint) c.Int { return 0 } // OSSL_DEPRECATEDIN_3_0 __owur int HMAC_CTX_copy(HMAC_CTX *dctx, HMAC_CTX *sctx); // // llgo:link (*HMAC_CTX).Copy C.HMAC_CTX_copy -func (c *HMAC_CTX) Copy(sctx *HMAC_CTX) c.Int { return 0 } +func (ctx *HMAC_CTX) Copy(sctx *HMAC_CTX) c.Int { return 0 } // OSSL_DEPRECATEDIN_3_0 void HMAC_CTX_set_flags(HMAC_CTX *ctx, unsigned long flags); // // llgo:link (*HMAC_CTX).SetFlags C.HMAC_CTX_set_flags -func (c *HMAC_CTX) SetFlags(flags c.Ulong) {} +func (ctx *HMAC_CTX) SetFlags(flags c.Ulong) {} // ----------------------------------------------------------------------------- diff --git a/cl/instr.go b/cl/instr.go index 83837ad0..3585569c 100644 --- a/cl/instr.go +++ b/cl/instr.go @@ -133,7 +133,7 @@ func (p *context) stringData(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) } // func funcAddr(fn any) unsafe.Pointer -func (p *context) funcAddr(b llssa.Builder, args []ssa.Value) llssa.Expr { +func (p *context) funcAddr(_ llssa.Builder, args []ssa.Value) llssa.Expr { if len(args) == 1 { if fn, ok := args[0].(*ssa.MakeInterface); ok { if fnDecl, ok := fn.X.(*ssa.Function); ok { diff --git a/internal/lib/crypto/hmac/hmac.go b/internal/lib/crypto/hmac/hmac.go index 120775b5..3fb933d2 100644 --- a/internal/lib/crypto/hmac/hmac.go +++ b/internal/lib/crypto/hmac/hmac.go @@ -2,10 +2,48 @@ package hmac // llgo:skipall import ( + "crypto/sha256" "crypto/subtle" "hash" + "unsafe" + + "github.com/goplus/llgo/c" + "github.com/goplus/llgo/c/openssl" ) +type eface struct { + _type unsafe.Pointer + funcPtr *unsafe.Pointer +} + +func funcOf(a any) unsafe.Pointer { + e := (*eface)(unsafe.Pointer(&a)) + return *e.funcPtr +} + +type digest openssl.HMAC_CTX + +func (d *digest) Size() int { panic("todo: hmac.(*digest).Size") } + +func (d *digest) BlockSize() int { panic("todo: hmac.(*digest).BlockSize") } + +func (d *digest) Reset() { + (*openssl.HMAC_CTX)(d).Reset() +} + +func (d *digest) Write(p []byte) (nn int, err error) { + (*openssl.HMAC_CTX)(d).UpdateBytes(p) + return len(p), nil +} + +func (d *digest) Sum(in []byte) []byte { + const Size = openssl.EVP_MAX_MD_SIZE + var digestLen c.Uint + hash := (*[Size]byte)(c.Alloca(Size)) + (*openssl.HMAC_CTX)(d).Final(&hash[0], &digestLen) + return append(in, hash[:digestLen]...) +} + // 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. @@ -13,7 +51,16 @@ import ( // the returned Hash does not implement [encoding.BinaryMarshaler] // or [encoding.BinaryUnmarshaler]. func New(h func() hash.Hash, key []byte) hash.Hash { - panic("todo") + var md *openssl.EVP_MD + switch funcOf(h) { + case c.Func(sha256.New): + md = openssl.EVP_sha256() + default: + panic("todo: hmac.New: unsupported hash function") + } + ctx := openssl.NewHMAC_CTX() + ctx.InitBytes(key, md) + return (*digest)(ctx) } // Equal compares two MACs for equality without leaking timing information.