Bump Alizer to fix potential panic when analyzing large projects (#6926)

* Bump Alizer to the latest commit at this time [1]

Amongst other things, this fixes an issue when analyzing large projects,
by preventing potential panics when trying to detect application ports.

[1] 14114f066c

* Downgrade and pin the versions of 'sigs.k8s.io/controller-runtime' and 'k8s.io/*' to the previous versions we had

Bumping Alizer bumped these packages to upper versions,
which seems to cause build errors due to Service Binding Operator
libraries not compatible with those new versions.
See the error below.

Since we don't want to update SBO libraries at this time
(as SBO is currently in maintenance mode only),
this makes sure we are using the versions it builds against.

Build error for reference:
```
go install -mod=vendor -ldflags="-X github.com/redhat-developer/odo/pkg/version.GITCOMMIT=cb9c13900" ./cmd/odo/
# github.com/redhat-developer/service-binding-operator/apis/spec/v1alpha3
vendor/github.com/redhat-developer/service-binding-operator/apis/spec/v1alpha3/servicebinding_webhook.go:44:27: cannot use &ServiceBinding{} (value of type *ServiceBinding) as type admission.Validator in variable declaration:
        *ServiceBinding does not implement admission.Validator (wrong type for ValidateCreate method)
                have ValidateCreate() error
                want ValidateCreate() (warnings admission.Warnings, err error)
# github.com/redhat-developer/service-binding-operator/apis/binding/v1alpha1
vendor/github.com/redhat-developer/service-binding-operator/apis/binding/v1alpha1/servicebinding_webhook.go:37:27: cannot use &ServiceBinding{} (value of type *ServiceBinding) as type admission.Validator in variable declaration:
        *ServiceBinding does not implement admission.Validator (wrong type for ValidateCreate method)
                have ValidateCreate() error
                want ValidateCreate() (warnings admission.Warnings, err error)
make: *** [Makefile:90: install] Error 2
```

* Fix expected output in doc automation tests
This commit is contained in:
Armel Soro
2023-06-27 09:34:38 +02:00
committed by GitHub
parent bfa125e4b0
commit 324d73fb37
640 changed files with 29395 additions and 6858 deletions

View File

@@ -11,6 +11,7 @@ Interactive mode enabled, please answer the following questions:
Based on the files in the current directory odo detected
Language: JavaScript
Project type: Node.js
Application ports: 3000
The devfile "nodejs:2.1.1" from the registry "DefaultDevfileRegistry" will be downloaded.
? Is this correct? Yes
✓ Downloading devfile "nodejs:2.1.1" from registry "DefaultDevfileRegistry" [3s]

107
go.mod
View File

@@ -28,8 +28,8 @@ require (
github.com/mattn/go-colorable v0.1.13
github.com/olekukonko/tablewriter v0.0.5
github.com/onsi/ginkgo v1.16.5
github.com/onsi/ginkgo/v2 v2.8.0
github.com/onsi/gomega v1.26.0
github.com/onsi/ginkgo/v2 v2.9.5
github.com/onsi/gomega v1.27.7
github.com/openshift/api v0.0.0-20220525145417-ee5b62754c68
github.com/openshift/client-go v0.0.0-20220603133046-984ee5ebedcf
github.com/openshift/oc v0.0.0-alpha.0.0.20220402064836-f1f09a392fd1
@@ -37,36 +37,36 @@ require (
github.com/operator-framework/operator-lifecycle-manager v0.21.2
github.com/pborman/uuid v1.2.1
github.com/posener/complete v1.2.3
github.com/redhat-developer/alizer/go v0.0.0-20230331140053-a1115da45e0c
github.com/redhat-developer/alizer/go v0.0.0-20230619172619-14114f066cef
github.com/redhat-developer/service-binding-operator v1.0.1-0.20211222115357-5b7bbba3bfb3
github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06
github.com/securego/gosec/v2 v2.15.0
github.com/segmentio/backo-go v1.0.1
github.com/sethvargo/go-envconfig v0.9.0
github.com/spf13/afero v1.6.0
github.com/spf13/cobra v1.6.1
github.com/spf13/cobra v1.7.0
github.com/spf13/pflag v1.0.5
github.com/tidwall/gjson v1.14.4
github.com/zalando/go-keyring v0.2.1
golang.org/x/sync v0.1.0
golang.org/x/sys v0.5.0
golang.org/x/term v0.5.0
golang.org/x/text v0.7.0
golang.org/x/sync v0.2.0
golang.org/x/sys v0.8.0
golang.org/x/term v0.8.0
golang.org/x/text v0.9.0
gopkg.in/AlecAivazis/survey.v1 v1.8.8
gopkg.in/segmentio/analytics-go.v3 v3.0.0-00010101000000-000000000000
gopkg.in/yaml.v2 v2.4.0
gopkg.in/yaml.v3 v3.0.1
k8s.io/api v0.26.1
k8s.io/apiextensions-apiserver v0.26.1
k8s.io/apimachinery v0.26.1
k8s.io/api v0.27.2
k8s.io/apiextensions-apiserver v0.27.2
k8s.io/apimachinery v0.27.2
k8s.io/cli-runtime v0.24.0
k8s.io/client-go v0.26.1
k8s.io/client-go v0.27.2
k8s.io/klog v1.0.0
k8s.io/klog/v2 v2.80.1
k8s.io/klog/v2 v2.90.1
k8s.io/kubectl v0.24.0
k8s.io/pod-security-admission v0.26.1
k8s.io/utils v0.0.0-20221128185143-99ec85e7a448
sigs.k8s.io/controller-runtime v0.14.4
k8s.io/utils v0.0.0-20230209194617-a36077c30491
sigs.k8s.io/controller-runtime v0.15.0
sigs.k8s.io/yaml v1.3.0
)
@@ -76,9 +76,9 @@ require (
github.com/ActiveState/vt10x v1.3.1 // indirect
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd // indirect
github.com/Microsoft/go-winio v0.6.0 // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 // indirect
github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 // indirect
github.com/ProtonMail/go-crypto v0.0.0-20230417170513-8ee5748c52b5 // indirect
github.com/RangelReale/osincli v0.0.0-20160924135400-fababb0555f2 // indirect
github.com/acomagu/bufpipe v1.0.4 // indirect
github.com/alessio/shellescape v1.4.1 // indirect
@@ -86,12 +86,12 @@ require (
github.com/apcera/gssapi v0.0.0-00010101000000-000000000000 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/blang/semver/v4 v4.0.0 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 // indirect
github.com/cloudflare/circl v1.3.1 // indirect
github.com/cloudflare/circl v1.3.2 // indirect
github.com/containerd/containerd v1.6.3-0.20220401172941-5ff8fce1fcc6 // indirect
github.com/containerd/typeurl v1.0.2 // indirect
github.com/creack/pty v1.1.17 // indirect
github.com/creack/pty v1.1.18 // indirect
github.com/danieljoos/wincred v1.1.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/distribution/distribution/v3 v3.0.0-20211118083504-a29a3c99a684 // indirect
@@ -111,14 +111,15 @@ require (
github.com/go-errors/errors v1.0.1 // indirect
github.com/go-git/gcfg v1.5.0 // indirect
github.com/go-git/go-billy/v5 v5.4.1 // indirect
github.com/go-logr/logr v1.2.3 // indirect
github.com/go-logr/logr v1.2.4 // indirect
github.com/go-logr/zapr v1.2.4 // indirect
github.com/go-openapi/swag v0.22.3 // indirect
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/gobwas/glob v0.2.3 // indirect
github.com/godbus/dbus/v5 v5.0.6 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/btree v1.0.1 // indirect
github.com/google/gnostic v0.5.7-v3refs // indirect
github.com/google/gofuzz v1.2.0 // indirect
@@ -132,8 +133,8 @@ require (
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-version v1.4.0 // indirect
github.com/hinshun/vt10x v0.0.0-20220301184237-5011da428d02 // indirect
github.com/imdario/mergo v0.3.13 // indirect
github.com/inconshreveable/mousetrap v1.0.1 // indirect
github.com/imdario/mergo v0.3.15 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/jessevdk/go-flags v1.5.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
@@ -146,14 +147,14 @@ require (
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-isatty v0.0.17 // indirect
github.com/mattn/go-runewidth v0.0.13 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.2 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
github.com/mitchellh/go-wordwrap v1.0.0 // indirect
github.com/mitchellh/reflectwalk v1.0.1 // indirect
github.com/moby/buildkit v0.10.6 // indirect
github.com/moby/locker v1.0.1 // indirect
github.com/moby/spdystream v0.2.0 // indirect
github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae // indirect
github.com/moby/term v0.0.0-20221205130635-1aeaba878587 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
@@ -167,14 +168,14 @@ require (
github.com/pjbgf/sha1cd v0.3.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_golang v1.14.0 // indirect
github.com/prometheus/client_model v0.3.0 // indirect
github.com/prometheus/common v0.37.0 // indirect
github.com/prometheus/procfs v0.8.0 // indirect
github.com/prometheus/client_golang v1.15.1 // indirect
github.com/prometheus/client_model v0.4.0 // indirect
github.com/prometheus/common v0.42.0 // indirect
github.com/prometheus/procfs v0.9.0 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/russross/blackfriday v1.5.2 // indirect
github.com/sergi/go-diff v1.2.0 // indirect
github.com/sirupsen/logrus v1.8.1 // indirect
github.com/sergi/go-diff v1.3.1 // indirect
github.com/sirupsen/logrus v1.9.0 // indirect
github.com/skeema/knownhosts v1.1.0 // indirect
github.com/stretchr/testify v1.8.1 // indirect
github.com/tidwall/match v1.1.1 // indirect
@@ -186,24 +187,27 @@ require (
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca // indirect
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect
golang.org/x/crypto v0.6.0 // indirect
golang.org/x/mod v0.7.0 // indirect
golang.org/x/net v0.7.0 // indirect
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 // indirect
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.6.0 // indirect
go.uber.org/zap v1.24.0 // indirect
golang.org/x/crypto v0.8.0 // indirect
golang.org/x/mod v0.10.0 // indirect
golang.org/x/net v0.10.0 // indirect
golang.org/x/oauth2 v0.5.0 // indirect
golang.org/x/time v0.3.0 // indirect
golang.org/x/tools v0.5.0 // indirect
gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
golang.org/x/tools v0.9.1 // indirect
gomodules.xyz/jsonpatch/v2 v2.3.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21 // indirect
google.golang.org/grpc v1.49.0 // indirect
google.golang.org/protobuf v1.28.1 // indirect
google.golang.org/grpc v1.51.0 // indirect
google.golang.org/protobuf v1.30.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
k8s.io/apiserver v0.26.1 // indirect
k8s.io/component-base v0.26.1 // indirect
k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 // indirect
k8s.io/apiserver v0.27.2 // indirect
k8s.io/component-base v0.27.2 // indirect
k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f // indirect
oras.land/oras-go v1.1.0 // indirect
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/kustomize/api v0.11.4 // indirect
sigs.k8s.io/kustomize/kyaml v0.13.6 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
@@ -212,3 +216,16 @@ require (
replace gopkg.in/segmentio/analytics-go.v3 => github.com/segmentio/analytics-go/v3 v3.2.1
replace github.com/apcera/gssapi => github.com/openshift/gssapi v0.0.0-20161010215902-5fb4217df13b
// We are pinning the versions here because bumping Alizer bumped these packages to upper versions,
// which were not compatible with the Service Binding Operator (SBO) version at this time.
// Example error: *ServiceBinding does not implement admission.Validator (wrong type for ValidateCreate method)
// But we don't want to update SBO libraries at this time, as SBO is currently in maintenance mode only.
// TODO(rm3l): remove these when we remove support for SBO.
replace (
k8s.io/api => k8s.io/api v0.26.1
k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.26.1
k8s.io/apimachinery => k8s.io/apimachinery v0.26.1
k8s.io/client-go => k8s.io/client-go v0.26.1
sigs.k8s.io/controller-runtime => sigs.k8s.io/controller-runtime v0.14.4
)

433
go.sum

File diff suppressed because it is too large Load Diff

View File

@@ -8,12 +8,8 @@ linters:
- containedctx # struct contains a context
- dupl # duplicate code
- errname # erorrs are named correctly
- goconst # strings that should be constants
- godot # comments end in a period
- misspell
- nolintlint # "//nolint" directives are properly explained
- revive # golint replacement
- stylecheck # golint replacement, less configurable than revive
- unconvert # unnecessary conversions
- wastedassign
@@ -23,10 +19,7 @@ linters:
- exhaustive # check exhaustiveness of enum switch statements
- gofmt # files are gofmt'ed
- gosec # security
- nestif # deeply nested ifs
- nilerr # returns nil even with non-nil error
- prealloc # slices that can be pre-allocated
- structcheck # unused struct fields
- unparam # unused function params
issues:
@@ -42,6 +35,18 @@ issues:
text: "^line-length-limit: "
source: "^//(go:generate|sys) "
#TODO: remove after upgrading to go1.18
# ignore comment spacing for nolint and sys directives
- linters:
- revive
text: "^comment-spacings: no space between comment delimiter and comment text"
source: "//(cspell:|nolint:|sys |todo)"
# not on go 1.18 yet, so no any
- linters:
- revive
text: "^use-any: since GO 1.18 'interface{}' can be replaced by 'any'"
# allow unjustified ignores of error checks in defer statements
- linters:
- nolintlint
@@ -56,6 +61,8 @@ issues:
linters-settings:
exhaustive:
default-signifies-exhaustive: true
govet:
enable-all: true
disable:
@@ -98,6 +105,8 @@ linters-settings:
disabled: true
- name: flag-parameter # excessive, and a common idiom we use
disabled: true
- name: unhandled-error # warns over common fmt.Print* and io.Close; rely on errcheck instead
disabled: true
# general config
- name: line-length-limit
arguments:
@@ -138,7 +147,3 @@ linters-settings:
- VPCI
- WCOW
- WIM
stylecheck:
checks:
- "all"
- "-ST1003" # use revive's var naming

View File

@@ -23,7 +23,7 @@ import (
const afHVSock = 34 // AF_HYPERV
// Well known Service and VM IDs
//https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/user-guide/make-integration-service#vmid-wildcards
// https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/user-guide/make-integration-service#vmid-wildcards
// HvsockGUIDWildcard is the wildcard VmId for accepting connections from all partitions.
func HvsockGUIDWildcard() guid.GUID { // 00000000-0000-0000-0000-000000000000
@@ -31,7 +31,7 @@ func HvsockGUIDWildcard() guid.GUID { // 00000000-0000-0000-0000-000000000000
}
// HvsockGUIDBroadcast is the wildcard VmId for broadcasting sends to all partitions.
func HvsockGUIDBroadcast() guid.GUID { //ffffffff-ffff-ffff-ffff-ffffffffffff
func HvsockGUIDBroadcast() guid.GUID { // ffffffff-ffff-ffff-ffff-ffffffffffff
return guid.GUID{
Data1: 0xffffffff,
Data2: 0xffff,
@@ -246,7 +246,7 @@ func (l *HvsockListener) Accept() (_ net.Conn, err error) {
var addrbuf [addrlen * 2]byte
var bytes uint32
err = syscall.AcceptEx(l.sock.handle, sock.handle, &addrbuf[0], 0 /*rxdatalen*/, addrlen, addrlen, &bytes, &c.o)
err = syscall.AcceptEx(l.sock.handle, sock.handle, &addrbuf[0], 0 /* rxdatalen */, addrlen, addrlen, &bytes, &c.o)
if _, err = l.sock.asyncIO(c, nil, bytes, err); err != nil {
return nil, l.opErr("accept", os.NewSyscallError("acceptex", err))
}

View File

@@ -0,0 +1,2 @@
// This package contains Win32 filesystem functionality.
package fs

202
vendor/github.com/Microsoft/go-winio/internal/fs/fs.go generated vendored Normal file
View File

@@ -0,0 +1,202 @@
//go:build windows
package fs
import (
"golang.org/x/sys/windows"
"github.com/Microsoft/go-winio/internal/stringbuffer"
)
//go:generate go run github.com/Microsoft/go-winio/tools/mkwinsyscall -output zsyscall_windows.go fs.go
// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew
//sys CreateFile(name string, access AccessMask, mode FileShareMode, sa *syscall.SecurityAttributes, createmode FileCreationDisposition, attrs FileFlagOrAttribute, templatefile windows.Handle) (handle windows.Handle, err error) [failretval==windows.InvalidHandle] = CreateFileW
const NullHandle windows.Handle = 0
// AccessMask defines standard, specific, and generic rights.
//
// Bitmask:
// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
// +---------------+---------------+-------------------------------+
// |G|G|G|G|Resvd|A| StandardRights| SpecificRights |
// |R|W|E|A| |S| | |
// +-+-------------+---------------+-------------------------------+
//
// GR Generic Read
// GW Generic Write
// GE Generic Exectue
// GA Generic All
// Resvd Reserved
// AS Access Security System
//
// https://learn.microsoft.com/en-us/windows/win32/secauthz/access-mask
//
// https://learn.microsoft.com/en-us/windows/win32/secauthz/generic-access-rights
//
// https://learn.microsoft.com/en-us/windows/win32/fileio/file-access-rights-constants
type AccessMask = windows.ACCESS_MASK
//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
const (
// Not actually any.
//
// For CreateFile: "query certain metadata such as file, directory, or device attributes without accessing that file or device"
// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew#parameters
FILE_ANY_ACCESS AccessMask = 0
// Specific Object Access
// from ntioapi.h
FILE_READ_DATA AccessMask = (0x0001) // file & pipe
FILE_LIST_DIRECTORY AccessMask = (0x0001) // directory
FILE_WRITE_DATA AccessMask = (0x0002) // file & pipe
FILE_ADD_FILE AccessMask = (0x0002) // directory
FILE_APPEND_DATA AccessMask = (0x0004) // file
FILE_ADD_SUBDIRECTORY AccessMask = (0x0004) // directory
FILE_CREATE_PIPE_INSTANCE AccessMask = (0x0004) // named pipe
FILE_READ_EA AccessMask = (0x0008) // file & directory
FILE_READ_PROPERTIES AccessMask = FILE_READ_EA
FILE_WRITE_EA AccessMask = (0x0010) // file & directory
FILE_WRITE_PROPERTIES AccessMask = FILE_WRITE_EA
FILE_EXECUTE AccessMask = (0x0020) // file
FILE_TRAVERSE AccessMask = (0x0020) // directory
FILE_DELETE_CHILD AccessMask = (0x0040) // directory
FILE_READ_ATTRIBUTES AccessMask = (0x0080) // all
FILE_WRITE_ATTRIBUTES AccessMask = (0x0100) // all
FILE_ALL_ACCESS AccessMask = (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1FF)
FILE_GENERIC_READ AccessMask = (STANDARD_RIGHTS_READ | FILE_READ_DATA | FILE_READ_ATTRIBUTES | FILE_READ_EA | SYNCHRONIZE)
FILE_GENERIC_WRITE AccessMask = (STANDARD_RIGHTS_WRITE | FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | FILE_APPEND_DATA | SYNCHRONIZE)
FILE_GENERIC_EXECUTE AccessMask = (STANDARD_RIGHTS_EXECUTE | FILE_READ_ATTRIBUTES | FILE_EXECUTE | SYNCHRONIZE)
SPECIFIC_RIGHTS_ALL AccessMask = 0x0000FFFF
// Standard Access
// from ntseapi.h
DELETE AccessMask = 0x0001_0000
READ_CONTROL AccessMask = 0x0002_0000
WRITE_DAC AccessMask = 0x0004_0000
WRITE_OWNER AccessMask = 0x0008_0000
SYNCHRONIZE AccessMask = 0x0010_0000
STANDARD_RIGHTS_REQUIRED AccessMask = 0x000F_0000
STANDARD_RIGHTS_READ AccessMask = READ_CONTROL
STANDARD_RIGHTS_WRITE AccessMask = READ_CONTROL
STANDARD_RIGHTS_EXECUTE AccessMask = READ_CONTROL
STANDARD_RIGHTS_ALL AccessMask = 0x001F_0000
)
type FileShareMode uint32
//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
const (
FILE_SHARE_NONE FileShareMode = 0x00
FILE_SHARE_READ FileShareMode = 0x01
FILE_SHARE_WRITE FileShareMode = 0x02
FILE_SHARE_DELETE FileShareMode = 0x04
FILE_SHARE_VALID_FLAGS FileShareMode = 0x07
)
type FileCreationDisposition uint32
//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
const (
// from winbase.h
CREATE_NEW FileCreationDisposition = 0x01
CREATE_ALWAYS FileCreationDisposition = 0x02
OPEN_EXISTING FileCreationDisposition = 0x03
OPEN_ALWAYS FileCreationDisposition = 0x04
TRUNCATE_EXISTING FileCreationDisposition = 0x05
)
// CreateFile and co. take flags or attributes together as one parameter.
// Define alias until we can use generics to allow both
// https://learn.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants
type FileFlagOrAttribute uint32
//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
const ( // from winnt.h
FILE_FLAG_WRITE_THROUGH FileFlagOrAttribute = 0x8000_0000
FILE_FLAG_OVERLAPPED FileFlagOrAttribute = 0x4000_0000
FILE_FLAG_NO_BUFFERING FileFlagOrAttribute = 0x2000_0000
FILE_FLAG_RANDOM_ACCESS FileFlagOrAttribute = 0x1000_0000
FILE_FLAG_SEQUENTIAL_SCAN FileFlagOrAttribute = 0x0800_0000
FILE_FLAG_DELETE_ON_CLOSE FileFlagOrAttribute = 0x0400_0000
FILE_FLAG_BACKUP_SEMANTICS FileFlagOrAttribute = 0x0200_0000
FILE_FLAG_POSIX_SEMANTICS FileFlagOrAttribute = 0x0100_0000
FILE_FLAG_OPEN_REPARSE_POINT FileFlagOrAttribute = 0x0020_0000
FILE_FLAG_OPEN_NO_RECALL FileFlagOrAttribute = 0x0010_0000
FILE_FLAG_FIRST_PIPE_INSTANCE FileFlagOrAttribute = 0x0008_0000
)
type FileSQSFlag = FileFlagOrAttribute
//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
const ( // from winbase.h
SECURITY_ANONYMOUS FileSQSFlag = FileSQSFlag(SecurityAnonymous << 16)
SECURITY_IDENTIFICATION FileSQSFlag = FileSQSFlag(SecurityIdentification << 16)
SECURITY_IMPERSONATION FileSQSFlag = FileSQSFlag(SecurityImpersonation << 16)
SECURITY_DELEGATION FileSQSFlag = FileSQSFlag(SecurityDelegation << 16)
SECURITY_SQOS_PRESENT FileSQSFlag = 0x00100000
SECURITY_VALID_SQOS_FLAGS FileSQSFlag = 0x001F0000
)
// GetFinalPathNameByHandle flags
//
// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfinalpathnamebyhandlew#parameters
type GetFinalPathFlag uint32
//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
const (
GetFinalPathDefaultFlag GetFinalPathFlag = 0x0
FILE_NAME_NORMALIZED GetFinalPathFlag = 0x0
FILE_NAME_OPENED GetFinalPathFlag = 0x8
VOLUME_NAME_DOS GetFinalPathFlag = 0x0
VOLUME_NAME_GUID GetFinalPathFlag = 0x1
VOLUME_NAME_NT GetFinalPathFlag = 0x2
VOLUME_NAME_NONE GetFinalPathFlag = 0x4
)
// getFinalPathNameByHandle facilitates calling the Windows API GetFinalPathNameByHandle
// with the given handle and flags. It transparently takes care of creating a buffer of the
// correct size for the call.
//
// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfinalpathnamebyhandlew
func GetFinalPathNameByHandle(h windows.Handle, flags GetFinalPathFlag) (string, error) {
b := stringbuffer.NewWString()
//TODO: can loop infinitely if Win32 keeps returning the same (or a larger) n?
for {
n, err := windows.GetFinalPathNameByHandle(h, b.Pointer(), b.Cap(), uint32(flags))
if err != nil {
return "", err
}
// If the buffer wasn't large enough, n will be the total size needed (including null terminator).
// Resize and try again.
if n > b.Cap() {
b.ResizeTo(n)
continue
}
// If the buffer is large enough, n will be the size not including the null terminator.
// Convert to a Go string and return.
return b.String(), nil
}
}

View File

@@ -0,0 +1,12 @@
package fs
// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ne-winnt-security_impersonation_level
type SecurityImpersonationLevel int32 // C default enums underlying type is `int`, which is Go `int32`
// Impersonation levels
const (
SecurityAnonymous SecurityImpersonationLevel = 0
SecurityIdentification SecurityImpersonationLevel = 1
SecurityImpersonation SecurityImpersonationLevel = 2
SecurityDelegation SecurityImpersonationLevel = 3
)

View File

@@ -0,0 +1,64 @@
//go:build windows
// Code generated by 'go generate' using "github.com/Microsoft/go-winio/tools/mkwinsyscall"; DO NOT EDIT.
package fs
import (
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
var _ unsafe.Pointer
// Do the interface allocations only once for common
// Errno values.
const (
errnoERROR_IO_PENDING = 997
)
var (
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
errERROR_EINVAL error = syscall.EINVAL
)
// errnoErr returns common boxed Errno values, to prevent
// allocations at runtime.
func errnoErr(e syscall.Errno) error {
switch e {
case 0:
return errERROR_EINVAL
case errnoERROR_IO_PENDING:
return errERROR_IO_PENDING
}
// TODO: add more here, after collecting data on the common
// error values see on Windows. (perhaps when running
// all.bat?)
return e
}
var (
modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
procCreateFileW = modkernel32.NewProc("CreateFileW")
)
func CreateFile(name string, access AccessMask, mode FileShareMode, sa *syscall.SecurityAttributes, createmode FileCreationDisposition, attrs FileFlagOrAttribute, templatefile windows.Handle) (handle windows.Handle, err error) {
var _p0 *uint16
_p0, err = syscall.UTF16PtrFromString(name)
if err != nil {
return
}
return _CreateFile(_p0, access, mode, sa, createmode, attrs, templatefile)
}
func _CreateFile(name *uint16, access AccessMask, mode FileShareMode, sa *syscall.SecurityAttributes, createmode FileCreationDisposition, attrs FileFlagOrAttribute, templatefile windows.Handle) (handle windows.Handle, err error) {
r0, _, e1 := syscall.Syscall9(procCreateFileW.Addr(), 7, uintptr(unsafe.Pointer(name)), uintptr(access), uintptr(mode), uintptr(unsafe.Pointer(sa)), uintptr(createmode), uintptr(attrs), uintptr(templatefile), 0, 0)
handle = windows.Handle(r0)
if handle == windows.InvalidHandle {
err = errnoErr(e1)
}
return
}

View File

@@ -100,8 +100,8 @@ func (f *runtimeFunc) Load() error {
(*byte)(unsafe.Pointer(&f.addr)),
uint32(unsafe.Sizeof(f.addr)),
&n,
nil, //overlapped
0, //completionRoutine
nil, // overlapped
0, // completionRoutine
)
})
return f.err

View File

@@ -0,0 +1,132 @@
package stringbuffer
import (
"sync"
"unicode/utf16"
)
// TODO: worth exporting and using in mkwinsyscall?
// Uint16BufferSize is the buffer size in the pool, chosen somewhat arbitrarily to accommodate
// large path strings:
// MAX_PATH (260) + size of volume GUID prefix (49) + null terminator = 310.
const MinWStringCap = 310
// use *[]uint16 since []uint16 creates an extra allocation where the slice header
// is copied to heap and then referenced via pointer in the interface header that sync.Pool
// stores.
var pathPool = sync.Pool{ // if go1.18+ adds Pool[T], use that to store []uint16 directly
New: func() interface{} {
b := make([]uint16, MinWStringCap)
return &b
},
}
func newBuffer() []uint16 { return *(pathPool.Get().(*[]uint16)) }
// freeBuffer copies the slice header data, and puts a pointer to that in the pool.
// This avoids taking a pointer to the slice header in WString, which can be set to nil.
func freeBuffer(b []uint16) { pathPool.Put(&b) }
// WString is a wide string buffer ([]uint16) meant for storing UTF-16 encoded strings
// for interacting with Win32 APIs.
// Sizes are specified as uint32 and not int.
//
// It is not thread safe.
type WString struct {
// type-def allows casting to []uint16 directly, use struct to prevent that and allow adding fields in the future.
// raw buffer
b []uint16
}
// NewWString returns a [WString] allocated from a shared pool with an
// initial capacity of at least [MinWStringCap].
// Since the buffer may have been previously used, its contents are not guaranteed to be empty.
//
// The buffer should be freed via [WString.Free]
func NewWString() *WString {
return &WString{
b: newBuffer(),
}
}
func (b *WString) Free() {
if b.empty() {
return
}
freeBuffer(b.b)
b.b = nil
}
// ResizeTo grows the buffer to at least c and returns the new capacity, freeing the
// previous buffer back into pool.
func (b *WString) ResizeTo(c uint32) uint32 {
// allready sufficient (or n is 0)
if c <= b.Cap() {
return b.Cap()
}
if c <= MinWStringCap {
c = MinWStringCap
}
// allocate at-least double buffer size, as is done in [bytes.Buffer] and other places
if c <= 2*b.Cap() {
c = 2 * b.Cap()
}
b2 := make([]uint16, c)
if !b.empty() {
copy(b2, b.b)
freeBuffer(b.b)
}
b.b = b2
return c
}
// Buffer returns the underlying []uint16 buffer.
func (b *WString) Buffer() []uint16 {
if b.empty() {
return nil
}
return b.b
}
// Pointer returns a pointer to the first uint16 in the buffer.
// If the [WString.Free] has already been called, the pointer will be nil.
func (b *WString) Pointer() *uint16 {
if b.empty() {
return nil
}
return &b.b[0]
}
// String returns the returns the UTF-8 encoding of the UTF-16 string in the buffer.
//
// It assumes that the data is null-terminated.
func (b *WString) String() string {
// Using [windows.UTF16ToString] would require importing "golang.org/x/sys/windows"
// and would make this code Windows-only, which makes no sense.
// So copy UTF16ToString code into here.
// If other windows-specific code is added, switch to [windows.UTF16ToString]
s := b.b
for i, v := range s {
if v == 0 {
s = s[:i]
break
}
}
return string(utf16.Decode(s))
}
// Cap returns the underlying buffer capacity.
func (b *WString) Cap() uint32 {
if b.empty() {
return 0
}
return b.cap()
}
func (b *WString) cap() uint32 { return uint32(cap(b.b)) }
func (b *WString) empty() bool { return b == nil || b.cap() == 0 }

View File

@@ -16,11 +16,12 @@ import (
"unsafe"
"golang.org/x/sys/windows"
"github.com/Microsoft/go-winio/internal/fs"
)
//sys connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) = ConnectNamedPipe
//sys createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *syscall.SecurityAttributes) (handle syscall.Handle, err error) [failretval==syscall.InvalidHandle] = CreateNamedPipeW
//sys createFile(name string, access uint32, mode uint32, sa *syscall.SecurityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) [failretval==syscall.InvalidHandle] = CreateFileW
//sys getNamedPipeInfo(pipe syscall.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) = GetNamedPipeInfo
//sys getNamedPipeHandleState(pipe syscall.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) = GetNamedPipeHandleStateW
//sys localAlloc(uFlags uint32, length uint32) (ptr uintptr) = LocalAlloc
@@ -163,19 +164,21 @@ func (s pipeAddress) String() string {
}
// tryDialPipe attempts to dial the pipe at `path` until `ctx` cancellation or timeout.
func tryDialPipe(ctx context.Context, path *string, access uint32) (syscall.Handle, error) {
func tryDialPipe(ctx context.Context, path *string, access fs.AccessMask) (syscall.Handle, error) {
for {
select {
case <-ctx.Done():
return syscall.Handle(0), ctx.Err()
default:
h, err := createFile(*path,
wh, err := fs.CreateFile(*path,
access,
0,
nil,
syscall.OPEN_EXISTING,
windows.FILE_FLAG_OVERLAPPED|windows.SECURITY_SQOS_PRESENT|windows.SECURITY_ANONYMOUS,
0)
0, // mode
nil, // security attributes
fs.OPEN_EXISTING,
fs.FILE_FLAG_OVERLAPPED|fs.SECURITY_SQOS_PRESENT|fs.SECURITY_ANONYMOUS,
0, // template file handle
)
h := syscall.Handle(wh)
if err == nil {
return h, nil
}
@@ -219,7 +222,7 @@ func DialPipeContext(ctx context.Context, path string) (net.Conn, error) {
func DialPipeAccess(ctx context.Context, path string, access uint32) (net.Conn, error) {
var err error
var h syscall.Handle
h, err = tryDialPipe(ctx, &path, access)
h, err = tryDialPipe(ctx, &path, fs.AccessMask(access))
if err != nil {
return nil, err
}
@@ -279,6 +282,7 @@ func makeServerPipeHandle(path string, sd []byte, c *PipeConfig, first bool) (sy
}
defer localFree(ntPath.Buffer)
oa.ObjectName = &ntPath
oa.Attributes = windows.OBJ_CASE_INSENSITIVE
// The security descriptor is only needed for the first pipe.
if first {

View File

@@ -63,7 +63,6 @@ var (
procBackupWrite = modkernel32.NewProc("BackupWrite")
procCancelIoEx = modkernel32.NewProc("CancelIoEx")
procConnectNamedPipe = modkernel32.NewProc("ConnectNamedPipe")
procCreateFileW = modkernel32.NewProc("CreateFileW")
procCreateIoCompletionPort = modkernel32.NewProc("CreateIoCompletionPort")
procCreateNamedPipeW = modkernel32.NewProc("CreateNamedPipeW")
procGetCurrentThread = modkernel32.NewProc("GetCurrentThread")
@@ -305,24 +304,6 @@ func connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) {
return
}
func createFile(name string, access uint32, mode uint32, sa *syscall.SecurityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) {
var _p0 *uint16
_p0, err = syscall.UTF16PtrFromString(name)
if err != nil {
return
}
return _createFile(_p0, access, mode, sa, createmode, attrs, templatefile)
}
func _createFile(name *uint16, access uint32, mode uint32, sa *syscall.SecurityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) {
r0, _, e1 := syscall.Syscall9(procCreateFileW.Addr(), 7, uintptr(unsafe.Pointer(name)), uintptr(access), uintptr(mode), uintptr(unsafe.Pointer(sa)), uintptr(createmode), uintptr(attrs), uintptr(templatefile), 0, 0)
handle = syscall.Handle(r0)
if handle == syscall.InvalidHandle {
err = errnoErr(e1)
}
return
}
func createIoCompletionPort(file syscall.Handle, port syscall.Handle, key uintptr, threadCount uint32) (newport syscall.Handle, err error) {
r0, _, e1 := syscall.Syscall6(procCreateIoCompletionPort.Addr(), 4, uintptr(file), uintptr(port), uintptr(key), uintptr(threadCount), 0, 0)
newport = syscall.Handle(r0)

View File

@@ -191,7 +191,7 @@ func (bitCurve *BitCurve) doubleJacobian(x, y, z *big.Int) (*big.Int, *big.Int,
return x3, y3, z3
}
//TODO: double check if it is okay
// TODO: double check if it is okay
// ScalarMult returns k*(Bx,By) where k is a number in big-endian form.
func (bitCurve *BitCurve) ScalarMult(Bx, By *big.Int, k []byte) (*big.Int, *big.Int) {
// We have a slight problem in that the identity of the group (the
@@ -239,7 +239,7 @@ func (bitCurve *BitCurve) ScalarBaseMult(k []byte) (*big.Int, *big.Int) {
var mask = []byte{0xff, 0x1, 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f}
//TODO: double check if it is okay
// TODO: double check if it is okay
// GenerateKey returns a public/private key pair. The private key is generated
// using the given reader, which must return random data.
func (bitCurve *BitCurve) GenerateKey(rand io.Reader) (priv []byte, x, y *big.Int, err error) {

View File

@@ -80,4 +80,4 @@ func (curve *rcurve) ScalarMult(x1, y1 *big.Int, scalar []byte) (x, y *big.Int)
func (curve *rcurve) ScalarBaseMult(scalar []byte) (x, y *big.Int) {
return curve.fromTwisted(curve.twisted.ScalarBaseMult(scalar))
}
}

View File

@@ -67,7 +67,7 @@ func (e *eax) Seal(dst, nonce, plaintext, adata []byte) []byte {
if len(nonce) > e.nonceSize {
panic("crypto/eax: Nonce too long for this instance")
}
ret, out := byteutil.SliceForAppend(dst, len(plaintext) + e.tagSize)
ret, out := byteutil.SliceForAppend(dst, len(plaintext)+e.tagSize)
omacNonce := e.omacT(0, nonce)
omacAdata := e.omacT(1, adata)
@@ -85,7 +85,7 @@ func (e *eax) Seal(dst, nonce, plaintext, adata []byte) []byte {
return ret
}
func (e* eax) Open(dst, nonce, ciphertext, adata []byte) ([]byte, error) {
func (e *eax) Open(dst, nonce, ciphertext, adata []byte) ([]byte, error) {
if len(nonce) > e.nonceSize {
panic("crypto/eax: Nonce too long for this instance")
}

View File

@@ -41,7 +41,7 @@ func ShiftNBytesLeft(dst, x []byte, n int) {
bits := uint(n % 8)
l := len(dst)
for i := 0; i < l-1; i++ {
dst[i] = (dst[i] << bits) | (dst[i+1] >> uint(8 - bits))
dst[i] = (dst[i] << bits) | (dst[i+1] >> uint(8-bits))
}
dst[l-1] = dst[l-1] << bits
@@ -56,7 +56,6 @@ func XorBytesMut(X, Y []byte) {
}
}
// XorBytes assumes equal input length, puts X XOR Y into Z
func XorBytes(Z, X, Y []byte) {
for i := 0; i < len(X); i++ {
@@ -67,10 +66,10 @@ func XorBytes(Z, X, Y []byte) {
// RightXor XORs smaller input (assumed Y) at the right of the larger input (assumed X)
func RightXor(X, Y []byte) []byte {
offset := len(X) - len(Y)
xored := make([]byte, len(X));
xored := make([]byte, len(X))
copy(xored, X)
for i := 0; i < len(Y); i++ {
xored[offset + i] ^= Y[i]
xored[offset+i] ^= Y[i]
}
return xored
}
@@ -89,4 +88,3 @@ func SliceForAppend(in []byte, n int) (head, tail []byte) {
tail = head[len(in):]
return
}

View File

@@ -93,13 +93,13 @@ func NewOCBWithNonceAndTagSize(
return nil, ocbError("Custom tag length exceeds blocksize")
}
return &ocb{
block: block,
tagSize: tagSize,
nonceSize: nonceSize,
mask: initializeMaskTable(block),
block: block,
tagSize: tagSize,
nonceSize: nonceSize,
mask: initializeMaskTable(block),
reusableKtop: reusableKtop{
noncePrefix: nil,
Ktop: nil,
Ktop: nil,
},
}, nil
}

View File

@@ -4,21 +4,22 @@ package ocb
var rfc7253TestVectorTaglen96 = struct {
key, nonce, header, plaintext, ciphertext string
}{"0F0E0D0C0B0A09080706050403020100",
"BBAA9988776655443322110D",
"000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627",
"000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627",
"1792A4E31E0755FB03E31B22116E6C2DDF9EFD6E33D536F1A0124B0A55BAE884ED93481529C76B6AD0C515F4D1CDD4FDAC4F02AA"}
"BBAA9988776655443322110D",
"000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627",
"000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627",
"1792A4E31E0755FB03E31B22116E6C2DDF9EFD6E33D536F1A0124B0A55BAE884ED93481529C76B6AD0C515F4D1CDD4FDAC4F02AA"}
var rfc7253AlgorithmTest = []struct {
KEYLEN, TAGLEN int
OUTPUT string }{
{128, 128, "67E944D23256C5E0B6C61FA22FDF1EA2"},
{192, 128, "F673F2C3E7174AAE7BAE986CA9F29E17"},
{256, 128, "D90EB8E9C977C88B79DD793D7FFA161C"},
{128, 96, "77A3D8E73589158D25D01209"},
{192, 96, "05D56EAD2752C86BE6932C5E"},
{256, 96, "5458359AC23B0CBA9E6330DD"},
{128, 64, "192C9B7BD90BA06A"},
{192, 64, "0066BC6E0EF34E24"},
{256, 64, "7D4EA5D445501CBE"},
}
OUTPUT string
}{
{128, 128, "67E944D23256C5E0B6C61FA22FDF1EA2"},
{192, 128, "F673F2C3E7174AAE7BAE986CA9F29E17"},
{256, 128, "D90EB8E9C977C88B79DD793D7FFA161C"},
{128, 96, "77A3D8E73589158D25D01209"},
{192, 96, "05D56EAD2752C86BE6932C5E"},
{256, 96, "5458359AC23B0CBA9E6330DD"},
{128, 64, "192C9B7BD90BA06A"},
{192, 64, "0066BC6E0EF34E24"},
{256, 64, "7D4EA5D445501CBE"},
}

View File

@@ -17,12 +17,14 @@ import (
// A Block represents an OpenPGP armored structure.
//
// The encoded form is:
// -----BEGIN Type-----
// Headers
//
// base64-encoded Bytes
// '=' base64 encoded checksum
// -----END Type-----
// -----BEGIN Type-----
// Headers
//
// base64-encoded Bytes
// '=' base64 encoded checksum
// -----END Type-----
//
// where Headers is a possibly empty sequence of Key: Value lines.
//
// Since the armored data can be very large, this package presents a streaming

View File

@@ -96,7 +96,8 @@ func (l *lineBreaker) Close() (err error) {
// trailer.
//
// It's built into a stack of io.Writers:
// encoding -> base64 encoder -> lineBreaker -> out
//
// encoding -> base64 encoder -> lineBreaker -> out
type encoding struct {
out io.Writer
breaker *lineBreaker

View File

@@ -34,7 +34,7 @@ type PrivateKey struct {
func NewPublicKey(curve ecc.ECDHCurve, kdfHash algorithm.Hash, kdfCipher algorithm.Cipher) *PublicKey {
return &PublicKey{
curve: curve,
curve: curve,
KDF: KDF{
Hash: kdfHash,
Cipher: kdfCipher,
@@ -167,7 +167,7 @@ func buildKey(pub *PublicKey, zb []byte, curveOID, fingerprint []byte, stripLead
if _, err := param.Write(fingerprint[:20]); err != nil {
return nil, err
}
if param.Len() - len(curveOID) != 45 {
if param.Len()-len(curveOID) != 45 {
return nil, errors.New("ecdh: malformed KDF Param")
}
@@ -181,15 +181,19 @@ func buildKey(pub *PublicKey, zb []byte, curveOID, fingerprint []byte, stripLead
j := zbLen - 1
if stripLeading {
// Work around old go crypto bug where the leading zeros are missing.
for ; i < zbLen && zb[i] == 0; i++ {}
for i < zbLen && zb[i] == 0 {
i++
}
}
if stripTrailing {
// Work around old OpenPGP.js bug where insignificant trailing zeros in
// this little-endian number are missing.
// (See https://github.com/openpgpjs/openpgpjs/pull/853.)
for ; j >= 0 && zb[j] == 0; j-- {}
for j >= 0 && zb[j] == 0 {
j--
}
}
if _, err := h.Write(zb[i:j+1]); err != nil {
if _, err := h.Write(zb[i : j+1]); err != nil {
return nil, err
}
if _, err := h.Write(param.Bytes()); err != nil {

View File

@@ -10,7 +10,7 @@ import (
)
type PublicKey struct {
X, Y *big.Int
X, Y *big.Int
curve ecc.ECDSACurve
}

View File

@@ -9,7 +9,7 @@ import (
)
type PublicKey struct {
X []byte
X []byte
curve ecc.EdDSACurve
}

View File

@@ -71,8 +71,8 @@ func Encrypt(random io.Reader, pub *PublicKey, msg []byte) (c1, c2 *big.Int, err
// returns the plaintext of the message. An error can result only if the
// ciphertext is invalid. Users should keep in mind that this is a padding
// oracle and thus, if exposed to an adaptive chosen ciphertext attack, can
// be used to break the cryptosystem. See ``Chosen Ciphertext Attacks
// Against Protocols Based on the RSA Encryption Standard PKCS #1'', Daniel
// be used to break the cryptosystem. See Chosen Ciphertext Attacks
// Against Protocols Based on the RSA Encryption Standard PKCS #1, Daniel
// Bleichenbacher, Advances in Cryptology (Crypto '98),
func Decrypt(priv *PrivateKey, c1, c2 *big.Int) (msg []byte, err error) {
s := new(big.Int).Exp(c1, priv.X, priv.P)

24
vendor/github.com/ProtonMail/go-crypto/openpgp/hash.go generated vendored Normal file
View File

@@ -0,0 +1,24 @@
package openpgp
import (
"crypto"
"github.com/ProtonMail/go-crypto/openpgp/internal/algorithm"
)
// HashIdToHash returns a crypto.Hash which corresponds to the given OpenPGP
// hash id.
func HashIdToHash(id byte) (h crypto.Hash, ok bool) {
return algorithm.HashIdToHash(id)
}
// HashIdToString returns the name of the hash function corresponding to the
// given OpenPGP hash id.
func HashIdToString(id byte) (name string, ok bool) {
return algorithm.HashIdToString(id)
}
// HashToHashId returns an OpenPGP hash id which corresponds the given Hash.
func HashToHashId(h crypto.Hash) (id byte, ok bool) {
return algorithm.HashToHashId(h)
}

View File

@@ -32,25 +32,25 @@ type Hash interface {
// The following vars mirror the crypto/Hash supported hash functions.
var (
SHA1 Hash = cryptoHash{2, crypto.SHA1}
SHA256 Hash = cryptoHash{8, crypto.SHA256}
SHA384 Hash = cryptoHash{9, crypto.SHA384}
SHA512 Hash = cryptoHash{10, crypto.SHA512}
SHA224 Hash = cryptoHash{11, crypto.SHA224}
SHA3_256 Hash = cryptoHash{12, crypto.SHA3_256}
SHA3_512 Hash = cryptoHash{14, crypto.SHA3_512}
SHA1 Hash = cryptoHash{2, crypto.SHA1}
SHA256 Hash = cryptoHash{8, crypto.SHA256}
SHA384 Hash = cryptoHash{9, crypto.SHA384}
SHA512 Hash = cryptoHash{10, crypto.SHA512}
SHA224 Hash = cryptoHash{11, crypto.SHA224}
SHA3_256 Hash = cryptoHash{12, crypto.SHA3_256}
SHA3_512 Hash = cryptoHash{14, crypto.SHA3_512}
)
// HashById represents the different hash functions specified for OpenPGP. See
// http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-14
var (
HashById = map[uint8]Hash{
SHA256.Id(): SHA256,
SHA384.Id(): SHA384,
SHA512.Id(): SHA512,
SHA224.Id(): SHA224,
SHA3_256.Id(): SHA3_256,
SHA3_512.Id(): SHA3_512,
SHA256.Id(): SHA256,
SHA384.Id(): SHA384,
SHA512.Id(): SHA512,
SHA224.Id(): SHA224,
SHA3_256.Id(): SHA3_256,
SHA3_512.Id(): SHA3_512,
}
)
@@ -67,12 +67,12 @@ func (h cryptoHash) Id() uint8 {
}
var hashNames = map[uint8]string{
SHA256.Id(): "SHA256",
SHA384.Id(): "SHA384",
SHA512.Id(): "SHA512",
SHA224.Id(): "SHA224",
SHA3_256.Id(): "SHA3-256",
SHA3_512.Id(): "SHA3-512",
SHA256.Id(): "SHA256",
SHA384.Id(): "SHA384",
SHA512.Id(): "SHA512",
SHA224.Id(): "SHA224",
SHA3_256.Id(): "SHA3-256",
SHA3_512.Id(): "SHA3-512",
}
func (h cryptoHash) String() string {

View File

@@ -9,7 +9,7 @@ import (
x25519lib "github.com/cloudflare/circl/dh/x25519"
)
type curve25519 struct {}
type curve25519 struct{}
func NewCurve25519() *curve25519 {
return &curve25519{}
@@ -21,14 +21,14 @@ func (c *curve25519) GetCurveName() string {
// MarshalBytePoint encodes the public point from native format, adding the prefix.
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.6
func (c *curve25519) MarshalBytePoint(point [] byte) []byte {
func (c *curve25519) MarshalBytePoint(point []byte) []byte {
return append([]byte{0x40}, point...)
}
// UnmarshalBytePoint decodes the public point to native format, removing the prefix.
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.6
func (c *curve25519) UnmarshalBytePoint(point []byte) []byte {
if len(point) != x25519lib.Size + 1 {
if len(point) != x25519lib.Size+1 {
return nil
}

View File

@@ -11,76 +11,76 @@ import (
type CurveInfo struct {
GenName string
Oid *encoding.OID
Curve Curve
Oid *encoding.OID
Curve Curve
}
var Curves = []CurveInfo{
{
// NIST P-256
GenName: "P256",
Oid: encoding.NewOID([]byte{0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07}),
Curve: NewGenericCurve(elliptic.P256()),
Oid: encoding.NewOID([]byte{0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07}),
Curve: NewGenericCurve(elliptic.P256()),
},
{
// NIST P-384
GenName: "P384",
Oid: encoding.NewOID([]byte{0x2B, 0x81, 0x04, 0x00, 0x22}),
Curve: NewGenericCurve(elliptic.P384()),
Oid: encoding.NewOID([]byte{0x2B, 0x81, 0x04, 0x00, 0x22}),
Curve: NewGenericCurve(elliptic.P384()),
},
{
// NIST P-521
GenName: "P521",
Oid: encoding.NewOID([]byte{0x2B, 0x81, 0x04, 0x00, 0x23}),
Curve: NewGenericCurve(elliptic.P521()),
Oid: encoding.NewOID([]byte{0x2B, 0x81, 0x04, 0x00, 0x23}),
Curve: NewGenericCurve(elliptic.P521()),
},
{
// SecP256k1
GenName: "SecP256k1",
Oid: encoding.NewOID([]byte{0x2B, 0x81, 0x04, 0x00, 0x0A}),
Curve: NewGenericCurve(bitcurves.S256()),
Oid: encoding.NewOID([]byte{0x2B, 0x81, 0x04, 0x00, 0x0A}),
Curve: NewGenericCurve(bitcurves.S256()),
},
{
// Curve25519
GenName: "Curve25519",
Oid: encoding.NewOID([]byte{0x2B, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01}),
Curve: NewCurve25519(),
Oid: encoding.NewOID([]byte{0x2B, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01}),
Curve: NewCurve25519(),
},
{
// X448
GenName: "Curve448",
Oid: encoding.NewOID([]byte{0x2B, 0x65, 0x6F}),
Curve: NewX448(),
Oid: encoding.NewOID([]byte{0x2B, 0x65, 0x6F}),
Curve: NewX448(),
},
{
// Ed25519
GenName: "Curve25519",
Oid: encoding.NewOID([]byte{0x2B, 0x06, 0x01, 0x04, 0x01, 0xDA, 0x47, 0x0F, 0x01}),
Curve: NewEd25519(),
Oid: encoding.NewOID([]byte{0x2B, 0x06, 0x01, 0x04, 0x01, 0xDA, 0x47, 0x0F, 0x01}),
Curve: NewEd25519(),
},
{
// Ed448
GenName: "Curve448",
Oid: encoding.NewOID([]byte{0x2B, 0x65, 0x71}),
Curve: NewEd448(),
Oid: encoding.NewOID([]byte{0x2B, 0x65, 0x71}),
Curve: NewEd448(),
},
{
// BrainpoolP256r1
GenName: "BrainpoolP256",
Oid: encoding.NewOID([]byte{0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x07}),
Curve: NewGenericCurve(brainpool.P256r1()),
Oid: encoding.NewOID([]byte{0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x07}),
Curve: NewGenericCurve(brainpool.P256r1()),
},
{
// BrainpoolP384r1
GenName: "BrainpoolP384",
Oid: encoding.NewOID([]byte{0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0B}),
Curve: NewGenericCurve(brainpool.P384r1()),
Oid: encoding.NewOID([]byte{0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0B}),
Curve: NewGenericCurve(brainpool.P384r1()),
},
{
// BrainpoolP512r1
GenName: "BrainpoolP512",
Oid: encoding.NewOID([]byte{0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0D}),
Curve: NewGenericCurve(brainpool.P512r1()),
Oid: encoding.NewOID([]byte{0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0D}),
Curve: NewGenericCurve(brainpool.P512r1()),
},
}

View File

@@ -38,7 +38,7 @@ type EdDSACurve interface {
type ECDHCurve interface {
Curve
MarshalBytePoint([]byte) (encoded []byte)
UnmarshalBytePoint(encoded []byte) ([]byte)
UnmarshalBytePoint(encoded []byte) []byte
MarshalByteSecret(d []byte) []byte
UnmarshalByteSecret(d []byte) []byte
GenerateECDH(rand io.Reader) (point []byte, secret []byte, err error)

View File

@@ -10,7 +10,8 @@ import (
)
const ed25519Size = 32
type ed25519 struct {}
type ed25519 struct{}
func NewEd25519() *ed25519 {
return &ed25519{}
@@ -29,7 +30,7 @@ func (c *ed25519) MarshalBytePoint(x []byte) []byte {
// UnmarshalBytePoint decodes a point from prefixed format to native.
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.5
func (c *ed25519) UnmarshalBytePoint(point []byte) (x []byte) {
if len(point) != ed25519lib.PublicKeySize + 1 {
if len(point) != ed25519lib.PublicKeySize+1 {
return nil
}
@@ -52,7 +53,7 @@ func (c *ed25519) UnmarshalByteSecret(s []byte) (d []byte) {
// Handle stripped leading zeroes
d = make([]byte, ed25519lib.SeedSize)
copy(d[ed25519lib.SeedSize - len(s):], s)
copy(d[ed25519lib.SeedSize-len(s):], s)
return
}

View File

@@ -9,7 +9,7 @@ import (
ed448lib "github.com/cloudflare/circl/sign/ed448"
)
type ed448 struct {}
type ed448 struct{}
func NewEd448() *ed448 {
return &ed448{}
@@ -29,7 +29,7 @@ func (c *ed448) MarshalBytePoint(x []byte) []byte {
// UnmarshalBytePoint decodes a point from prefixed format to native.
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.5
func (c *ed448) UnmarshalBytePoint(point []byte) (x []byte) {
if len(point) != ed448lib.PublicKeySize + 1 {
if len(point) != ed448lib.PublicKeySize+1 {
return nil
}
@@ -48,7 +48,7 @@ func (c *ed448) MarshalByteSecret(d []byte) []byte {
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.5
func (c *ed448) UnmarshalByteSecret(s []byte) (d []byte) {
// Check prefixed size
if len(s) != ed448lib.SeedSize + 1 {
if len(s) != ed448lib.SeedSize+1 {
return nil
}
@@ -66,7 +66,7 @@ func (c *ed448) MarshalSignature(sig []byte) (r, s []byte) {
// UnmarshalSignature decodes R and S in the native format. Only R is used, in prefixed native format.
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.2.3.3.2
func (c *ed448) UnmarshalSignature(r, s []byte) (sig []byte) {
if len(r) != ed448lib.SignatureSize + 1 {
if len(r) != ed448lib.SignatureSize+1 {
return nil
}

View File

@@ -9,7 +9,7 @@ import (
x448lib "github.com/cloudflare/circl/dh/x448"
)
type x448 struct {}
type x448 struct{}
func NewX448() *x448 {
return &x448{}
@@ -28,7 +28,7 @@ func (c *x448) MarshalBytePoint(point []byte) []byte {
// UnmarshalBytePoint decodes a point from prefixed format to native.
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.6
func (c *x448) UnmarshalBytePoint(point []byte) []byte {
if len(point) != x448lib.Size + 1 {
if len(point) != x448lib.Size+1 {
return nil
}
@@ -44,7 +44,7 @@ func (c *x448) MarshalByteSecret(d []byte) []byte {
// UnmarshalByteSecret decodes a scalar from prefixed format to native.
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.6.1.2
func (c *x448) UnmarshalByteSecret(d []byte) []byte {
if len(d) != x448lib.Size + 1 {
if len(d) != x448lib.Size+1 {
return nil
}

View File

@@ -150,11 +150,9 @@ func (e *Entity) EncryptionKey(now time.Time) (Key, bool) {
return Key{e, subkey.PublicKey, subkey.PrivateKey, subkey.Sig, subkey.Revocations}, true
}
// If we don't have any candidate subkeys for encryption and
// the primary key doesn't have any usage metadata then we
// assume that the primary key is ok. Or, if the primary key is
// marked as ok to encrypt with, then we can obviously use it.
if !i.SelfSignature.FlagsValid || i.SelfSignature.FlagEncryptCommunications &&
// If we don't have any subkeys for encryption and the primary key
// is marked as OK to encrypt with, then we can use it.
if i.SelfSignature.FlagsValid && i.SelfSignature.FlagEncryptCommunications &&
e.PrimaryKey.PubKeyAlgo.CanEncrypt() {
return Key{e, e.PrimaryKey, e.PrivateKey, i.SelfSignature, e.Revocations}, true
}
@@ -162,7 +160,6 @@ func (e *Entity) EncryptionKey(now time.Time) (Key, bool) {
return Key{}, false
}
// CertificationKey return the best candidate Key for certifying a key with this
// Entity.
func (e *Entity) CertificationKey(now time.Time) (Key, bool) {
@@ -203,8 +200,8 @@ func (e *Entity) signingKeyByIdUsage(now time.Time, id uint64, flags int) (Key,
var maxTime time.Time
for idx, subkey := range e.Subkeys {
if subkey.Sig.FlagsValid &&
(flags & packet.KeyFlagCertify == 0 || subkey.Sig.FlagCertify) &&
(flags & packet.KeyFlagSign == 0 || subkey.Sig.FlagSign) &&
(flags&packet.KeyFlagCertify == 0 || subkey.Sig.FlagCertify) &&
(flags&packet.KeyFlagSign == 0 || subkey.Sig.FlagSign) &&
subkey.PublicKey.PubKeyAlgo.CanSign() &&
!subkey.PublicKey.KeyExpired(subkey.Sig, now) &&
!subkey.Sig.SigExpired(now) &&
@@ -221,12 +218,11 @@ func (e *Entity) signingKeyByIdUsage(now time.Time, id uint64, flags int) (Key,
return Key{e, subkey.PublicKey, subkey.PrivateKey, subkey.Sig, subkey.Revocations}, true
}
// If we have no candidate subkey then we assume that it's ok to sign
// with the primary key. Or, if the primary key is marked as ok to
// sign with, then we can use it.
if !i.SelfSignature.FlagsValid || (
(flags & packet.KeyFlagCertify == 0 || i.SelfSignature.FlagCertify) &&
(flags & packet.KeyFlagSign == 0 || i.SelfSignature.FlagSign)) &&
// If we don't have any subkeys for signing and the primary key
// is marked as OK to sign with, then we can use it.
if i.SelfSignature.FlagsValid &&
(flags&packet.KeyFlagCertify == 0 || i.SelfSignature.FlagCertify) &&
(flags&packet.KeyFlagSign == 0 || i.SelfSignature.FlagSign) &&
e.PrimaryKey.PubKeyAlgo.CanSign() &&
(id == 0 || e.PrimaryKey.KeyId == id) {
return Key{e, e.PrimaryKey, e.PrivateKey, i.SelfSignature, e.Revocations}, true
@@ -256,6 +252,44 @@ func (e *Entity) Revoked(now time.Time) bool {
return revoked(e.Revocations, now)
}
// EncryptPrivateKeys encrypts all non-encrypted keys in the entity with the same key
// derived from the provided passphrase. Public keys and dummy keys are ignored,
// and don't cause an error to be returned.
func (e *Entity) EncryptPrivateKeys(passphrase []byte, config *packet.Config) error {
var keysToEncrypt []*packet.PrivateKey
// Add entity private key to encrypt.
if e.PrivateKey != nil && !e.PrivateKey.Dummy() && !e.PrivateKey.Encrypted {
keysToEncrypt = append(keysToEncrypt, e.PrivateKey)
}
// Add subkeys to encrypt.
for _, sub := range e.Subkeys {
if sub.PrivateKey != nil && !sub.PrivateKey.Dummy() && !sub.PrivateKey.Encrypted {
keysToEncrypt = append(keysToEncrypt, sub.PrivateKey)
}
}
return packet.EncryptPrivateKeys(keysToEncrypt, passphrase, config)
}
// DecryptPrivateKeys decrypts all encrypted keys in the entitiy with the given passphrase.
// Avoids recomputation of similar s2k key derivations. Public keys and dummy keys are ignored,
// and don't cause an error to be returned.
func (e *Entity) DecryptPrivateKeys(passphrase []byte) error {
var keysToDecrypt []*packet.PrivateKey
// Add entity private key to decrypt.
if e.PrivateKey != nil && !e.PrivateKey.Dummy() && e.PrivateKey.Encrypted {
keysToDecrypt = append(keysToDecrypt, e.PrivateKey)
}
// Add subkeys to decrypt.
for _, sub := range e.Subkeys {
if sub.PrivateKey != nil && !sub.PrivateKey.Dummy() && sub.PrivateKey.Encrypted {
keysToDecrypt = append(keysToDecrypt, sub.PrivateKey)
}
}
return packet.DecryptPrivateKeys(keysToDecrypt, passphrase)
}
// Revoked returns whether the identity has been revoked by a self-signature.
// Note that third-party revocation signatures are not supported.
func (i *Identity) Revoked(now time.Time) bool {
@@ -303,7 +337,11 @@ func (el EntityList) KeysById(id uint64) (keys []Key) {
// the bitwise-OR of packet.KeyFlag* values.
func (el EntityList) KeysByIdUsage(id uint64, requiredUsage byte) (keys []Key) {
for _, key := range el.KeysById(id) {
if key.SelfSignature != nil && key.SelfSignature.FlagsValid && requiredUsage != 0 {
if requiredUsage != 0 {
if key.SelfSignature == nil || !key.SelfSignature.FlagsValid {
continue
}
var usage byte
if key.SelfSignature.FlagCertify {
usage |= packet.KeyFlagCertify
@@ -331,7 +369,7 @@ func (el EntityList) KeysByIdUsage(id uint64, requiredUsage byte) (keys []Key) {
func (el EntityList) DecryptionKeys() (keys []Key) {
for _, e := range el {
for _, subKey := range e.Subkeys {
if subKey.PrivateKey != nil && (!subKey.Sig.FlagsValid || subKey.Sig.FlagEncryptStorage || subKey.Sig.FlagEncryptCommunications) {
if subKey.PrivateKey != nil && subKey.Sig.FlagsValid && (subKey.Sig.FlagEncryptStorage || subKey.Sig.FlagEncryptCommunications) {
keys = append(keys, Key{e, subKey.PublicKey, subKey.PrivateKey, subKey.Sig, subKey.Revocations})
}
}

View File

@@ -18,7 +18,7 @@ type aeadCrypter struct {
initialNonce []byte
associatedData []byte // Chunk-independent associated data
chunkIndex []byte // Chunk counter
packetTag packetType
packetTag packetType // SEIP packet (v2) or AEAD Encrypted Data packet
bytesProcessed int // Amount of plaintext bytes encrypted/decrypted
buffer bytes.Buffer // Buffered bytes across chunks
}
@@ -83,7 +83,7 @@ func (ar *aeadDecrypter) Read(dst []byte) (n int, err error) {
// Read a chunk
tagLen := ar.aead.Overhead()
cipherChunkBuf := new(bytes.Buffer)
_, errRead := io.CopyN(cipherChunkBuf, ar.reader, int64(ar.chunkSize + tagLen))
_, errRead := io.CopyN(cipherChunkBuf, ar.reader, int64(ar.chunkSize+tagLen))
cipherChunk := cipherChunkBuf.Bytes()
if errRead != nil && errRead != io.EOF {
return 0, errRead
@@ -177,7 +177,6 @@ type aeadEncrypter struct {
writer io.WriteCloser // 'writer' is a partialLengthWriter
}
// Write encrypts and writes bytes. It encrypts when necessary and buffers extra
// plaintext bytes for next call. When the stream is finished, Close() MUST be
// called to append the final tag.

View File

@@ -10,6 +10,8 @@ import (
"io"
"math/big"
"time"
"github.com/ProtonMail/go-crypto/openpgp/s2k"
)
// Config collects a number of parameters along with sensible defaults.
@@ -33,16 +35,24 @@ type Config struct {
DefaultCompressionAlgo CompressionAlgo
// CompressionConfig configures the compression settings.
CompressionConfig *CompressionConfig
// S2KCount is only used for symmetric encryption. It
// determines the strength of the passphrase stretching when
// S2K (String to Key) config, used for key derivation in the context of secret key encryption
// and password-encrypted data.
// If nil, the default configuration is used
S2KConfig *s2k.Config
// Iteration count for Iterated S2K (String to Key).
// Only used if sk2.Mode is nil.
// This value is duplicated here from s2k.Config for backwards compatibility.
// It determines the strength of the passphrase stretching when
// the said passphrase is hashed to produce a key. S2KCount
// should be between 1024 and 65011712, inclusive. If Config
// is nil or S2KCount is 0, the value 65536 used. Not all
// should be between 65536 and 65011712, inclusive. If Config
// is nil or S2KCount is 0, the value 16777216 used. Not all
// values in the above range can be represented. S2KCount will
// be rounded up to the next representable value if it cannot
// be encoded exactly. When set, it is strongly encrouraged to
// use a value that is at least 65536. See RFC 4880 Section
// 3.7.1.3.
//
// Deprecated: SK2Count should be configured in S2KConfig instead.
S2KCount int
// RSABits is the number of bits in new RSA keys made with NewEntity.
// If zero, then 2048 bit keys are created.
@@ -153,13 +163,6 @@ func (c *Config) Compression() CompressionAlgo {
return c.DefaultCompressionAlgo
}
func (c *Config) PasswordHashIterations() int {
if c == nil || c.S2KCount == 0 {
return 0
}
return c.S2KCount
}
func (c *Config) RSAModulusBits() int {
if c == nil || c.RSABits == 0 {
return 2048
@@ -181,6 +184,27 @@ func (c *Config) CurveName() Curve {
return c.Curve
}
// Deprecated: The hash iterations should now be queried via the S2K() method.
func (c *Config) PasswordHashIterations() int {
if c == nil || c.S2KCount == 0 {
return 0
}
return c.S2KCount
}
func (c *Config) S2K() *s2k.Config {
if c == nil {
return nil
}
// for backwards compatibility
if c != nil && c.S2KCount > 0 && c.S2KConfig == nil {
return &s2k.Config {
S2KCount: c.S2KCount,
}
}
return c.S2KConfig
}
func (c *Config) AEAD() *AEADConfig {
if c == nil {
return nil

View File

@@ -55,7 +55,7 @@ func (ops *OnePassSignature) Serialize(w io.Writer) error {
buf[0] = onePassSignatureVersion
buf[1] = uint8(ops.SigType)
var ok bool
buf[2], ok = algorithm.HashToHashId(ops.Hash)
buf[2], ok = algorithm.HashToHashIdWithSha1(ops.Hash)
if !ok {
return errors.UnsupportedError("hash type: " + strconv.Itoa(int(ops.Hash)))
}

View File

@@ -384,18 +384,18 @@ func Read(r io.Reader) (p Packet, err error) {
type SignatureType uint8
const (
SigTypeBinary SignatureType = 0x00
SigTypeText = 0x01
SigTypeGenericCert = 0x10
SigTypePersonaCert = 0x11
SigTypeCasualCert = 0x12
SigTypePositiveCert = 0x13
SigTypeSubkeyBinding = 0x18
SigTypePrimaryKeyBinding = 0x19
SigTypeDirectSignature = 0x1F
SigTypeKeyRevocation = 0x20
SigTypeSubkeyRevocation = 0x28
SigTypeCertificationRevocation = 0x30
SigTypeBinary SignatureType = 0x00
SigTypeText = 0x01
SigTypeGenericCert = 0x10
SigTypePersonaCert = 0x11
SigTypeCasualCert = 0x12
SigTypePositiveCert = 0x13
SigTypeSubkeyBinding = 0x18
SigTypePrimaryKeyBinding = 0x19
SigTypeDirectSignature = 0x1F
SigTypeKeyRevocation = 0x20
SigTypeSubkeyRevocation = 0x28
SigTypeCertificationRevocation = 0x30
)
// PublicKeyAlgorithm represents the different public key system specified for
@@ -533,19 +533,19 @@ const (
type Curve string
const (
Curve25519 Curve = "Curve25519"
Curve448 Curve = "Curve448"
CurveNistP256 Curve = "P256"
CurveNistP384 Curve = "P384"
CurveNistP521 Curve = "P521"
CurveSecP256k1 Curve = "SecP256k1"
Curve25519 Curve = "Curve25519"
Curve448 Curve = "Curve448"
CurveNistP256 Curve = "P256"
CurveNistP384 Curve = "P384"
CurveNistP521 Curve = "P521"
CurveSecP256k1 Curve = "SecP256k1"
CurveBrainpoolP256 Curve = "BrainpoolP256"
CurveBrainpoolP384 Curve = "BrainpoolP384"
CurveBrainpoolP512 Curve = "BrainpoolP512"
)
// TrustLevel represents a trust level per RFC4880 5.2.3.13
type TrustLevel uint8
type TrustLevel uint8
// TrustAmount represents a trust amount per RFC4880 5.2.3.13
type TrustAmount uint8

View File

@@ -49,7 +49,7 @@ type PrivateKey struct {
s2kParams *s2k.Params
}
//S2KType s2k packet type
// S2KType s2k packet type
type S2KType uint8
const (
@@ -370,8 +370,8 @@ func serializeECDHPrivateKey(w io.Writer, priv *ecdh.PrivateKey) error {
return err
}
// Decrypt decrypts an encrypted private key using a passphrase.
func (pk *PrivateKey) Decrypt(passphrase []byte) error {
// decrypt decrypts an encrypted private key using a decryption key.
func (pk *PrivateKey) decrypt(decryptionKey []byte) error {
if pk.Dummy() {
return errors.ErrDummyPrivateKey("dummy key found")
}
@@ -379,9 +379,7 @@ func (pk *PrivateKey) Decrypt(passphrase []byte) error {
return nil
}
key := make([]byte, pk.cipher.KeySize())
pk.s2k(key, passphrase)
block := pk.cipher.new(key)
block := pk.cipher.new(decryptionKey)
cfb := cipher.NewCFBDecrypter(block, pk.iv)
data := make([]byte, len(pk.encryptedData))
@@ -430,35 +428,79 @@ func (pk *PrivateKey) Decrypt(passphrase []byte) error {
return nil
}
// Encrypt encrypts an unencrypted private key using a passphrase.
func (pk *PrivateKey) Encrypt(passphrase []byte) error {
func (pk *PrivateKey) decryptWithCache(passphrase []byte, keyCache *s2k.Cache) error {
if pk.Dummy() {
return errors.ErrDummyPrivateKey("dummy key found")
}
if !pk.Encrypted {
return nil
}
key, err := keyCache.GetOrComputeDerivedKey(passphrase, pk.s2kParams, pk.cipher.KeySize())
if err != nil {
return err
}
return pk.decrypt(key)
}
// Decrypt decrypts an encrypted private key using a passphrase.
func (pk *PrivateKey) Decrypt(passphrase []byte) error {
if pk.Dummy() {
return errors.ErrDummyPrivateKey("dummy key found")
}
if !pk.Encrypted {
return nil
}
key := make([]byte, pk.cipher.KeySize())
pk.s2k(key, passphrase)
return pk.decrypt(key)
}
// DecryptPrivateKeys decrypts all encrypted keys with the given config and passphrase.
// Avoids recomputation of similar s2k key derivations.
func DecryptPrivateKeys(keys []*PrivateKey, passphrase []byte) error {
// Create a cache to avoid recomputation of key derviations for the same passphrase.
s2kCache := &s2k.Cache{}
for _, key := range keys {
if key != nil && !key.Dummy() && key.Encrypted {
err := key.decryptWithCache(passphrase, s2kCache)
if err != nil {
return err
}
}
}
return nil
}
// encrypt encrypts an unencrypted private key.
func (pk *PrivateKey) encrypt(key []byte, params *s2k.Params, cipherFunction CipherFunction) error {
if pk.Dummy() {
return errors.ErrDummyPrivateKey("dummy key found")
}
if pk.Encrypted {
return nil
}
// check if encryptionKey has the correct size
if len(key) != cipherFunction.KeySize() {
return errors.InvalidArgumentError("supplied encryption key has the wrong size")
}
priv := bytes.NewBuffer(nil)
err := pk.serializePrivateKey(priv)
if err != nil {
return err
}
//Default config of private key encryption
pk.cipher = CipherAES256
s2kConfig := &s2k.Config{
S2KMode: 3, //Iterated
S2KCount: 65536,
Hash: crypto.SHA256,
}
pk.s2kParams, err = s2k.Generate(rand.Reader, s2kConfig)
if err != nil {
return err
}
privateKeyBytes := priv.Bytes()
key := make([]byte, pk.cipher.KeySize())
pk.sha1Checksum = true
pk.cipher = cipherFunction
pk.s2kParams = params
pk.s2k, err = pk.s2kParams.Function()
if err != nil {
return err
}
pk.s2k(key, passphrase)
}
privateKeyBytes := priv.Bytes()
pk.sha1Checksum = true
block := pk.cipher.new(key)
pk.iv = make([]byte, pk.cipher.blockSize())
_, err = rand.Read(pk.iv)
@@ -489,6 +531,62 @@ func (pk *PrivateKey) Encrypt(passphrase []byte) error {
return err
}
// encryptWithConfig encrypts an unencrypted private key using the passphrase and the config.
func (pk *PrivateKey) encryptWithConfig(passphrase []byte, config *Config) error {
params, err := s2k.Generate(config.Random(), config.S2K())
if err != nil {
return err
}
// Derive an encryption key with the configured s2k function.
key := make([]byte, config.Cipher().KeySize())
s2k, err := params.Function()
if err != nil {
return err
}
s2k(key, passphrase)
// Encrypt the private key with the derived encryption key.
return pk.encrypt(key, params, config.Cipher())
}
// EncryptPrivateKeys encrypts all unencrypted keys with the given config and passphrase.
// Only derives one key from the passphrase, which is then used to encrypt each key.
func EncryptPrivateKeys(keys []*PrivateKey, passphrase []byte, config *Config) error {
params, err := s2k.Generate(config.Random(), config.S2K())
if err != nil {
return err
}
// Derive an encryption key with the configured s2k function.
encryptionKey := make([]byte, config.Cipher().KeySize())
s2k, err := params.Function()
if err != nil {
return err
}
s2k(encryptionKey, passphrase)
for _, key := range keys {
if key != nil && !key.Dummy() && !key.Encrypted {
err = key.encrypt(encryptionKey, params, config.Cipher())
if err != nil {
return err
}
}
}
return nil
}
// Encrypt encrypts an unencrypted private key using a passphrase.
func (pk *PrivateKey) Encrypt(passphrase []byte) error {
// Default config of private key encryption
config := &Config{
S2KConfig: &s2k.Config{
S2KMode: s2k.IteratedSaltedS2K,
S2KCount: 65536,
Hash: crypto.SHA256,
} ,
DefaultCipher: CipherAES256,
}
return pk.encryptWithConfig(passphrase, config)
}
func (pk *PrivateKey) serializePrivateKey(w io.Writer) (err error) {
switch priv := pk.PrivateKey.(type) {
case *rsa.PrivateKey:

View File

@@ -73,15 +73,15 @@ type Signature struct {
IsPrimaryId *bool
Notations []*Notation
// TrustLevel and TrustAmount can be set by the signer to assert that
// the key is not only valid but also trustworthy at the specified
// level.
// See RFC 4880, section 5.2.3.13 for details.
TrustLevel TrustLevel
// TrustLevel and TrustAmount can be set by the signer to assert that
// the key is not only valid but also trustworthy at the specified
// level.
// See RFC 4880, section 5.2.3.13 for details.
TrustLevel TrustLevel
TrustAmount TrustAmount
// TrustRegularExpression can be used in conjunction with trust Signature
// packets to limit the scope of the trust that is extended.
// packets to limit the scope of the trust that is extended.
// See RFC 4880, section 5.2.3.14 for details.
TrustRegularExpression *string
@@ -271,6 +271,10 @@ func parseSignatureSubpacket(sig *Signature, subpacket []byte, isHashed bool) (r
packetType signatureSubpacketType
isCritical bool
)
if len(subpacket) == 0 {
err = errors.StructuralError("zero length signature subpacket")
return
}
switch {
case subpacket[0] < 192:
length = uint32(subpacket[0])
@@ -327,10 +331,18 @@ func parseSignatureSubpacket(sig *Signature, subpacket []byte, isHashed bool) (r
sig.SigLifetimeSecs = new(uint32)
*sig.SigLifetimeSecs = binary.BigEndian.Uint32(subpacket)
case trustSubpacket:
if len(subpacket) != 2 {
err = errors.StructuralError("trust subpacket with bad length")
return
}
// Trust level and amount, section 5.2.3.13
sig.TrustLevel = TrustLevel(subpacket[0])
sig.TrustAmount = TrustAmount(subpacket[1])
case regularExpressionSubpacket:
if len(subpacket) == 0 {
err = errors.StructuralError("regexp subpacket with bad length")
return
}
// Trust regular expression, section 5.2.3.14
// RFC specifies the string should be null-terminated; remove a null byte from the end
if subpacket[len(subpacket)-1] != 0x00 {
@@ -372,16 +384,16 @@ func parseSignatureSubpacket(sig *Signature, subpacket []byte, isHashed bool) (r
nameLength := uint32(subpacket[4])<<8 | uint32(subpacket[5])
valueLength := uint32(subpacket[6])<<8 | uint32(subpacket[7])
if len(subpacket) != int(nameLength) + int(valueLength) + 8 {
if len(subpacket) != int(nameLength)+int(valueLength)+8 {
err = errors.StructuralError("notation data subpacket with bad length")
return
}
notation := Notation{
IsHumanReadable: (subpacket[0] & 0x80) == 0x80,
Name: string(subpacket[8: (nameLength + 8)]),
Value: subpacket[(nameLength + 8) : (valueLength + nameLength + 8)],
IsCritical: isCritical,
Name: string(subpacket[8:(nameLength + 8)]),
Value: subpacket[(nameLength + 8):(valueLength + nameLength + 8)],
IsCritical: isCritical,
}
sig.Notations = append(sig.Notations, &notation)
@@ -478,6 +490,10 @@ func parseSignatureSubpacket(sig *Signature, subpacket []byte, isHashed bool) (r
// Policy URI, section 5.2.3.20
sig.PolicyURI = string(subpacket)
case issuerFingerprintSubpacket:
if len(subpacket) == 0 {
err = errors.StructuralError("empty issuer fingerprint subpacket")
return
}
v, l := subpacket[0], len(subpacket[1:])
if v == 5 && l != 32 || v != 5 && l != 20 {
return nil, errors.StructuralError("bad fingerprint length")
@@ -493,14 +509,14 @@ func parseSignatureSubpacket(sig *Signature, subpacket []byte, isHashed bool) (r
case prefCipherSuitesSubpacket:
// Preferred AEAD cipher suites
// See https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-07.html#name-preferred-aead-ciphersuites
if len(subpacket) % 2 != 0 {
if len(subpacket)%2 != 0 {
err = errors.StructuralError("invalid aead cipher suite length")
return
}
sig.PreferredCipherSuites = make([][2]byte, len(subpacket) / 2)
sig.PreferredCipherSuites = make([][2]byte, len(subpacket)/2)
for i := 0; i < len(subpacket) / 2; i++ {
for i := 0; i < len(subpacket)/2; i++ {
sig.PreferredCipherSuites[i] = [2]uint8{subpacket[2*i], subpacket[2*i+1]}
}
default:
@@ -1039,7 +1055,7 @@ func (sig *Signature) AddMetadataToHashSuffix() {
n := sig.HashSuffix[len(sig.HashSuffix)-8:]
l := uint64(
uint64(n[0])<<56 | uint64(n[1])<<48 | uint64(n[2])<<40 | uint64(n[3])<<32 |
uint64(n[4])<<24 | uint64(n[5])<<16 | uint64(n[6])<<8 | uint64(n[7]))
uint64(n[4])<<24 | uint64(n[5])<<16 | uint64(n[6])<<8 | uint64(n[7]))
suffix := bytes.NewBuffer(nil)
suffix.Write(sig.HashSuffix[:l])

View File

@@ -198,7 +198,7 @@ func SerializeSymmetricKeyEncryptedReuseKey(w io.Writer, sessionKey []byte, pass
}
cipherFunc := config.Cipher()
// cipherFunc must be AES
if !cipherFunc.IsSupported() || cipherFunc < CipherAES128 || cipherFunc > CipherAES256 {
if !cipherFunc.IsSupported() || cipherFunc < CipherAES128 || cipherFunc > CipherAES256 {
return errors.UnsupportedError("unsupported cipher: " + strconv.Itoa(int(cipherFunc)))
}
@@ -207,7 +207,7 @@ func SerializeSymmetricKeyEncryptedReuseKey(w io.Writer, sessionKey []byte, pass
keyEncryptingKey := make([]byte, keySize)
// s2k.Serialize salts and stretches the passphrase, and writes the
// resulting key to keyEncryptingKey and the s2k descriptor to s2kBuf.
err = s2k.Serialize(s2kBuf, keyEncryptingKey, config.Random(), passphrase, &s2k.Config{Hash: config.Hash(), S2KCount: config.PasswordHashIterations()})
err = s2k.Serialize(s2kBuf, keyEncryptingKey, config.Random(), passphrase, config.S2K())
if err != nil {
return
}
@@ -232,7 +232,7 @@ func SerializeSymmetricKeyEncryptedReuseKey(w io.Writer, sessionKey []byte, pass
if version == 5 {
// Scalar octet count
buf = append(buf, byte(3 + len(s2kBytes) + config.AEAD().Mode().IvLength()))
buf = append(buf, byte(3+len(s2kBytes)+config.AEAD().Mode().IvLength()))
}
// Cipher function

View File

@@ -21,21 +21,20 @@ type SymmetricallyEncrypted struct {
IntegrityProtected bool // If true it is type 18 (with MDC or AEAD). False is packet type 9
// Specific to version 1
prefix []byte
prefix []byte
// Specific to version 2
cipher CipherFunction
mode AEADMode
cipher CipherFunction
mode AEADMode
chunkSizeByte byte
salt [aeadSaltSize]byte
salt [aeadSaltSize]byte
}
const (
symmetricallyEncryptedVersionMdc = 1
symmetricallyEncryptedVersionMdc = 1
symmetricallyEncryptedVersionAead = 2
)
func (se *SymmetricallyEncrypted) parse(r io.Reader) error {
if se.IntegrityProtected {
// See RFC 4880, section 5.13.

View File

@@ -144,7 +144,7 @@ func getSymmetricallyEncryptedAeadInstance(c CipherFunction, mode AEADMode, inpu
_, _ = readFull(hkdfReader, encryptionKey)
// Last 64 bits of nonce are the counter
nonce = make([]byte, mode.IvLength() - 8)
nonce = make([]byte, mode.IvLength()-8)
_, _ = readFull(hkdfReader, nonce)

View File

@@ -221,7 +221,7 @@ func (c noOpCloser) Close() error {
func serializeSymmetricallyEncryptedMdc(ciphertext io.WriteCloser, c CipherFunction, key []byte, config *Config) (Contents io.WriteCloser, err error) {
// Disallow old cipher suites
if !c.IsSupported() || c < CipherAES128 {
if !c.IsSupported() || c < CipherAES128 {
return nil, errors.InvalidArgumentError("invalid mdc cipher function")
}

View File

@@ -534,22 +534,24 @@ func CheckArmoredDetachedSignature(keyring KeyRing, signed, signature io.Reader,
}
// checkSignatureDetails returns an error if:
// - The signature (or one of the binding signatures mentioned below)
// has a unknown critical notation data subpacket
// - The primary key of the signing entity is revoked
// The signature was signed by a subkey and:
// - The signature (or one of the binding signatures mentioned below)
// has a unknown critical notation data subpacket
// - The primary key of the signing entity is revoked
// - The primary identity is revoked
// - The signature is expired
// - The primary key of the signing entity is expired according to the
// primary identity binding signature
//
// ... or, if the signature was signed by a subkey and:
// - The signing subkey is revoked
// - The primary identity is revoked
// - The signature is expired
// - The primary key of the signing entity is expired according to the
// primary identity binding signature
// The signature was signed by a subkey and:
// - The signing subkey is expired according to the subkey binding signature
// - The signing subkey binding signature is expired
// - The signing subkey cross-signature is expired
//
// NOTE: The order of these checks is important, as the caller may choose to
// ignore ErrSignatureExpired or ErrKeyExpired errors, but should never
// ignore any other errors.
//
// TODO: Also return an error if:
// - The primary key is expired according to a direct-key signature
// - (For V5 keys only:) The direct-key signature (exists and) is expired
@@ -557,7 +559,7 @@ func checkSignatureDetails(key *Key, signature *packet.Signature, config *packet
now := config.Now()
primaryIdentity := key.Entity.PrimaryIdentity()
signedBySubKey := key.PublicKey != key.Entity.PrimaryKey
sigsToCheck := []*packet.Signature{ signature, primaryIdentity.SelfSignature }
sigsToCheck := []*packet.Signature{signature, primaryIdentity.SelfSignature}
if signedBySubKey {
sigsToCheck = append(sigsToCheck, key.SelfSignature, key.SelfSignature.EmbeddedSignature)
}

View File

@@ -3,7 +3,8 @@
// license that can be found in the LICENSE file.
// Package s2k implements the various OpenPGP string-to-key transforms as
// specified in RFC 4800 section 3.7.1.
// specified in RFC 4800 section 3.7.1, and Argon2 specified in
// draft-ietf-openpgp-crypto-refresh-08 section 3.7.1.4.
package s2k // import "github.com/ProtonMail/go-crypto/openpgp/s2k"
import (
@@ -14,70 +15,47 @@ import (
"github.com/ProtonMail/go-crypto/openpgp/errors"
"github.com/ProtonMail/go-crypto/openpgp/internal/algorithm"
"golang.org/x/crypto/argon2"
)
// Config collects configuration parameters for s2k key-stretching
// transformations. A nil *Config is valid and results in all default
// values. Currently, Config is used only by the Serialize function in
// this package.
type Config struct {
// S2KMode is the mode of s2k function.
// It can be 0 (simple), 1(salted), 3(iterated)
// 2(reserved) 100-110(private/experimental).
S2KMode uint8
// Hash is the default hash function to be used. If
// nil, SHA256 is used.
Hash crypto.Hash
// S2KCount is only used for symmetric encryption. It
// determines the strength of the passphrase stretching when
// the said passphrase is hashed to produce a key. S2KCount
// should be between 65536 and 65011712, inclusive. If Config
// is nil or S2KCount is 0, the value 16777216 used. Not all
// values in the above range can be represented. S2KCount will
// be rounded up to the next representable value if it cannot
// be encoded exactly. See RFC 4880 Section 3.7.1.3.
S2KCount int
}
type Mode uint8
// Defines the default S2KMode constants
//
// 0 (simple), 1(salted), 3(iterated), 4(argon2)
const (
SimpleS2K Mode = 0
SaltedS2K Mode = 1
IteratedSaltedS2K Mode = 3
Argon2S2K Mode = 4
GnuS2K Mode = 101
)
const Argon2SaltSize int = 16
// Params contains all the parameters of the s2k packet
type Params struct {
// mode is the mode of s2k function.
// It can be 0 (simple), 1(salted), 3(iterated)
// 2(reserved) 100-110(private/experimental).
mode uint8
mode Mode
// hashId is the ID of the hash function used in any of the modes
hashId byte
// salt is a byte array to use as a salt in hashing process
salt []byte
// salt is a byte array to use as a salt in hashing process or argon2
saltBytes [Argon2SaltSize]byte
// countByte is used to determine how many rounds of hashing are to
// be performed in s2k mode 3. See RFC 4880 Section 3.7.1.3.
countByte byte
}
func (c *Config) hash() crypto.Hash {
if c == nil || uint(c.Hash) == 0 {
return crypto.SHA256
}
return c.Hash
}
// EncodedCount get encoded count
func (c *Config) EncodedCount() uint8 {
if c == nil || c.S2KCount == 0 {
return 224 // The common case. Corresponding to 16777216
}
i := c.S2KCount
switch {
case i < 65536:
i = 65536
case i > 65011712:
i = 65011712
}
return encodeCount(i)
// passes is a parameter in Argon2 to determine the number of iterations
// See RFC the crypto refresh Section 3.7.1.4.
passes byte
// parallelism is a parameter in Argon2 to determine the degree of paralellism
// See RFC the crypto refresh Section 3.7.1.4.
parallelism byte
// memoryExp is a parameter in Argon2 to determine the memory usage
// i.e., 2 ** memoryExp kibibytes
// See RFC the crypto refresh Section 3.7.1.4.
memoryExp byte
}
// encodeCount converts an iterative "count" in the range 1024 to
@@ -106,6 +84,31 @@ func decodeCount(c uint8) int {
return (16 + int(c&15)) << (uint32(c>>4) + 6)
}
// encodeMemory converts the Argon2 "memory" in the range parallelism*8 to
// 2**31, inclusive, to an encoded memory. The return value is the
// octet that is actually stored in the GPG file. encodeMemory panics
// if is not in the above range
// See OpenPGP crypto refresh Section 3.7.1.4.
func encodeMemory(memory uint32, parallelism uint8) uint8 {
if memory < (8 * uint32(parallelism)) || memory > uint32(2147483648) {
panic("Memory argument memory is outside the required range")
}
for exp := 3; exp < 31; exp++ {
compare := decodeMemory(uint8(exp))
if compare >= memory {
return uint8(exp)
}
}
return 31
}
// decodeMemory computes the decoded memory in kibibytes as 2**memoryExponent
func decodeMemory(memoryExponent uint8) uint32 {
return uint32(1) << memoryExponent
}
// Simple writes to out the result of computing the Simple S2K function (RFC
// 4880, section 3.7.1.1) using the given hash and input passphrase.
func Simple(out []byte, h hash.Hash, in []byte) {
@@ -169,25 +172,45 @@ func Iterated(out []byte, h hash.Hash, in []byte, salt []byte, count int) {
}
}
// Argon2 writes to out the key derived from the password (in) with the Argon2
// function (the crypto refresh, section 3.7.1.4)
func Argon2(out []byte, in []byte, salt []byte, passes uint8, paralellism uint8, memoryExp uint8) {
key := argon2.IDKey(in, salt, uint32(passes), decodeMemory(memoryExp), paralellism, uint32(len(out)))
copy(out[:], key)
}
// Generate generates valid parameters from given configuration.
// It will enforce salted + hashed s2k method
// It will enforce the Iterated and Salted or Argon2 S2K method.
func Generate(rand io.Reader, c *Config) (*Params, error) {
hashId, ok := algorithm.HashToHashId(c.Hash)
if !ok {
return nil, errors.UnsupportedError("no such hash")
var params *Params
if c != nil && c.Mode() == Argon2S2K {
// handle Argon2 case
argonConfig := c.Argon2()
params = &Params{
mode: Argon2S2K,
passes: argonConfig.Passes(),
parallelism: argonConfig.Parallelism(),
memoryExp: argonConfig.EncodedMemory(),
}
} else {
// handle IteratedSaltedS2K case
hashId, ok := algorithm.HashToHashId(c.hash())
if !ok {
return nil, errors.UnsupportedError("no such hash")
}
// Enforce iterared + salted method if not Argon 2
if c != nil {
c.S2KMode = IteratedSaltedS2K
}
params = &Params{
mode: IteratedSaltedS2K,
hashId: hashId,
countByte: c.EncodedCount(),
}
}
params := &Params{
mode: 3, // Enforce iterared + salted method
hashId: hashId,
salt: make([]byte, 8),
countByte: c.EncodedCount(),
}
if _, err := io.ReadFull(rand, params.salt); err != nil {
if _, err := io.ReadFull(rand, params.salt()); err != nil {
return nil, err
}
return params, nil
}
@@ -207,45 +230,60 @@ func Parse(r io.Reader) (f func(out, in []byte), err error) {
// ParseIntoParams reads a binary specification for a string-to-key
// transformation from r and returns a struct describing the s2k parameters.
func ParseIntoParams(r io.Reader) (params *Params, err error) {
var buf [9]byte
var buf [Argon2SaltSize + 3]byte
_, err = io.ReadFull(r, buf[:2])
_, err = io.ReadFull(r, buf[:1])
if err != nil {
return
}
params = &Params{
mode: buf[0],
hashId: buf[1],
mode: Mode(buf[0]),
}
switch params.mode {
case 0:
return params, nil
case 1:
_, err = io.ReadFull(r, buf[:8])
case SimpleS2K:
_, err = io.ReadFull(r, buf[:1])
if err != nil {
return nil, err
}
params.salt = buf[:8]
params.hashId = buf[0]
return params, nil
case 3:
case SaltedS2K:
_, err = io.ReadFull(r, buf[:9])
if err != nil {
return nil, err
}
params.salt = buf[:8]
params.countByte = buf[8]
params.hashId = buf[0]
copy(params.salt(), buf[1:9])
return params, nil
case 101:
// This is a GNU extension. See
// https://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=blob;f=doc/DETAILS;h=fe55ae16ab4e26d8356dc574c9e8bc935e71aef1;hb=23191d7851eae2217ecdac6484349849a24fd94a#l1109
if _, err = io.ReadFull(r, buf[:4]); err != nil {
case IteratedSaltedS2K:
_, err = io.ReadFull(r, buf[:10])
if err != nil {
return nil, err
}
if buf[0] == 'G' && buf[1] == 'N' && buf[2] == 'U' && buf[3] == 1 {
params.hashId = buf[0]
copy(params.salt(), buf[1:9])
params.countByte = buf[9]
return params, nil
case Argon2S2K:
_, err = io.ReadFull(r, buf[:Argon2SaltSize+3])
if err != nil {
return nil, err
}
copy(params.salt(), buf[:Argon2SaltSize])
params.passes = buf[Argon2SaltSize]
params.parallelism = buf[Argon2SaltSize+1]
params.memoryExp = buf[Argon2SaltSize+2]
return params, nil
case GnuS2K:
// This is a GNU extension. See
// https://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=blob;f=doc/DETAILS;h=fe55ae16ab4e26d8356dc574c9e8bc935e71aef1;hb=23191d7851eae2217ecdac6484349849a24fd94a#l1109
if _, err = io.ReadFull(r, buf[:5]); err != nil {
return nil, err
}
params.hashId = buf[0]
if buf[1] == 'G' && buf[2] == 'N' && buf[3] == 'U' && buf[4] == 1 {
return params, nil
}
return nil, errors.UnsupportedError("GNU S2K extension")
@@ -255,39 +293,56 @@ func ParseIntoParams(r io.Reader) (params *Params, err error) {
}
func (params *Params) Dummy() bool {
return params != nil && params.mode == 101
return params != nil && params.mode == GnuS2K
}
func (params *Params) salt() []byte {
switch params.mode {
case SaltedS2K, IteratedSaltedS2K: return params.saltBytes[:8]
case Argon2S2K: return params.saltBytes[:Argon2SaltSize]
default: return nil
}
}
func (params *Params) Function() (f func(out, in []byte), err error) {
if params.Dummy() {
return nil, errors.ErrDummyPrivateKey("dummy key found")
}
hashObj, ok := algorithm.HashIdToHashWithSha1(params.hashId)
if !ok {
return nil, errors.UnsupportedError("hash for S2K function: " + strconv.Itoa(int(params.hashId)))
}
if !hashObj.Available() {
return nil, errors.UnsupportedError("hash not available: " + strconv.Itoa(int(hashObj)))
var hashObj crypto.Hash
if params.mode != Argon2S2K {
var ok bool
hashObj, ok = algorithm.HashIdToHashWithSha1(params.hashId)
if !ok {
return nil, errors.UnsupportedError("hash for S2K function: " + strconv.Itoa(int(params.hashId)))
}
if !hashObj.Available() {
return nil, errors.UnsupportedError("hash not available: " + strconv.Itoa(int(hashObj)))
}
}
switch params.mode {
case 0:
case SimpleS2K:
f := func(out, in []byte) {
Simple(out, hashObj.New(), in)
}
return f, nil
case 1:
case SaltedS2K:
f := func(out, in []byte) {
Salted(out, hashObj.New(), in, params.salt)
Salted(out, hashObj.New(), in, params.salt())
}
return f, nil
case 3:
case IteratedSaltedS2K:
f := func(out, in []byte) {
Iterated(out, hashObj.New(), in, params.salt, decodeCount(params.countByte))
Iterated(out, hashObj.New(), in, params.salt(), decodeCount(params.countByte))
}
return f, nil
case Argon2S2K:
f := func(out, in []byte) {
Argon2(out, in, params.salt(), params.passes, params.parallelism, params.memoryExp)
}
return f, nil
}
@@ -295,23 +350,28 @@ func (params *Params) Function() (f func(out, in []byte), err error) {
}
func (params *Params) Serialize(w io.Writer) (err error) {
if _, err = w.Write([]byte{params.mode}); err != nil {
if _, err = w.Write([]byte{uint8(params.mode)}); err != nil {
return
}
if _, err = w.Write([]byte{params.hashId}); err != nil {
return
if params.mode != Argon2S2K {
if _, err = w.Write([]byte{params.hashId}); err != nil {
return
}
}
if params.Dummy() {
_, err = w.Write(append([]byte("GNU"), 1))
return
}
if params.mode > 0 {
if _, err = w.Write(params.salt); err != nil {
if _, err = w.Write(params.salt()); err != nil {
return
}
if params.mode == 3 {
if params.mode == IteratedSaltedS2K {
_, err = w.Write([]byte{params.countByte})
}
if params.mode == Argon2S2K {
_, err = w.Write([]byte{params.passes, params.parallelism, params.memoryExp})
}
}
return
}

View File

@@ -0,0 +1,26 @@
package s2k
// Cache stores keys derived with s2k functions from one passphrase
// to avoid recomputation if multiple items are encrypted with
// the same parameters.
type Cache map[Params][]byte
// GetOrComputeDerivedKey tries to retrieve the key
// for the given s2k parameters from the cache.
// If there is no hit, it derives the key with the s2k function from the passphrase,
// updates the cache, and returns the key.
func (c *Cache) GetOrComputeDerivedKey(passphrase []byte, params *Params, expectedKeySize int) ([]byte, error) {
key, found := (*c)[*params]
if !found || len(key) != expectedKeySize {
var err error
derivedKey := make([]byte, expectedKeySize)
s2k, err := params.Function()
if err != nil {
return nil, err
}
s2k(derivedKey, passphrase)
(*c)[*params] = key
return derivedKey, nil
}
return key, nil
}

View File

@@ -0,0 +1,121 @@
package s2k
import "crypto"
// Config collects configuration parameters for s2k key-stretching
// transformations. A nil *Config is valid and results in all default
// values.
type Config struct {
// S2K (String to Key) mode, used for key derivation in the context of secret key encryption
// and password-encrypted data. Either s2k.Argon2S2K or s2k.IteratedSaltedS2K has to be selected
// weaker options are not allowed.
// Note: Argon2 is the strongest option but not all OpenPGP implementations are compatible with it
//(pending standardisation).
// 0 (simple), 1(salted), 3(iterated), 4(argon2)
// 2(reserved) 100-110(private/experimental).
S2KMode Mode
// Only relevant if S2KMode is not set to s2k.Argon2S2K.
// Hash is the default hash function to be used. If
// nil, SHA256 is used.
Hash crypto.Hash
// Argon2 parameters for S2K (String to Key).
// Only relevant if S2KMode is set to s2k.Argon2S2K.
// If nil, default parameters are used.
// For more details on the choice of parameters, see https://tools.ietf.org/html/rfc9106#section-4.
Argon2Config *Argon2Config
// Only relevant if S2KMode is set to s2k.IteratedSaltedS2K.
// Iteration count for Iterated S2K (String to Key). It
// determines the strength of the passphrase stretching when
// the said passphrase is hashed to produce a key. S2KCount
// should be between 65536 and 65011712, inclusive. If Config
// is nil or S2KCount is 0, the value 16777216 used. Not all
// values in the above range can be represented. S2KCount will
// be rounded up to the next representable value if it cannot
// be encoded exactly. When set, it is strongly encrouraged to
// use a value that is at least 65536. See RFC 4880 Section
// 3.7.1.3.
S2KCount int
}
// Argon2Config stores the Argon2 parameters
// A nil *Argon2Config is valid and results in all default
type Argon2Config struct {
NumberOfPasses uint8
DegreeOfParallelism uint8
// The memory parameter for Argon2 specifies desired memory usage in kibibytes.
// For example memory=64*1024 sets the memory cost to ~64 MB.
Memory uint32
}
func (c *Config) Mode() Mode {
if c == nil {
return IteratedSaltedS2K
}
return c.S2KMode
}
func (c *Config) hash() crypto.Hash {
if c == nil || uint(c.Hash) == 0 {
return crypto.SHA256
}
return c.Hash
}
func (c *Config) Argon2() *Argon2Config {
if c == nil || c.Argon2Config == nil {
return nil
}
return c.Argon2Config
}
// EncodedCount get encoded count
func (c *Config) EncodedCount() uint8 {
if c == nil || c.S2KCount == 0 {
return 224 // The common case. Corresponding to 16777216
}
i := c.S2KCount
switch {
case i < 65536:
i = 65536
case i > 65011712:
i = 65011712
}
return encodeCount(i)
}
func (c *Argon2Config) Passes() uint8 {
if c == nil || c.NumberOfPasses == 0 {
return 3
}
return c.NumberOfPasses
}
func (c *Argon2Config) Parallelism() uint8 {
if c == nil || c.DegreeOfParallelism == 0 {
return 4
}
return c.DegreeOfParallelism
}
func (c *Argon2Config) EncodedMemory() uint8 {
if c == nil || c.Memory == 0 {
return 16 // 64 MiB of RAM
}
memory := c.Memory
lowerBound := uint32(c.Parallelism())*8
upperBound := uint32(2147483648)
switch {
case memory < lowerBound:
memory = lowerBound
case memory > upperBound:
memory = upperBound
}
return encodeMemory(memory, c.Parallelism())
}

View File

@@ -123,7 +123,7 @@ func SymmetricallyEncrypt(ciphertext io.Writer, passphrase []byte, hints *FileHi
var w io.WriteCloser
cipherSuite := packet.CipherSuite{
Cipher: config.Cipher(),
Mode: config.AEAD().Mode(),
Mode: config.AEAD().Mode(),
}
w, err = packet.SerializeSymmetricallyEncrypted(ciphertext, config.Cipher(), config.AEAD() != nil, cipherSuite, key, config)
if err != nil {
@@ -409,7 +409,7 @@ func encrypt(keyWriter io.Writer, dataWriter io.Writer, to []*Entity, signed *En
cipher := packet.CipherFunction(candidateCiphers[0])
aeadCipherSuite := packet.CipherSuite{
Cipher: packet.CipherFunction(candidateCipherSuites[0][0]),
Mode: packet.AEADMode(candidateCipherSuites[0][1]),
Mode: packet.AEADMode(candidateCipherSuites[0][1]),
}
// If the cipher specified by config is a candidate, we'll use that.
@@ -436,8 +436,8 @@ func encrypt(keyWriter io.Writer, dataWriter io.Writer, to []*Entity, signed *En
var payload io.WriteCloser
payload, err = packet.SerializeSymmetricallyEncrypted(dataWriter, cipher, aeadSupported, aeadCipherSuite, symKey, config)
if err != nil {
return
}
return
}
payload, err = handleCompression(payload, candidateCompression, config)
if err != nil {

View File

@@ -3,8 +3,7 @@
[![Go Reference](https://pkg.go.dev/badge/github.com/cespare/xxhash/v2.svg)](https://pkg.go.dev/github.com/cespare/xxhash/v2)
[![Test](https://github.com/cespare/xxhash/actions/workflows/test.yml/badge.svg)](https://github.com/cespare/xxhash/actions/workflows/test.yml)
xxhash is a Go implementation of the 64-bit
[xxHash](http://cyan4973.github.io/xxHash/) algorithm, XXH64. This is a
xxhash is a Go implementation of the 64-bit [xxHash] algorithm, XXH64. This is a
high-quality hashing algorithm that is much faster than anything in the Go
standard library.
@@ -25,8 +24,11 @@ func (*Digest) WriteString(string) (int, error)
func (*Digest) Sum64() uint64
```
This implementation provides a fast pure-Go implementation and an even faster
assembly implementation for amd64.
The package is written with optimized pure Go and also contains even faster
assembly implementations for amd64 and arm64. If desired, the `purego` build tag
opts into using the Go code even on those architectures.
[xxHash]: http://cyan4973.github.io/xxHash/
## Compatibility
@@ -45,19 +47,20 @@ I recommend using the latest release of Go.
Here are some quick benchmarks comparing the pure-Go and assembly
implementations of Sum64.
| input size | purego | asm |
| --- | --- | --- |
| 5 B | 979.66 MB/s | 1291.17 MB/s |
| 100 B | 7475.26 MB/s | 7973.40 MB/s |
| 4 KB | 17573.46 MB/s | 17602.65 MB/s |
| 10 MB | 17131.46 MB/s | 17142.16 MB/s |
| input size | purego | asm |
| ---------- | --------- | --------- |
| 4 B | 1.3 GB/s | 1.2 GB/s |
| 16 B | 2.9 GB/s | 3.5 GB/s |
| 100 B | 6.9 GB/s | 8.1 GB/s |
| 4 KB | 11.7 GB/s | 16.7 GB/s |
| 10 MB | 12.0 GB/s | 17.3 GB/s |
These numbers were generated on Ubuntu 18.04 with an Intel i7-8700K CPU using
the following commands under Go 1.11.2:
These numbers were generated on Ubuntu 20.04 with an Intel Xeon Platinum 8252C
CPU using the following commands under Go 1.19.2:
```
$ go test -tags purego -benchtime 10s -bench '/xxhash,direct,bytes'
$ go test -benchtime 10s -bench '/xxhash,direct,bytes'
benchstat <(go test -tags purego -benchtime 500ms -count 15 -bench 'Sum64$')
benchstat <(go test -benchtime 500ms -count 15 -bench 'Sum64$')
```
## Projects using this package

10
vendor/github.com/cespare/xxhash/v2/testall.sh generated vendored Normal file
View File

@@ -0,0 +1,10 @@
#!/bin/bash
set -eu -o pipefail
# Small convenience script for running the tests with various combinations of
# arch/tags. This assumes we're running on amd64 and have qemu available.
go test ./...
go test -tags purego ./...
GOARCH=arm64 go test
GOARCH=arm64 go test -tags purego

View File

@@ -16,19 +16,11 @@ const (
prime5 uint64 = 2870177450012600261
)
// NOTE(caleb): I'm using both consts and vars of the primes. Using consts where
// possible in the Go code is worth a small (but measurable) performance boost
// by avoiding some MOVQs. Vars are needed for the asm and also are useful for
// convenience in the Go code in a few places where we need to intentionally
// avoid constant arithmetic (e.g., v1 := prime1 + prime2 fails because the
// result overflows a uint64).
var (
prime1v = prime1
prime2v = prime2
prime3v = prime3
prime4v = prime4
prime5v = prime5
)
// Store the primes in an array as well.
//
// The consts are used when possible in Go code to avoid MOVs but we need a
// contiguous array of the assembly code.
var primes = [...]uint64{prime1, prime2, prime3, prime4, prime5}
// Digest implements hash.Hash64.
type Digest struct {
@@ -50,10 +42,10 @@ func New() *Digest {
// Reset clears the Digest's state so that it can be reused.
func (d *Digest) Reset() {
d.v1 = prime1v + prime2
d.v1 = primes[0] + prime2
d.v2 = prime2
d.v3 = 0
d.v4 = -prime1v
d.v4 = -primes[0]
d.total = 0
d.n = 0
}
@@ -69,21 +61,23 @@ func (d *Digest) Write(b []byte) (n int, err error) {
n = len(b)
d.total += uint64(n)
memleft := d.mem[d.n&(len(d.mem)-1):]
if d.n+n < 32 {
// This new data doesn't even fill the current block.
copy(d.mem[d.n:], b)
copy(memleft, b)
d.n += n
return
}
if d.n > 0 {
// Finish off the partial block.
copy(d.mem[d.n:], b)
c := copy(memleft, b)
d.v1 = round(d.v1, u64(d.mem[0:8]))
d.v2 = round(d.v2, u64(d.mem[8:16]))
d.v3 = round(d.v3, u64(d.mem[16:24]))
d.v4 = round(d.v4, u64(d.mem[24:32]))
b = b[32-d.n:]
b = b[c:]
d.n = 0
}
@@ -133,21 +127,20 @@ func (d *Digest) Sum64() uint64 {
h += d.total
i, end := 0, d.n
for ; i+8 <= end; i += 8 {
k1 := round(0, u64(d.mem[i:i+8]))
b := d.mem[:d.n&(len(d.mem)-1)]
for ; len(b) >= 8; b = b[8:] {
k1 := round(0, u64(b[:8]))
h ^= k1
h = rol27(h)*prime1 + prime4
}
if i+4 <= end {
h ^= uint64(u32(d.mem[i:i+4])) * prime1
if len(b) >= 4 {
h ^= uint64(u32(b[:4])) * prime1
h = rol23(h)*prime2 + prime3
i += 4
b = b[4:]
}
for i < end {
h ^= uint64(d.mem[i]) * prime5
for ; len(b) > 0; b = b[1:] {
h ^= uint64(b[0]) * prime5
h = rol11(h) * prime1
i++
}
h ^= h >> 33

View File

@@ -1,215 +1,209 @@
//go:build !appengine && gc && !purego
// +build !appengine
// +build gc
// +build !purego
#include "textflag.h"
// Register allocation:
// AX h
// SI pointer to advance through b
// DX n
// BX loop end
// R8 v1, k1
// R9 v2
// R10 v3
// R11 v4
// R12 tmp
// R13 prime1v
// R14 prime2v
// DI prime4v
// Registers:
#define h AX
#define d AX
#define p SI // pointer to advance through b
#define n DX
#define end BX // loop end
#define v1 R8
#define v2 R9
#define v3 R10
#define v4 R11
#define x R12
#define prime1 R13
#define prime2 R14
#define prime4 DI
// round reads from and advances the buffer pointer in SI.
// It assumes that R13 has prime1v and R14 has prime2v.
#define round(r) \
MOVQ (SI), R12 \
ADDQ $8, SI \
IMULQ R14, R12 \
ADDQ R12, r \
ROLQ $31, r \
IMULQ R13, r
#define round(acc, x) \
IMULQ prime2, x \
ADDQ x, acc \
ROLQ $31, acc \
IMULQ prime1, acc
// mergeRound applies a merge round on the two registers acc and val.
// It assumes that R13 has prime1v, R14 has prime2v, and DI has prime4v.
#define mergeRound(acc, val) \
IMULQ R14, val \
ROLQ $31, val \
IMULQ R13, val \
XORQ val, acc \
IMULQ R13, acc \
ADDQ DI, acc
// round0 performs the operation x = round(0, x).
#define round0(x) \
IMULQ prime2, x \
ROLQ $31, x \
IMULQ prime1, x
// mergeRound applies a merge round on the two registers acc and x.
// It assumes that prime1, prime2, and prime4 have been loaded.
#define mergeRound(acc, x) \
round0(x) \
XORQ x, acc \
IMULQ prime1, acc \
ADDQ prime4, acc
// blockLoop processes as many 32-byte blocks as possible,
// updating v1, v2, v3, and v4. It assumes that there is at least one block
// to process.
#define blockLoop() \
loop: \
MOVQ +0(p), x \
round(v1, x) \
MOVQ +8(p), x \
round(v2, x) \
MOVQ +16(p), x \
round(v3, x) \
MOVQ +24(p), x \
round(v4, x) \
ADDQ $32, p \
CMPQ p, end \
JLE loop
// func Sum64(b []byte) uint64
TEXT ·Sum64(SB), NOSPLIT, $0-32
TEXT ·Sum64(SB), NOSPLIT|NOFRAME, $0-32
// Load fixed primes.
MOVQ ·prime1v(SB), R13
MOVQ ·prime2v(SB), R14
MOVQ ·prime4v(SB), DI
MOVQ ·primes+0(SB), prime1
MOVQ ·primes+8(SB), prime2
MOVQ ·primes+24(SB), prime4
// Load slice.
MOVQ b_base+0(FP), SI
MOVQ b_len+8(FP), DX
LEAQ (SI)(DX*1), BX
MOVQ b_base+0(FP), p
MOVQ b_len+8(FP), n
LEAQ (p)(n*1), end
// The first loop limit will be len(b)-32.
SUBQ $32, BX
SUBQ $32, end
// Check whether we have at least one block.
CMPQ DX, $32
CMPQ n, $32
JLT noBlocks
// Set up initial state (v1, v2, v3, v4).
MOVQ R13, R8
ADDQ R14, R8
MOVQ R14, R9
XORQ R10, R10
XORQ R11, R11
SUBQ R13, R11
MOVQ prime1, v1
ADDQ prime2, v1
MOVQ prime2, v2
XORQ v3, v3
XORQ v4, v4
SUBQ prime1, v4
// Loop until SI > BX.
blockLoop:
round(R8)
round(R9)
round(R10)
round(R11)
blockLoop()
CMPQ SI, BX
JLE blockLoop
MOVQ v1, h
ROLQ $1, h
MOVQ v2, x
ROLQ $7, x
ADDQ x, h
MOVQ v3, x
ROLQ $12, x
ADDQ x, h
MOVQ v4, x
ROLQ $18, x
ADDQ x, h
MOVQ R8, AX
ROLQ $1, AX
MOVQ R9, R12
ROLQ $7, R12
ADDQ R12, AX
MOVQ R10, R12
ROLQ $12, R12
ADDQ R12, AX
MOVQ R11, R12
ROLQ $18, R12
ADDQ R12, AX
mergeRound(AX, R8)
mergeRound(AX, R9)
mergeRound(AX, R10)
mergeRound(AX, R11)
mergeRound(h, v1)
mergeRound(h, v2)
mergeRound(h, v3)
mergeRound(h, v4)
JMP afterBlocks
noBlocks:
MOVQ ·prime5v(SB), AX
MOVQ ·primes+32(SB), h
afterBlocks:
ADDQ DX, AX
ADDQ n, h
// Right now BX has len(b)-32, and we want to loop until SI > len(b)-8.
ADDQ $24, BX
ADDQ $24, end
CMPQ p, end
JG try4
CMPQ SI, BX
JG fourByte
loop8:
MOVQ (p), x
ADDQ $8, p
round0(x)
XORQ x, h
ROLQ $27, h
IMULQ prime1, h
ADDQ prime4, h
wordLoop:
// Calculate k1.
MOVQ (SI), R8
ADDQ $8, SI
IMULQ R14, R8
ROLQ $31, R8
IMULQ R13, R8
CMPQ p, end
JLE loop8
XORQ R8, AX
ROLQ $27, AX
IMULQ R13, AX
ADDQ DI, AX
try4:
ADDQ $4, end
CMPQ p, end
JG try1
CMPQ SI, BX
JLE wordLoop
MOVL (p), x
ADDQ $4, p
IMULQ prime1, x
XORQ x, h
fourByte:
ADDQ $4, BX
CMPQ SI, BX
JG singles
ROLQ $23, h
IMULQ prime2, h
ADDQ ·primes+16(SB), h
MOVL (SI), R8
ADDQ $4, SI
IMULQ R13, R8
XORQ R8, AX
ROLQ $23, AX
IMULQ R14, AX
ADDQ ·prime3v(SB), AX
singles:
ADDQ $4, BX
CMPQ SI, BX
try1:
ADDQ $4, end
CMPQ p, end
JGE finalize
singlesLoop:
MOVBQZX (SI), R12
ADDQ $1, SI
IMULQ ·prime5v(SB), R12
XORQ R12, AX
loop1:
MOVBQZX (p), x
ADDQ $1, p
IMULQ ·primes+32(SB), x
XORQ x, h
ROLQ $11, h
IMULQ prime1, h
ROLQ $11, AX
IMULQ R13, AX
CMPQ SI, BX
JL singlesLoop
CMPQ p, end
JL loop1
finalize:
MOVQ AX, R12
SHRQ $33, R12
XORQ R12, AX
IMULQ R14, AX
MOVQ AX, R12
SHRQ $29, R12
XORQ R12, AX
IMULQ ·prime3v(SB), AX
MOVQ AX, R12
SHRQ $32, R12
XORQ R12, AX
MOVQ h, x
SHRQ $33, x
XORQ x, h
IMULQ prime2, h
MOVQ h, x
SHRQ $29, x
XORQ x, h
IMULQ ·primes+16(SB), h
MOVQ h, x
SHRQ $32, x
XORQ x, h
MOVQ AX, ret+24(FP)
MOVQ h, ret+24(FP)
RET
// writeBlocks uses the same registers as above except that it uses AX to store
// the d pointer.
// func writeBlocks(d *Digest, b []byte) int
TEXT ·writeBlocks(SB), NOSPLIT, $0-40
TEXT ·writeBlocks(SB), NOSPLIT|NOFRAME, $0-40
// Load fixed primes needed for round.
MOVQ ·prime1v(SB), R13
MOVQ ·prime2v(SB), R14
MOVQ ·primes+0(SB), prime1
MOVQ ·primes+8(SB), prime2
// Load slice.
MOVQ b_base+8(FP), SI
MOVQ b_len+16(FP), DX
LEAQ (SI)(DX*1), BX
SUBQ $32, BX
MOVQ b_base+8(FP), p
MOVQ b_len+16(FP), n
LEAQ (p)(n*1), end
SUBQ $32, end
// Load vN from d.
MOVQ d+0(FP), AX
MOVQ 0(AX), R8 // v1
MOVQ 8(AX), R9 // v2
MOVQ 16(AX), R10 // v3
MOVQ 24(AX), R11 // v4
MOVQ s+0(FP), d
MOVQ 0(d), v1
MOVQ 8(d), v2
MOVQ 16(d), v3
MOVQ 24(d), v4
// We don't need to check the loop condition here; this function is
// always called with at least one block of data to process.
blockLoop:
round(R8)
round(R9)
round(R10)
round(R11)
CMPQ SI, BX
JLE blockLoop
blockLoop()
// Copy vN back to d.
MOVQ R8, 0(AX)
MOVQ R9, 8(AX)
MOVQ R10, 16(AX)
MOVQ R11, 24(AX)
MOVQ v1, 0(d)
MOVQ v2, 8(d)
MOVQ v3, 16(d)
MOVQ v4, 24(d)
// The number of bytes written is SI minus the old base pointer.
SUBQ b_base+8(FP), SI
MOVQ SI, ret+32(FP)
// The number of bytes written is p minus the old base pointer.
SUBQ b_base+8(FP), p
MOVQ p, ret+32(FP)
RET

183
vendor/github.com/cespare/xxhash/v2/xxhash_arm64.s generated vendored Normal file
View File

@@ -0,0 +1,183 @@
//go:build !appengine && gc && !purego
// +build !appengine
// +build gc
// +build !purego
#include "textflag.h"
// Registers:
#define digest R1
#define h R2 // return value
#define p R3 // input pointer
#define n R4 // input length
#define nblocks R5 // n / 32
#define prime1 R7
#define prime2 R8
#define prime3 R9
#define prime4 R10
#define prime5 R11
#define v1 R12
#define v2 R13
#define v3 R14
#define v4 R15
#define x1 R20
#define x2 R21
#define x3 R22
#define x4 R23
#define round(acc, x) \
MADD prime2, acc, x, acc \
ROR $64-31, acc \
MUL prime1, acc
// round0 performs the operation x = round(0, x).
#define round0(x) \
MUL prime2, x \
ROR $64-31, x \
MUL prime1, x
#define mergeRound(acc, x) \
round0(x) \
EOR x, acc \
MADD acc, prime4, prime1, acc
// blockLoop processes as many 32-byte blocks as possible,
// updating v1, v2, v3, and v4. It assumes that n >= 32.
#define blockLoop() \
LSR $5, n, nblocks \
PCALIGN $16 \
loop: \
LDP.P 16(p), (x1, x2) \
LDP.P 16(p), (x3, x4) \
round(v1, x1) \
round(v2, x2) \
round(v3, x3) \
round(v4, x4) \
SUB $1, nblocks \
CBNZ nblocks, loop
// func Sum64(b []byte) uint64
TEXT ·Sum64(SB), NOSPLIT|NOFRAME, $0-32
LDP b_base+0(FP), (p, n)
LDP ·primes+0(SB), (prime1, prime2)
LDP ·primes+16(SB), (prime3, prime4)
MOVD ·primes+32(SB), prime5
CMP $32, n
CSEL LT, prime5, ZR, h // if n < 32 { h = prime5 } else { h = 0 }
BLT afterLoop
ADD prime1, prime2, v1
MOVD prime2, v2
MOVD $0, v3
NEG prime1, v4
blockLoop()
ROR $64-1, v1, x1
ROR $64-7, v2, x2
ADD x1, x2
ROR $64-12, v3, x3
ROR $64-18, v4, x4
ADD x3, x4
ADD x2, x4, h
mergeRound(h, v1)
mergeRound(h, v2)
mergeRound(h, v3)
mergeRound(h, v4)
afterLoop:
ADD n, h
TBZ $4, n, try8
LDP.P 16(p), (x1, x2)
round0(x1)
// NOTE: here and below, sequencing the EOR after the ROR (using a
// rotated register) is worth a small but measurable speedup for small
// inputs.
ROR $64-27, h
EOR x1 @> 64-27, h, h
MADD h, prime4, prime1, h
round0(x2)
ROR $64-27, h
EOR x2 @> 64-27, h, h
MADD h, prime4, prime1, h
try8:
TBZ $3, n, try4
MOVD.P 8(p), x1
round0(x1)
ROR $64-27, h
EOR x1 @> 64-27, h, h
MADD h, prime4, prime1, h
try4:
TBZ $2, n, try2
MOVWU.P 4(p), x2
MUL prime1, x2
ROR $64-23, h
EOR x2 @> 64-23, h, h
MADD h, prime3, prime2, h
try2:
TBZ $1, n, try1
MOVHU.P 2(p), x3
AND $255, x3, x1
LSR $8, x3, x2
MUL prime5, x1
ROR $64-11, h
EOR x1 @> 64-11, h, h
MUL prime1, h
MUL prime5, x2
ROR $64-11, h
EOR x2 @> 64-11, h, h
MUL prime1, h
try1:
TBZ $0, n, finalize
MOVBU (p), x4
MUL prime5, x4
ROR $64-11, h
EOR x4 @> 64-11, h, h
MUL prime1, h
finalize:
EOR h >> 33, h
MUL prime2, h
EOR h >> 29, h
MUL prime3, h
EOR h >> 32, h
MOVD h, ret+24(FP)
RET
// func writeBlocks(d *Digest, b []byte) int
TEXT ·writeBlocks(SB), NOSPLIT|NOFRAME, $0-40
LDP ·primes+0(SB), (prime1, prime2)
// Load state. Assume v[1-4] are stored contiguously.
MOVD d+0(FP), digest
LDP 0(digest), (v1, v2)
LDP 16(digest), (v3, v4)
LDP b_base+8(FP), (p, n)
blockLoop()
// Store updated state.
STP (v1, v2), 0(digest)
STP (v3, v4), 16(digest)
BIC $31, n
MOVD n, ret+32(FP)
RET

View File

@@ -1,3 +1,5 @@
//go:build (amd64 || arm64) && !appengine && gc && !purego
// +build amd64 arm64
// +build !appengine
// +build gc
// +build !purego

View File

@@ -1,4 +1,5 @@
// +build !amd64 appengine !gc purego
//go:build (!amd64 && !arm64) || appengine || !gc || purego
// +build !amd64,!arm64 appengine !gc purego
package xxhash
@@ -14,10 +15,10 @@ func Sum64(b []byte) uint64 {
var h uint64
if n >= 32 {
v1 := prime1v + prime2
v1 := primes[0] + prime2
v2 := prime2
v3 := uint64(0)
v4 := -prime1v
v4 := -primes[0]
for len(b) >= 32 {
v1 = round(v1, u64(b[0:8:len(b)]))
v2 = round(v2, u64(b[8:16:len(b)]))
@@ -36,19 +37,18 @@ func Sum64(b []byte) uint64 {
h += uint64(n)
i, end := 0, len(b)
for ; i+8 <= end; i += 8 {
k1 := round(0, u64(b[i:i+8:len(b)]))
for ; len(b) >= 8; b = b[8:] {
k1 := round(0, u64(b[:8]))
h ^= k1
h = rol27(h)*prime1 + prime4
}
if i+4 <= end {
h ^= uint64(u32(b[i:i+4:len(b)])) * prime1
if len(b) >= 4 {
h ^= uint64(u32(b[:4])) * prime1
h = rol23(h)*prime2 + prime3
i += 4
b = b[4:]
}
for ; i < end; i++ {
h ^= uint64(b[i]) * prime5
for ; len(b) > 0; b = b[1:] {
h ^= uint64(b[0]) * prime5
h = rol11(h) * prime1
}

View File

@@ -1,3 +1,4 @@
//go:build appengine
// +build appengine
// This file contains the safe implementations of otherwise unsafe-using code.

View File

@@ -1,3 +1,4 @@
//go:build !appengine
// +build !appengine
// This file encapsulates usage of unsafe.
@@ -11,7 +12,7 @@ import (
// In the future it's possible that compiler optimizations will make these
// XxxString functions unnecessary by realizing that calls such as
// Sum64([]byte(s)) don't need to copy s. See https://golang.org/issue/2205.
// Sum64([]byte(s)) don't need to copy s. See https://go.dev/issue/2205.
// If that happens, even if we keep these functions they can be replaced with
// the trivial safe code.

View File

@@ -1,5 +1,5 @@
//go:build !windows && !solaris
//+build !windows,!solaris
//go:build !windows && !solaris && !aix
// +build !windows,!solaris,!aix
package pty

View File

@@ -1,5 +1,5 @@
//go:build (darwin || dragonfly || freebsd || netbsd || openbsd)
//+build darwin dragonfly freebsd netbsd openbsd
//go:build darwin || dragonfly || freebsd || netbsd || openbsd
// +build darwin dragonfly freebsd netbsd openbsd
package pty

View File

@@ -1,5 +1,5 @@
//go:build solaris
//+build solaris
// +build solaris
package pty

13
vendor/github.com/creack/pty/ioctl_unsupported.go generated vendored Normal file
View File

@@ -0,0 +1,13 @@
//go:build aix
// +build aix
package pty
const (
TIOCGWINSZ = 0
TIOCSWINSZ = 0
)
func ioctl(fd, cmd, ptr uintptr) error {
return ErrUnsupported
}

View File

@@ -1,5 +1,5 @@
//go:build darwin
//+build darwin
// +build darwin
package pty

View File

@@ -1,5 +1,5 @@
//go:build dragonfly
//+build dragonfly
// +build dragonfly
package pty

View File

@@ -1,5 +1,5 @@
//go:build freebsd
//+build freebsd
// +build freebsd
package pty

View File

@@ -1,5 +1,5 @@
//go:build linux
//+build linux
// +build linux
package pty

View File

@@ -1,5 +1,5 @@
//go:build netbsd
//+build netbsd
// +build netbsd
package pty

View File

@@ -1,5 +1,5 @@
//go:build openbsd
//+build openbsd
// +build openbsd
package pty

View File

@@ -1,5 +1,5 @@
//go:build solaris
//+build solaris
// +build solaris
package pty

View File

@@ -1,5 +1,5 @@
//go:build !linux && !darwin && !freebsd && !dragonfly && !netbsd && !openbsd && !solaris
//+build !linux,!darwin,!freebsd,!dragonfly,!netbsd,!openbsd,!solaris
// +build !linux,!darwin,!freebsd,!dragonfly,!netbsd,!openbsd,!solaris
package pty

18
vendor/github.com/creack/pty/run.go generated vendored
View File

@@ -1,6 +1,3 @@
//go:build !windows
//+build !windows
package pty
import (
@@ -18,21 +15,6 @@ func Start(cmd *exec.Cmd) (*os.File, error) {
return StartWithSize(cmd, nil)
}
// StartWithSize assigns a pseudo-terminal tty os.File to c.Stdin, c.Stdout,
// and c.Stderr, calls c.Start, and returns the File of the tty's
// corresponding pty.
//
// This will resize the pty to the specified size before starting the command.
// Starts the process in a new session and sets the controlling terminal.
func StartWithSize(cmd *exec.Cmd, ws *Winsize) (*os.File, error) {
if cmd.SysProcAttr == nil {
cmd.SysProcAttr = &syscall.SysProcAttr{}
}
cmd.SysProcAttr.Setsid = true
cmd.SysProcAttr.Setctty = true
return StartWithAttrs(cmd, ws, cmd.SysProcAttr)
}
// StartWithAttrs assigns a pseudo-terminal tty os.File to c.Stdin, c.Stdout,
// and c.Stderr, calls c.Start, and returns the File of the tty's
// corresponding pty.

25
vendor/github.com/creack/pty/start.go generated vendored Normal file
View File

@@ -0,0 +1,25 @@
//go:build !windows
// +build !windows
package pty
import (
"os"
"os/exec"
"syscall"
)
// StartWithSize assigns a pseudo-terminal tty os.File to c.Stdin, c.Stdout,
// and c.Stderr, calls c.Start, and returns the File of the tty's
// corresponding pty.
//
// This will resize the pty to the specified size before starting the command.
// Starts the process in a new session and sets the controlling terminal.
func StartWithSize(cmd *exec.Cmd, ws *Winsize) (*os.File, error) {
if cmd.SysProcAttr == nil {
cmd.SysProcAttr = &syscall.SysProcAttr{}
}
cmd.SysProcAttr.Setsid = true
cmd.SysProcAttr.Setctty = true
return StartWithAttrs(cmd, ws, cmd.SysProcAttr)
}

19
vendor/github.com/creack/pty/start_windows.go generated vendored Normal file
View File

@@ -0,0 +1,19 @@
//go:build windows
// +build windows
package pty
import (
"os"
"os/exec"
)
// StartWithSize assigns a pseudo-terminal tty os.File to c.Stdin, c.Stdout,
// and c.Stderr, calls c.Start, and returns the File of the tty's
// corresponding pty.
//
// This will resize the pty to the specified size before starting the command.
// Starts the process in a new session and sets the controlling terminal.
func StartWithSize(cmd *exec.Cmd, ws *Winsize) (*os.File, error) {
return nil, ErrUnsupported
}

View File

@@ -4,30 +4,30 @@
# Does not actually test the logic, just the compilation so we make sure we don't break code depending on the lib.
echo2() {
echo $@ >&2
echo $@ >&2
}
trap end 0
end() {
[ "$?" = 0 ] && echo2 "Pass." || (echo2 "Fail."; exit 1)
[ "$?" = 0 ] && echo2 "Pass." || (echo2 "Fail."; exit 1)
}
cross() {
os=$1
shift
echo2 "Build for $os."
for arch in $@; do
echo2 " - $os/$arch"
GOOS=$os GOARCH=$arch go build
done
echo2
os=$1
shift
echo2 "Build for $os."
for arch in $@; do
echo2 " - $os/$arch"
GOOS=$os GOARCH=$arch go build
done
echo2
}
set -e
cross linux amd64 386 arm arm64 ppc64 ppc64le s390x mips mipsle mips64 mips64le
cross darwin amd64 arm64
cross freebsd amd64 386 arm arm64 ppc64
cross freebsd amd64 386 arm arm64
cross netbsd amd64 386 arm arm64
cross openbsd amd64 386 arm arm64
cross dragonfly amd64
@@ -41,8 +41,8 @@ cross windows amd64 386 arm
# Some os/arch require a different compiler. Run in docker.
if ! hash docker; then
# If docker is not present, stop here.
return
# If docker is not present, stop here.
return
fi
echo2 "Build for linux."

View File

@@ -20,5 +20,8 @@ func InheritSize(pty, tty *os.File) error {
// in each line) in terminal t.
func Getsize(t *os.File) (rows, cols int, err error) {
ws, err := GetsizeFull(t)
return int(ws.Rows), int(ws.Cols), err
if err != nil {
return 0, 0, err
}
return int(ws.Rows), int(ws.Cols), nil
}

View File

@@ -1,5 +1,5 @@
//go:build !windows
//+build !windows
// +build !windows
package pty

View File

@@ -1,5 +1,5 @@
//go:build windows
//+build windows
// +build windows
package pty
@@ -9,7 +9,7 @@ import (
// Winsize is a dummy struct to enable compilation on unsupported platforms.
type Winsize struct {
Rows, Cols, X, Y uint
Rows, Cols, X, Y uint16
}
// Setsize resizes t to s.

View File

@@ -1,5 +1,5 @@
//go:build 386
//+build 386
// +build 386
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs types.go

View File

@@ -1,5 +1,5 @@
//go:build amd64
//+build amd64
// +build amd64
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs types.go

View File

@@ -1,5 +1,5 @@
//go:build arm
//+build arm
// +build arm
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs types.go

View File

@@ -1,5 +1,5 @@
//go:build arm64
//+build arm64
// +build arm64
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs types.go

View File

@@ -1,5 +1,5 @@
//go:build amd64 && dragonfly
//+build amd64,dragonfly
// +build amd64,dragonfly
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs types_dragonfly.go

View File

@@ -1,5 +1,5 @@
//go:build 386 && freebsd
//+build 386,freebsd
// +build 386,freebsd
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs types_freebsd.go

View File

@@ -1,5 +1,5 @@
//go:build amd64 && freebsd
//+build amd64,freebsd
// +build amd64,freebsd
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs types_freebsd.go

View File

@@ -1,5 +1,5 @@
//go:build arm && freebsd
//+build arm,freebsd
// +build arm,freebsd
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs types_freebsd.go

View File

@@ -1,5 +1,5 @@
//go:build arm64 && freebsd
//+build arm64,freebsd
// +build arm64,freebsd
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs types_freebsd.go

View File

@@ -1,6 +1,6 @@
//go:build (mips || mipsle || mips64 || mips64le) && linux
//+build linux
//+build mips mipsle mips64 mips64le
// +build mips mipsle mips64 mips64le
// +build linux
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs types.go

View File

@@ -1,6 +1,6 @@
//go:build (386 || amd64 || arm || arm64) && netbsd
//+build netbsd
//+build 386 amd64 arm arm64
// +build 386 amd64 arm arm64
// +build netbsd
package pty

View File

@@ -1,6 +1,6 @@
//go:build (386 || amd64 || arm || arm64 || mips64) && openbsd
//+build openbsd
//+build 386 amd64 arm arm64 mips64
// +build 386 amd64 arm arm64 mips64
// +build openbsd
package pty

View File

@@ -1,5 +1,5 @@
//go:build ppc64
//+build ppc64
// +build ppc64
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs types.go

View File

@@ -1,5 +1,5 @@
//go:build ppc64le
//+build ppc64le
// +build ppc64le
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs types.go

View File

@@ -1,5 +1,5 @@
//go:build riscv || riscv64
//+build riscv riscv64
// +build riscv riscv64
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs types.go

View File

@@ -1,5 +1,5 @@
//go:build s390x
//+build s390x
// +build s390x
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs types.go

View File

@@ -6,7 +6,6 @@ linters:
disable-all: true
enable:
- asciicheck
- deadcode
- errcheck
- forcetypeassert
- gocritic
@@ -18,10 +17,8 @@ linters:
- misspell
- revive
- staticcheck
- structcheck
- typecheck
- unused
- varcheck
issues:
exclude-use-default: false

View File

@@ -20,35 +20,5 @@ package logr
// used whenever the caller is not interested in the logs. Logger instances
// produced by this function always compare as equal.
func Discard() Logger {
return Logger{
level: 0,
sink: discardLogSink{},
}
}
// discardLogSink is a LogSink that discards all messages.
type discardLogSink struct{}
// Verify that it actually implements the interface
var _ LogSink = discardLogSink{}
func (l discardLogSink) Init(RuntimeInfo) {
}
func (l discardLogSink) Enabled(int) bool {
return false
}
func (l discardLogSink) Info(int, string, ...interface{}) {
}
func (l discardLogSink) Error(error, string, ...interface{}) {
}
func (l discardLogSink) WithValues(...interface{}) LogSink {
return l
}
func (l discardLogSink) WithName(string) LogSink {
return l
return New(nil)
}

View File

@@ -21,13 +21,13 @@ limitations under the License.
// github.com/go-logr/logr.LogSink with output through an arbitrary
// "write" function. See New and NewJSON for details.
//
// Custom LogSinks
// # Custom LogSinks
//
// For users who need more control, a funcr.Formatter can be embedded inside
// your own custom LogSink implementation. This is useful when the LogSink
// needs to implement additional methods, for example.
//
// Formatting
// # Formatting
//
// This will respect logr.Marshaler, fmt.Stringer, and error interfaces for
// values which are being logged. When rendering a struct, funcr will use Go's
@@ -37,6 +37,7 @@ package funcr
import (
"bytes"
"encoding"
"encoding/json"
"fmt"
"path/filepath"
"reflect"
@@ -217,7 +218,7 @@ func newFormatter(opts Options, outfmt outputFormat) Formatter {
prefix: "",
values: nil,
depth: 0,
opts: opts,
opts: &opts,
}
return f
}
@@ -231,7 +232,7 @@ type Formatter struct {
values []interface{}
valuesStr string
depth int
opts Options
opts *Options
}
// outputFormat indicates which outputFormat to use.
@@ -447,6 +448,7 @@ func (f Formatter) prettyWithFlags(value interface{}, flags uint32, depth int) s
if flags&flagRawStruct == 0 {
buf.WriteByte('{')
}
printComma := false // testing i>0 is not enough because of JSON omitted fields
for i := 0; i < t.NumField(); i++ {
fld := t.Field(i)
if fld.PkgPath != "" {
@@ -478,9 +480,10 @@ func (f Formatter) prettyWithFlags(value interface{}, flags uint32, depth int) s
if omitempty && isEmpty(v.Field(i)) {
continue
}
if i > 0 {
if printComma {
buf.WriteByte(',')
}
printComma = true // if we got here, we are rendering a field
if fld.Anonymous && fld.Type.Kind() == reflect.Struct && name == "" {
buf.WriteString(f.prettyWithFlags(v.Field(i).Interface(), flags|flagRawStruct, depth+1))
continue
@@ -500,6 +503,20 @@ func (f Formatter) prettyWithFlags(value interface{}, flags uint32, depth int) s
}
return buf.String()
case reflect.Slice, reflect.Array:
// If this is outputing as JSON make sure this isn't really a json.RawMessage.
// If so just emit "as-is" and don't pretty it as that will just print
// it as [X,Y,Z,...] which isn't terribly useful vs the string form you really want.
if f.outputFormat == outputJSON {
if rm, ok := value.(json.RawMessage); ok {
// If it's empty make sure we emit an empty value as the array style would below.
if len(rm) > 0 {
buf.Write(rm)
} else {
buf.WriteString("null")
}
return buf.String()
}
}
buf.WriteByte('[')
for i := 0; i < v.Len(); i++ {
if i > 0 {

View File

@@ -21,7 +21,7 @@ limitations under the License.
// to back that API. Packages in the Go ecosystem can depend on this package,
// while callers can implement logging with whatever backend is appropriate.
//
// Usage
// # Usage
//
// Logging is done using a Logger instance. Logger is a concrete type with
// methods, which defers the actual logging to a LogSink interface. The main
@@ -30,16 +30,20 @@ limitations under the License.
// "structured logging".
//
// With Go's standard log package, we might write:
// log.Printf("setting target value %s", targetValue)
//
// log.Printf("setting target value %s", targetValue)
//
// With logr's structured logging, we'd write:
// logger.Info("setting target", "value", targetValue)
//
// logger.Info("setting target", "value", targetValue)
//
// Errors are much the same. Instead of:
// log.Printf("failed to open the pod bay door for user %s: %v", user, err)
//
// log.Printf("failed to open the pod bay door for user %s: %v", user, err)
//
// We'd write:
// logger.Error(err, "failed to open the pod bay door", "user", user)
//
// logger.Error(err, "failed to open the pod bay door", "user", user)
//
// Info() and Error() are very similar, but they are separate methods so that
// LogSink implementations can choose to do things like attach additional
@@ -47,7 +51,7 @@ limitations under the License.
// always logged, regardless of the current verbosity. If there is no error
// instance available, passing nil is valid.
//
// Verbosity
// # Verbosity
//
// Often we want to log information only when the application in "verbose
// mode". To write log lines that are more verbose, Logger has a V() method.
@@ -58,20 +62,22 @@ limitations under the License.
// Error messages do not have a verbosity level and are always logged.
//
// Where we might have written:
// if flVerbose >= 2 {
// log.Printf("an unusual thing happened")
// }
//
// if flVerbose >= 2 {
// log.Printf("an unusual thing happened")
// }
//
// We can write:
// logger.V(2).Info("an unusual thing happened")
//
// Logger Names
// logger.V(2).Info("an unusual thing happened")
//
// # Logger Names
//
// Logger instances can have name strings so that all messages logged through
// that instance have additional context. For example, you might want to add
// a subsystem name:
//
// logger.WithName("compactor").Info("started", "time", time.Now())
// logger.WithName("compactor").Info("started", "time", time.Now())
//
// The WithName() method returns a new Logger, which can be passed to
// constructors or other functions for further use. Repeated use of WithName()
@@ -82,25 +88,27 @@ limitations under the License.
// joining operation (e.g. whitespace, commas, periods, slashes, brackets,
// quotes, etc).
//
// Saved Values
// # Saved Values
//
// Logger instances can store any number of key/value pairs, which will be
// logged alongside all messages logged through that instance. For example,
// you might want to create a Logger instance per managed object:
//
// With the standard log package, we might write:
// log.Printf("decided to set field foo to value %q for object %s/%s",
// targetValue, object.Namespace, object.Name)
//
// log.Printf("decided to set field foo to value %q for object %s/%s",
// targetValue, object.Namespace, object.Name)
//
// With logr we'd write:
// // Elsewhere: set up the logger to log the object name.
// obj.logger = mainLogger.WithValues(
// "name", obj.name, "namespace", obj.namespace)
//
// // later on...
// obj.logger.Info("setting foo", "value", targetValue)
// // Elsewhere: set up the logger to log the object name.
// obj.logger = mainLogger.WithValues(
// "name", obj.name, "namespace", obj.namespace)
//
// Best Practices
// // later on...
// obj.logger.Info("setting foo", "value", targetValue)
//
// # Best Practices
//
// Logger has very few hard rules, with the goal that LogSink implementations
// might have a lot of freedom to differentiate. There are, however, some
@@ -124,15 +132,15 @@ limitations under the License.
// around. For cases where passing a logger is optional, a pointer to Logger
// should be used.
//
// Key Naming Conventions
// # Key Naming Conventions
//
// Keys are not strictly required to conform to any specification or regex, but
// it is recommended that they:
// * be human-readable and meaningful (not auto-generated or simple ordinals)
// * be constant (not dependent on input data)
// * contain only printable characters
// * not contain whitespace or punctuation
// * use lower case for simple keys and lowerCamelCase for more complex ones
// - be human-readable and meaningful (not auto-generated or simple ordinals)
// - be constant (not dependent on input data)
// - contain only printable characters
// - not contain whitespace or punctuation
// - use lower case for simple keys and lowerCamelCase for more complex ones
//
// These guidelines help ensure that log data is processed properly regardless
// of the log implementation. For example, log implementations will try to
@@ -141,51 +149,54 @@ limitations under the License.
// While users are generally free to use key names of their choice, it's
// generally best to avoid using the following keys, as they're frequently used
// by implementations:
// * "caller": the calling information (file/line) of a particular log line
// * "error": the underlying error value in the `Error` method
// * "level": the log level
// * "logger": the name of the associated logger
// * "msg": the log message
// * "stacktrace": the stack trace associated with a particular log line or
// error (often from the `Error` message)
// * "ts": the timestamp for a log line
// - "caller": the calling information (file/line) of a particular log line
// - "error": the underlying error value in the `Error` method
// - "level": the log level
// - "logger": the name of the associated logger
// - "msg": the log message
// - "stacktrace": the stack trace associated with a particular log line or
// error (often from the `Error` message)
// - "ts": the timestamp for a log line
//
// Implementations are encouraged to make use of these keys to represent the
// above concepts, when necessary (for example, in a pure-JSON output form, it
// would be necessary to represent at least message and timestamp as ordinary
// named values).
//
// Break Glass
// # Break Glass
//
// Implementations may choose to give callers access to the underlying
// logging implementation. The recommended pattern for this is:
// // Underlier exposes access to the underlying logging implementation.
// // Since callers only have a logr.Logger, they have to know which
// // implementation is in use, so this interface is less of an abstraction
// // and more of way to test type conversion.
// type Underlier interface {
// GetUnderlying() <underlying-type>
// }
//
// // Underlier exposes access to the underlying logging implementation.
// // Since callers only have a logr.Logger, they have to know which
// // implementation is in use, so this interface is less of an abstraction
// // and more of way to test type conversion.
// type Underlier interface {
// GetUnderlying() <underlying-type>
// }
//
// Logger grants access to the sink to enable type assertions like this:
// func DoSomethingWithImpl(log logr.Logger) {
// if underlier, ok := log.GetSink()(impl.Underlier) {
// implLogger := underlier.GetUnderlying()
// ...
// }
// }
//
// func DoSomethingWithImpl(log logr.Logger) {
// if underlier, ok := log.GetSink().(impl.Underlier); ok {
// implLogger := underlier.GetUnderlying()
// ...
// }
// }
//
// Custom `With*` functions can be implemented by copying the complete
// Logger struct and replacing the sink in the copy:
// // WithFooBar changes the foobar parameter in the log sink and returns a
// // new logger with that modified sink. It does nothing for loggers where
// // the sink doesn't support that parameter.
// func WithFoobar(log logr.Logger, foobar int) logr.Logger {
// if foobarLogSink, ok := log.GetSink()(FoobarSink); ok {
// log = log.WithSink(foobarLogSink.WithFooBar(foobar))
// }
// return log
// }
//
// // WithFooBar changes the foobar parameter in the log sink and returns a
// // new logger with that modified sink. It does nothing for loggers where
// // the sink doesn't support that parameter.
// func WithFoobar(log logr.Logger, foobar int) logr.Logger {
// if foobarLogSink, ok := log.GetSink().(FoobarSink); ok {
// log = log.WithSink(foobarLogSink.WithFooBar(foobar))
// }
// return log
// }
//
// Don't use New to construct a new Logger with a LogSink retrieved from an
// existing Logger. Source code attribution might not work correctly and
@@ -201,11 +212,14 @@ import (
)
// New returns a new Logger instance. This is primarily used by libraries
// implementing LogSink, rather than end users.
// implementing LogSink, rather than end users. Passing a nil sink will create
// a Logger which discards all log lines.
func New(sink LogSink) Logger {
logger := Logger{}
logger.setSink(sink)
sink.Init(runtimeInfo)
if sink != nil {
sink.Init(runtimeInfo)
}
return logger
}
@@ -244,7 +258,7 @@ type Logger struct {
// Enabled tests whether this Logger is enabled. For example, commandline
// flags might be used to set the logging verbosity and disable some info logs.
func (l Logger) Enabled() bool {
return l.sink.Enabled(l.level)
return l.sink != nil && l.sink.Enabled(l.level)
}
// Info logs a non-error message with the given key/value pairs as context.
@@ -254,6 +268,9 @@ func (l Logger) Enabled() bool {
// information. The key/value pairs must alternate string keys and arbitrary
// values.
func (l Logger) Info(msg string, keysAndValues ...interface{}) {
if l.sink == nil {
return
}
if l.Enabled() {
if withHelper, ok := l.sink.(CallStackHelperLogSink); ok {
withHelper.GetCallStackHelper()()
@@ -273,6 +290,9 @@ func (l Logger) Info(msg string, keysAndValues ...interface{}) {
// triggered this log line, if present. The err parameter is optional
// and nil may be passed instead of an error instance.
func (l Logger) Error(err error, msg string, keysAndValues ...interface{}) {
if l.sink == nil {
return
}
if withHelper, ok := l.sink.(CallStackHelperLogSink); ok {
withHelper.GetCallStackHelper()()
}
@@ -284,6 +304,9 @@ func (l Logger) Error(err error, msg string, keysAndValues ...interface{}) {
// level means a log message is less important. Negative V-levels are treated
// as 0.
func (l Logger) V(level int) Logger {
if l.sink == nil {
return l
}
if level < 0 {
level = 0
}
@@ -294,6 +317,9 @@ func (l Logger) V(level int) Logger {
// WithValues returns a new Logger instance with additional key/value pairs.
// See Info for documentation on how key/value pairs work.
func (l Logger) WithValues(keysAndValues ...interface{}) Logger {
if l.sink == nil {
return l
}
l.setSink(l.sink.WithValues(keysAndValues...))
return l
}
@@ -304,6 +330,9 @@ func (l Logger) WithValues(keysAndValues ...interface{}) Logger {
// contain only letters, digits, and hyphens (see the package documentation for
// more information).
func (l Logger) WithName(name string) Logger {
if l.sink == nil {
return l
}
l.setSink(l.sink.WithName(name))
return l
}
@@ -324,6 +353,9 @@ func (l Logger) WithName(name string) Logger {
// WithCallDepth(1) because it works with implementions that support the
// CallDepthLogSink and/or CallStackHelperLogSink interfaces.
func (l Logger) WithCallDepth(depth int) Logger {
if l.sink == nil {
return l
}
if withCallDepth, ok := l.sink.(CallDepthLogSink); ok {
l.setSink(withCallDepth.WithCallDepth(depth))
}
@@ -345,6 +377,9 @@ func (l Logger) WithCallDepth(depth int) Logger {
// implementation does not support either of these, the original Logger will be
// returned.
func (l Logger) WithCallStackHelper() (func(), Logger) {
if l.sink == nil {
return func() {}, l
}
var helper func()
if withCallDepth, ok := l.sink.(CallDepthLogSink); ok {
l.setSink(withCallDepth.WithCallDepth(1))
@@ -357,6 +392,11 @@ func (l Logger) WithCallStackHelper() (func(), Logger) {
return helper, l
}
// IsZero returns true if this logger is an uninitialized zero value
func (l Logger) IsZero() bool {
return l.sink == nil
}
// contextKey is how we find Loggers in a context.Context.
type contextKey struct{}
@@ -442,7 +482,7 @@ type LogSink interface {
WithName(name string) LogSink
}
// CallDepthLogSink represents a Logger that knows how to climb the call stack
// CallDepthLogSink represents a LogSink that knows how to climb the call stack
// to identify the original call site and can offset the depth by a specified
// number of frames. This is useful for users who have helper functions
// between the "real" call site and the actual calls to Logger methods.
@@ -467,7 +507,7 @@ type CallDepthLogSink interface {
WithCallDepth(depth int) LogSink
}
// CallStackHelperLogSink represents a Logger that knows how to climb
// CallStackHelperLogSink represents a LogSink that knows how to climb
// the call stack to identify the original call site and can skip
// intermediate helper functions if they mark themselves as
// helper. Go's testing package uses that approach.

2
vendor/github.com/go-logr/zapr/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,2 @@
*~
*.swp

201
vendor/github.com/go-logr/zapr/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
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.

70
vendor/github.com/go-logr/zapr/README.md generated vendored Normal file
View File

@@ -0,0 +1,70 @@
Zapr :zap:
==========
A [logr](https://github.com/go-logr/logr) implementation using
[Zap](https://github.com/uber-go/zap).
Usage
-----
```go
import (
"fmt"
"go.uber.org/zap"
"github.com/go-logr/logr"
"github.com/go-logr/zapr"
)
func main() {
var log logr.Logger
zapLog, err := zap.NewDevelopment()
if err != nil {
panic(fmt.Sprintf("who watches the watchmen (%v)?", err))
}
log = zapr.NewLogger(zapLog)
log.Info("Logr in action!", "the answer", 42)
}
```
Increasing Verbosity
--------------------
Zap uses semantically named levels for logging (`DebugLevel`, `InfoLevel`,
`WarningLevel`, ...). Logr uses arbitrary numeric levels. By default logr's
`V(0)` is zap's `InfoLevel` and `V(1)` is zap's `DebugLevel` (which is
numerically -1). Zap does not have named levels that are more verbose than
`DebugLevel`, but it's possible to fake it.
As of zap v1.19.0 you can do something like the following in your setup code:
```go
zc := zap.NewProductionConfig()
zc.Level = zap.NewAtomicLevelAt(zapcore.Level(-2))
z, err := zc.Build()
if err != nil {
// ...
}
log := zapr.NewLogger(z)
```
Zap's levels get more verbose as the number gets smaller and more important and
the number gets larger (`DebugLevel` is -1, `InfoLevel` is 0, `WarnLevel` is 1,
and so on).
The `-2` in the above snippet means that `log.V(2).Info()` calls will be active.
`-3` would enable `log.V(3).Info()`, etc. Note that zap's levels are `int8`
which means the most verbose level you can give it is -128. The zapr
implementation will cap `V()` levels greater than 127 to 127, so setting the
zap level to -128 really means "activate all logs".
Implementation Details
----------------------
For the most part, concepts in Zap correspond directly with those in logr.
Unlike Zap, all fields *must* be in the form of sugared fields --
it's illegal to pass a strongly-typed Zap field in a key position to any
of the logging methods (`Log`, `Error`).

Some files were not shown because too many files have changed in this diff Show More