v20230828patchmerge
into V20230912
8 months ago
@@ -1,9 +1,8 @@ | |||
module code.gitea.io/gitea | |||
go 1.14 | |||
go 1.18 | |||
require ( | |||
cloud.google.com/go v0.45.0 // indirect | |||
gitea.com/jolheiser/gitea-vet v0.1.0 | |||
gitea.com/lunny/levelqueue v0.3.0 | |||
gitea.com/macaron/binding v0.0.0-20190822013154-a5f53841ed2b | |||
@@ -21,40 +20,26 @@ require ( | |||
github.com/BurntSushi/toml v0.3.1 | |||
github.com/PuerkitoBio/goquery v1.5.0 | |||
github.com/RichardKnop/machinery v1.6.9 | |||
github.com/RoaringBitmap/roaring v0.4.23 // indirect | |||
github.com/alecthomas/chroma v0.10.0 | |||
github.com/alibabacloud-go/darabonba-openapi v0.1.18 | |||
github.com/alibabacloud-go/dysmsapi-20170525/v2 v2.0.9 | |||
github.com/alibabacloud-go/tea v1.1.17 | |||
github.com/alibabacloud-go/tea-utils v1.4.3 | |||
github.com/alibabacloud-go/tea-xml v1.1.2 // indirect | |||
github.com/bgentry/speakeasy v0.1.0 // indirect | |||
github.com/blevesearch/bleve v1.0.7 | |||
github.com/clbanning/mxj/v2 v2.5.5 // indirect | |||
github.com/couchbase/gomemcached v0.0.0-20191004160342-7b5da2ec40b2 // indirect | |||
github.com/cznic/b v0.0.0-20181122101859-a26611c4d92d // indirect | |||
github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 // indirect | |||
github.com/cznic/strutil v0.0.0-20181122101858-275e90344537 // indirect | |||
github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc | |||
github.com/dgrijalva/jwt-go v3.2.0+incompatible | |||
github.com/disintegration/imaging v1.6.2 | |||
github.com/dustin/go-humanize v1.0.0 | |||
github.com/editorconfig/editorconfig-core-go/v2 v2.1.1 | |||
github.com/elliotchance/orderedmap v1.4.0 | |||
github.com/emirpasic/gods v1.12.0 | |||
github.com/emirpasic/gods v1.18.1 | |||
github.com/ethantkoenig/rupture v0.0.0-20180203182544-0a76f03a811a | |||
github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 // indirect | |||
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 // indirect | |||
github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 // indirect | |||
github.com/gliderlabs/ssh v0.2.2 | |||
github.com/glycerine/go-unsnap-stream v0.0.0-20190901134440-81cf024a9e0a // indirect | |||
github.com/gliderlabs/ssh v0.3.5 | |||
github.com/go-enry/go-enry/v2 v2.3.0 | |||
github.com/go-git/go-billy/v5 v5.0.0 | |||
github.com/go-git/go-git/v5 v5.0.0 | |||
github.com/go-git/go-billy/v5 v5.5.0 | |||
github.com/go-git/go-git/v5 v5.7.0 | |||
github.com/go-http-utils/headers v0.0.0-20181008091004-fed159eddc2a | |||
github.com/go-ini/ini v1.56.0 // indirect | |||
github.com/go-macaron/auth v0.0.0-20161228062157-884c0e6c9b92 | |||
github.com/go-openapi/jsonreference v0.19.3 // indirect | |||
github.com/go-redis/redis v6.15.2+incompatible | |||
github.com/go-resty/resty/v2 v2.3.0 | |||
github.com/go-sql-driver/mysql v1.4.1 | |||
@@ -62,30 +47,22 @@ require ( | |||
github.com/gobwas/glob v0.2.3 | |||
github.com/gogs/chardet v0.0.0-20191104214054-4b6791f73a28 | |||
github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14 | |||
github.com/golang/mock v1.6.0 // indirect | |||
github.com/golang/protobuf v1.4.1 // indirect | |||
github.com/gomodule/redigo v2.0.0+incompatible | |||
github.com/google/go-github/v24 v24.0.1 | |||
github.com/google/uuid v1.1.1 | |||
github.com/gorilla/context v1.1.1 | |||
github.com/gorilla/websocket v1.4.0 | |||
github.com/hashicorp/go-retryablehttp v0.6.6 // indirect | |||
github.com/huandu/xstrings v1.3.0 | |||
github.com/issue9/assert v1.3.2 // indirect | |||
github.com/issue9/identicon v1.0.1 | |||
github.com/jaytaylor/html2text v0.0.0-20160923191438-8fb95d837f7d | |||
github.com/jmhodges/levigo v1.0.0 // indirect | |||
github.com/joho/godotenv v1.3.0 // indirect | |||
github.com/kballard/go-shellquote v0.0.0-20170619183022-cd60e84ee657 | |||
github.com/keybase/go-crypto v0.0.0-20200123153347-de78d2cb44f4 | |||
github.com/klauspost/compress v1.10.2 | |||
github.com/lafriks/xormstore v1.3.2 | |||
github.com/lib/pq v1.2.0 | |||
github.com/lunny/dingtalk_webhook v0.0.0-20171025031554-e3534c89ef96 | |||
github.com/mailru/easyjson v0.7.0 // indirect | |||
github.com/markbates/goth v1.61.2 | |||
github.com/mattn/go-isatty v0.0.11 | |||
github.com/mattn/go-oci8 v0.0.0-20190320171441-14ba190cf52d // indirect | |||
github.com/mattn/go-sqlite3 v1.11.0 | |||
github.com/mcuadros/go-version v0.0.0-20190308113854-92cdf37c5b75 | |||
github.com/mgechev/dots v0.0.0-20190921121421-c36f7dcfbb81 | |||
@@ -103,17 +80,11 @@ require ( | |||
github.com/pkg/errors v0.9.1 | |||
github.com/pquerna/otp v1.2.0 | |||
github.com/prometheus/client_golang v1.1.0 | |||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 // indirect | |||
github.com/prometheus/procfs v0.0.4 // indirect | |||
github.com/quasoft/websspi v1.0.0 | |||
github.com/remyoudompheng/bigfft v0.0.0-20190321074620-2f0d2b0e0001 // indirect | |||
github.com/satori/go.uuid v1.2.0 | |||
github.com/sergi/go-diff v1.1.0 | |||
github.com/shurcooL/httpfs v0.0.0-20190527155220-6a4d4a70508b // indirect | |||
github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd | |||
github.com/stretchr/testify v1.7.0 | |||
github.com/tecbot/gorocksdb v0.0.0-20181010114359-8752a9433481 // indirect | |||
github.com/tinylib/msgp v1.1.2 // indirect | |||
github.com/tstranex/u2f v1.0.0 | |||
github.com/unknwon/cae v1.0.0 | |||
github.com/unknwon/com v1.0.1 | |||
@@ -125,24 +96,176 @@ require ( | |||
github.com/yuin/goldmark v1.4.13 | |||
github.com/yuin/goldmark-highlighting v0.0.0-20220208100518-594be1970594 | |||
github.com/yuin/goldmark-meta v1.1.0 | |||
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 | |||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 | |||
golang.org/x/crypto v0.13.0 | |||
golang.org/x/net v0.15.0 | |||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d | |||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007 | |||
golang.org/x/text v0.3.3 | |||
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1 // indirect | |||
golang.org/x/tools v0.1.1 | |||
google.golang.org/appengine v1.6.5 // indirect | |||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect | |||
gopkg.in/asn1-ber.v1 v1.0.0-20150924051756-4e86f4367175 // indirect | |||
golang.org/x/sys v0.12.0 | |||
golang.org/x/text v0.13.0 | |||
golang.org/x/tools v0.9.3 | |||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df | |||
gopkg.in/ini.v1 v1.56.0 | |||
gopkg.in/ldap.v3 v3.0.2 | |||
gopkg.in/macaron.v1 v1.3.9 // indirect | |||
gopkg.in/testfixtures.v2 v2.5.0 | |||
gopkg.in/yaml.v2 v2.3.0 | |||
gopkg.in/yaml.v2 v2.4.0 | |||
mvdan.cc/xurls/v2 v2.1.0 | |||
strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251 | |||
xorm.io/builder v0.3.7 | |||
xorm.io/xorm v1.0.1 | |||
) | |||
require ( | |||
cloud.google.com/go v0.45.0 // indirect | |||
github.com/Microsoft/go-winio v0.5.2 // indirect | |||
github.com/ProtonMail/go-crypto v0.0.0-20230518184743-7afd39499903 // indirect | |||
github.com/PuerkitoBio/purell v1.1.1 // indirect | |||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect | |||
github.com/RichardKnop/logging v0.0.0-20181101035820-b1d5d44c82d6 // indirect | |||
github.com/RichardKnop/redsync v1.2.0 // indirect | |||
github.com/RoaringBitmap/roaring v0.4.23 // indirect | |||
github.com/acomagu/bufpipe v1.0.4 // indirect | |||
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4 // indirect | |||
github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68 // indirect | |||
github.com/alibabacloud-go/endpoint-util v1.1.0 // indirect | |||
github.com/alibabacloud-go/openapi-util v0.0.11 // indirect | |||
github.com/alibabacloud-go/tea-xml v1.1.2 // indirect | |||
github.com/aliyun/credentials-go v1.1.2 // indirect | |||
github.com/andybalholm/cascadia v1.0.0 // indirect | |||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect | |||
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a // indirect | |||
github.com/aws/aws-sdk-go v1.25.25 // indirect | |||
github.com/aymerick/douceur v0.2.0 // indirect | |||
github.com/beorn7/perks v1.0.1 // indirect | |||
github.com/bgentry/speakeasy v0.1.0 // indirect | |||
github.com/blevesearch/go-porterstemmer v1.0.3 // indirect | |||
github.com/blevesearch/mmap-go v1.0.2 // indirect | |||
github.com/blevesearch/segment v0.9.0 // indirect | |||
github.com/blevesearch/snowballstem v0.9.0 // indirect | |||
github.com/blevesearch/zap/v11 v11.0.7 // indirect | |||
github.com/blevesearch/zap/v12 v12.0.7 // indirect | |||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect | |||
github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668 // indirect | |||
github.com/chris-ramon/douceur v0.2.0 // indirect | |||
github.com/clbanning/mxj/v2 v2.5.5 // indirect | |||
github.com/cloudflare/circl v1.3.3 // indirect | |||
github.com/couchbase/gomemcached v0.0.0-20191004160342-7b5da2ec40b2 // indirect | |||
github.com/couchbase/goutils v0.0.0-20191018232750-b49639060d85 // indirect | |||
github.com/couchbase/vellum v1.0.1 // indirect | |||
github.com/couchbaselabs/go-couchbase v0.0.0-20190708161019-23e7ca2ce2b7 // indirect | |||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d // indirect | |||
github.com/cyphar/filepath-securejoin v0.2.4 // indirect | |||
github.com/cznic/b v0.0.0-20181122101859-a26611c4d92d // indirect | |||
github.com/davecgh/go-spew v1.1.1 // indirect | |||
github.com/dlclark/regexp2 v1.4.0 // indirect | |||
github.com/fatih/color v1.9.0 // indirect | |||
github.com/fatih/structtag v1.2.0 // indirect | |||
github.com/fsnotify/fsnotify v1.4.7 // indirect | |||
github.com/glycerine/go-unsnap-stream v0.0.0-20190901134440-81cf024a9e0a // indirect | |||
github.com/go-enry/go-oniguruma v1.2.0 // indirect | |||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect | |||
github.com/go-ini/ini v1.56.0 // indirect | |||
github.com/go-macaron/inject v0.0.0-20160627170012-d8a0b8677191 // indirect | |||
github.com/go-openapi/analysis v0.19.5 // indirect | |||
github.com/go-openapi/errors v0.19.2 // indirect | |||
github.com/go-openapi/inflect v0.19.0 // indirect | |||
github.com/go-openapi/jsonpointer v0.19.3 // indirect | |||
github.com/go-openapi/jsonreference v0.19.3 // indirect | |||
github.com/go-openapi/loads v0.19.3 // indirect | |||
github.com/go-openapi/runtime v0.19.5 // indirect | |||
github.com/go-openapi/spec v0.19.3 // indirect | |||
github.com/go-openapi/strfmt v0.19.3 // indirect | |||
github.com/go-openapi/swag v0.19.5 // indirect | |||
github.com/go-openapi/validate v0.19.3 // indirect | |||
github.com/go-stack/stack v1.8.0 // indirect | |||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe // indirect | |||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect | |||
github.com/golang/protobuf v1.3.2 // indirect | |||
github.com/golang/snappy v0.0.1 // indirect | |||
github.com/google/go-querystring v1.0.0 // indirect | |||
github.com/googleapis/gax-go/v2 v2.0.5 // indirect | |||
github.com/gorilla/css v1.0.0 // indirect | |||
github.com/gorilla/handlers v1.4.2 // indirect | |||
github.com/gorilla/mux v1.6.2 // indirect | |||
github.com/gorilla/securecookie v1.1.1 // indirect | |||
github.com/gorilla/sessions v1.2.0 // indirect | |||
github.com/hashicorp/go-cleanhttp v0.5.1 // indirect | |||
github.com/hashicorp/go-retryablehttp v0.6.6 // indirect | |||
github.com/hashicorp/hcl v1.0.0 // indirect | |||
github.com/imdario/mergo v0.3.15 // indirect | |||
github.com/issue9/assert v1.3.2 // indirect | |||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect | |||
github.com/jessevdk/go-flags v1.5.0 // indirect | |||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af // indirect | |||
github.com/jmhodges/levigo v1.0.0 // indirect | |||
github.com/joho/godotenv v1.3.0 // indirect | |||
github.com/json-iterator/go v1.1.10 // indirect | |||
github.com/kelseyhightower/envconfig v1.3.0 // indirect | |||
github.com/kevinburke/ssh_config v1.2.0 // indirect | |||
github.com/klauspost/cpuid v1.2.3 // indirect | |||
github.com/kr/pretty v0.3.1 // indirect | |||
github.com/kr/text v0.2.0 // indirect | |||
github.com/lunny/log v0.0.0-20160921050905-7887c61bf0de // indirect | |||
github.com/lunny/nodb v0.0.0-20160621015157-fc1ef06ad4af // indirect | |||
github.com/magiconair/properties v1.8.1 // indirect | |||
github.com/mailru/easyjson v0.7.0 // indirect | |||
github.com/mattn/go-colorable v0.1.4 // indirect | |||
github.com/mattn/go-oci8 v0.0.0-20190320171441-14ba190cf52d // indirect | |||
github.com/mattn/go-runewidth v0.0.7 // indirect | |||
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect | |||
github.com/minio/md5-simd v1.1.0 // indirect | |||
github.com/minio/sha256-simd v0.1.1 // indirect | |||
github.com/mitchellh/mapstructure v1.1.2 // indirect | |||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect | |||
github.com/modern-go/reflect2 v1.0.1 // indirect | |||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect | |||
github.com/mrjones/oauth v0.0.0-20180629183705-f4e24b6d100c // indirect | |||
github.com/mschoch/smat v0.2.0 // indirect | |||
github.com/olekukonko/tablewriter v0.0.4 // indirect | |||
github.com/opentracing/opentracing-go v1.1.0 // indirect | |||
github.com/pelletier/go-toml v1.4.0 // indirect | |||
github.com/philhofer/fwd v1.0.0 // indirect | |||
github.com/pjbgf/sha1cd v0.3.0 // indirect | |||
github.com/pmezard/go-difflib v1.0.0 // indirect | |||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 // indirect | |||
github.com/prometheus/common v0.6.0 // indirect | |||
github.com/prometheus/procfs v0.0.4 // indirect | |||
github.com/rogpeppe/go-internal v1.11.0 // indirect | |||
github.com/russross/blackfriday/v2 v2.0.1 // indirect | |||
github.com/shurcooL/httpfs v0.0.0-20190527155220-6a4d4a70508b // indirect | |||
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect | |||
github.com/siddontang/go-snappy v0.0.0-20140704025258-d8f7bb82a96d // indirect | |||
github.com/skeema/knownhosts v1.1.1 // indirect | |||
github.com/spf13/afero v1.2.2 // indirect | |||
github.com/spf13/cast v1.3.0 // indirect | |||
github.com/spf13/jwalterweatherman v1.1.0 // indirect | |||
github.com/spf13/pflag v1.0.3 // indirect | |||
github.com/spf13/viper v1.4.0 // indirect | |||
github.com/steveyen/gtreap v0.1.0 // indirect | |||
github.com/streadway/amqp v0.0.0-20190214183023-884228600bc9 // indirect | |||
github.com/syndtr/goleveldb v1.0.0 // indirect | |||
github.com/tecbot/gorocksdb v0.0.0-20181010114359-8752a9433481 // indirect | |||
github.com/tinylib/msgp v1.1.2 // indirect | |||
github.com/tjfoc/gmsm v1.3.2 // indirect | |||
github.com/toqueteos/trie v1.0.0 // indirect | |||
github.com/toqueteos/webbrowser v1.2.0 // indirect | |||
github.com/willf/bitset v1.1.10 // indirect | |||
github.com/xanzy/ssh-agent v0.3.3 // indirect | |||
github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c // indirect | |||
github.com/xdg/stringprep v1.0.0 // indirect | |||
go.etcd.io/bbolt v1.3.4 // indirect | |||
go.mongodb.org/mongo-driver v1.1.1 // indirect | |||
go.opencensus.io v0.22.1 // indirect | |||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8 // indirect | |||
golang.org/x/mod v0.10.0 // indirect | |||
golang.org/x/sync v0.2.0 // indirect | |||
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1 // indirect | |||
google.golang.org/api v0.9.0 // indirect | |||
google.golang.org/appengine v1.6.5 // indirect | |||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 // indirect | |||
google.golang.org/grpc v1.21.1 // indirect | |||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect | |||
gopkg.in/asn1-ber.v1 v1.0.0-20150924051756-4e86f4367175 // indirect | |||
gopkg.in/macaron.v1 v1.3.9 // indirect | |||
gopkg.in/toqueteos/substring.v1 v1.0.2 // indirect | |||
gopkg.in/warnings.v0 v0.1.2 // indirect | |||
gopkg.in/yaml.v3 v3.0.1 // indirect | |||
) |
@@ -54,7 +54,11 @@ github.com/360EntSecGroup-Skylar/excelize/v2 v2.0.2/go.mod h1:EfRHD2k+Kd7ijnqlwO | |||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= | |||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= | |||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= | |||
github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA= | |||
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= | |||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= | |||
github.com/ProtonMail/go-crypto v0.0.0-20230518184743-7afd39499903 h1:ZK3C5DtzV2nVAQTx5S5jQvMeDqWtD1By5mOoyY/xJek= | |||
github.com/ProtonMail/go-crypto v0.0.0-20230518184743-7afd39499903/go.mod h1:8TI4H3IbrackdNgv+92dI+rhpCaLqM0IfpgCgenFvRE= | |||
github.com/PuerkitoBio/goquery v1.5.0 h1:uGvmFXOA73IKluu/F84Xd1tt/z07GYm8X49XKHP7EJk= | |||
github.com/PuerkitoBio/goquery v1.5.0/go.mod h1:qD2PgZ9lccMbQlc7eEOjaeRlFQON7xY8kdmcsrnKqMg= | |||
github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= | |||
@@ -74,8 +78,8 @@ github.com/RoaringBitmap/roaring v0.4.23/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06 | |||
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= | |||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= | |||
github.com/Unknwon/com v0.0.0-20190321035513-0fed4efef755/go.mod h1:voKvFVpXBJxdIPeqjoJuLK+UVcRlo/JLjeToGxPYu68= | |||
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs= | |||
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= | |||
github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ= | |||
github.com/acomagu/bufpipe v1.0.4/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= | |||
github.com/alecthomas/chroma v0.10.0 h1:7XDcGkCQopCNKjZHfYrNLraA+M7e0fMiJ/Mfikbfjek= | |||
github.com/alecthomas/chroma v0.10.0/go.mod h1:jtJATyUxlIORhUOFNA9NZDWGAQ8wpxQQqNSB4rjA/1s= | |||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= | |||
@@ -111,12 +115,12 @@ github.com/aliyun/credentials-go v1.1.2 h1:qU1vwGIBb3UJ8BwunHDRFtAhS6jnQLnde/yk0 | |||
github.com/aliyun/credentials-go v1.1.2/go.mod h1:ozcZaMR5kLM7pwtCMEpVmQ242suV6qTJya2bDq4X1Tw= | |||
github.com/andybalholm/cascadia v1.0.0 h1:hOCXnnZ5A+3eVDX8pvgl4kofXv2ELss0bKcqRySc45o= | |||
github.com/andybalholm/cascadia v1.0.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= | |||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA= | |||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= | |||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= | |||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= | |||
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= | |||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= | |||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= | |||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= | |||
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= | |||
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA= | |||
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= | |||
@@ -153,12 +157,16 @@ github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBT | |||
github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60= | |||
github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668 h1:U/lr3Dgy4WK+hNk4tyD+nuGjpVLPEHuJSFXMw11/HPA= | |||
github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= | |||
github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= | |||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= | |||
github.com/chris-ramon/douceur v0.2.0 h1:IDMEdxlEUUBYBKE4z/mJnFyVXox+MjuEVDJNN27glkU= | |||
github.com/chris-ramon/douceur v0.2.0/go.mod h1:wDW5xjJdeoMm1mRt4sD4c/LbF/mWdEpRXQKjTR8nIBE= | |||
github.com/clbanning/mxj/v2 v2.5.5 h1:oT81vUeEiQQ/DcHbzSytRngP6Ky9O+L+0Bw0zSJag9E= | |||
github.com/clbanning/mxj/v2 v2.5.5/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= | |||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= | |||
github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I= | |||
github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs= | |||
github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= | |||
github.com/corbym/gocrest v1.0.3 h1:gwEdq6RkTmq+09CTuM29DfKOCtZ7G7bcyxs3IZ6EVdU= | |||
github.com/corbym/gocrest v1.0.3/go.mod h1:maVFL5lbdS2PgfOQgGRWDYTeunSWQeiEgoNdTABShCs= | |||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= | |||
@@ -181,18 +189,15 @@ github.com/couchbase/vellum v1.0.1 h1:qrj9ohvZedvc51S5KzPfJ6P6z0Vqzv7Lx7k3mVc2WO | |||
github.com/couchbase/vellum v1.0.1/go.mod h1:FcwrEivFpNi24R3jLOs3n+fs5RnuQnQqCLBJ1uAg1W4= | |||
github.com/couchbaselabs/go-couchbase v0.0.0-20190708161019-23e7ca2ce2b7 h1:1XjEY/gnjQ+AfXef2U6dxCquhiRzkEpxZuWqs+QxTL8= | |||
github.com/couchbaselabs/go-couchbase v0.0.0-20190708161019-23e7ca2ce2b7/go.mod h1:mby/05p8HE5yHEAKiIH/555NoblMs7PtW6NrYshDruc= | |||
github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk= | |||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= | |||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= | |||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= | |||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= | |||
github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY= | |||
github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= | |||
github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= | |||
github.com/cznic/b v0.0.0-20181122101859-a26611c4d92d h1:SwD98825d6bdB+pEuTxWOXiSjBrHdOl/UVp75eI7JT8= | |||
github.com/cznic/b v0.0.0-20181122101859-a26611c4d92d/go.mod h1:URriBxXwVq5ijiJ12C7iIZqlA69nTlI+LgI6/pwftG8= | |||
github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 h1:iwZdTE0PVqJCos1vaoKsclOGD3ADKpshg3SRtYBbwso= | |||
github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM= | |||
github.com/cznic/strutil v0.0.0-20181122101858-275e90344537 h1:MZRmHqDBd0vxNwenEbKSQqRVT24d3C05ft8kduSwlqM= | |||
github.com/cznic/strutil v0.0.0-20181122101858-275e90344537/go.mod h1:AHHPPPXTw0h6pVabbcbyGRK1DckRn7r/STdZEeIDzZc= | |||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | |||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | |||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | |||
@@ -217,23 +222,17 @@ github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFP | |||
github.com/editorconfig/editorconfig-core-go/v2 v2.1.1 h1:mhPg/0hGebcpiiQLqJD2PWWyoHRLEdZ3sXKaEvT1EQU= | |||
github.com/editorconfig/editorconfig-core-go/v2 v2.1.1/go.mod h1:/LuhWJiQ9Gvo1DhVpa4ssm5qeg8rrztdtI7j/iCie2k= | |||
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= | |||
github.com/elazarl/goproxy v0.0.0-20221015165544-a0805db90819 h1:RIB4cRk+lBqKK3Oy0r2gRX4ui7tuhiZq2SuTtTCi0/0= | |||
github.com/elliotchance/orderedmap v1.4.0 h1:wZtfeEONCbx6in1CZyE6bELEt/vFayMvsxqI5SgsR+A= | |||
github.com/elliotchance/orderedmap v1.4.0/go.mod h1:wsDwEaX5jEoyhbs7x93zk2H/qv0zwuhg4inXhDkYqys= | |||
github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= | |||
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= | |||
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= | |||
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= | |||
github.com/ethantkoenig/rupture v0.0.0-20180203182544-0a76f03a811a h1:M1bRpaZAn4GSsqu3hdK2R8H0AH9O6vqCTCbm2oAFGfE= | |||
github.com/ethantkoenig/rupture v0.0.0-20180203182544-0a76f03a811a/go.mod h1:MkKY/CB98aVE4VxO63X5vTQKUgcn+3XP15LMASe3lYs= | |||
github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 h1:0JZ+dUmQeA8IIVUMzysrX4/AKuQwWhV2dYQuPZdvdSQ= | |||
github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= | |||
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A= | |||
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg= | |||
github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 h1:E2s37DuLxFhQDg5gKsWoLBOB0n+ZW8s599zru8FJ2/Y= | |||
github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0= | |||
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= | |||
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= | |||
github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4= | |||
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= | |||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ= | |||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= | |||
github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= | |||
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= | |||
@@ -241,8 +240,8 @@ github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV | |||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= | |||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= | |||
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= | |||
github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0= | |||
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= | |||
github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY= | |||
github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4= | |||
github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= | |||
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= | |||
github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= | |||
@@ -254,14 +253,13 @@ github.com/go-enry/go-enry/v2 v2.3.0 h1:o8KwgY6uSplysrIpj+Y42J/xGPp90ogVpxE2Z3s8 | |||
github.com/go-enry/go-enry/v2 v2.3.0/go.mod h1:+xFJwbqWi15bvqFHb2ELUWVRKFQtwB61+sDrkvvxxGI= | |||
github.com/go-enry/go-oniguruma v1.2.0 h1:oBO9XC1IDT9+AoWW5oFsa/7gFeOPacEqDbyXZKWXuDs= | |||
github.com/go-enry/go-oniguruma v1.2.0/go.mod h1:bWDhYP+S6xZQgiRL7wlTScFYBe023B6ilRZbCAD5Hf4= | |||
github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= | |||
github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= | |||
github.com/go-git/go-billy/v5 v5.0.0 h1:7NQHvd9FVid8VL4qVUMm8XifBK+2xCoZ2lSk0agRrHM= | |||
github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= | |||
github.com/go-git/go-git-fixtures/v4 v4.0.1 h1:q+IFMfLx200Q3scvt2hN79JsEzy4AmBTp/pqnefH+Bc= | |||
github.com/go-git/go-git-fixtures/v4 v4.0.1/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw= | |||
github.com/go-git/go-git/v5 v5.0.0 h1:k5RWPm4iJwYtfWoxIJy4wJX9ON7ihPeZZYC1fLYDnpg= | |||
github.com/go-git/go-git/v5 v5.0.0/go.mod h1:oYD8y9kWsGINPFJoLdaScGCN6dlKg23blmClfZwtUVA= | |||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= | |||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= | |||
github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU= | |||
github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow= | |||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20230305113008-0c11038e723f h1:Pz0DHeFij3XFhoBRGUDPzSJ+w2UcK5/0JvF8DRI58r8= | |||
github.com/go-git/go-git/v5 v5.7.0 h1:t9AudWVLmqzlo+4bqdf7GY+46SUuRsx59SboFxkq2aE= | |||
github.com/go-git/go-git/v5 v5.7.0/go.mod h1:coJHKEOk5kUClpsNlXrUvPrDxY3w3gjHvhcZd8Fodw8= | |||
github.com/go-http-utils/headers v0.0.0-20181008091004-fed159eddc2a h1:v6zMvHuY9yue4+QkG/HQ/W67wvtQmWJ4SDo9aK/GIno= | |||
github.com/go-http-utils/headers v0.0.0-20181008091004-fed159eddc2a/go.mod h1:I79BieaU4fxrw4LMXby6q5OS9XnoR9UIKLOzDFjUmuw= | |||
github.com/go-ini/ini v1.56.0 h1:6HjxSjqdmgnujDPhlzR4a44lxK3w03WPN8te0SoUSeM= | |||
@@ -355,25 +353,17 @@ github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2V | |||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= | |||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= | |||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= | |||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 h1:ZgQEtGgCBiWRM39fZuwSd1LwSqqSW0hOdXCYYDX0R3I= | |||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= | |||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= | |||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= | |||
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= | |||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= | |||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= | |||
github.com/golang/mock v1.3.1 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s= | |||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= | |||
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= | |||
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= | |||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= | |||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= | |||
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= | |||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= | |||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= | |||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= | |||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= | |||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= | |||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= | |||
github.com/golang/protobuf v1.4.1 h1:ZFgWrT+bLgsYPirOnRfKLYJLvssAegOj/hgyMFdJZe0= | |||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= | |||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= | |||
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= | |||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= | |||
@@ -384,9 +374,7 @@ github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ | |||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= | |||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= | |||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= | |||
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= | |||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= | |||
github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY= | |||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= | |||
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= | |||
github.com/google/go-github/v24 v24.0.1 h1:KCt1LjMJEey1qvPXxa9SjaWxwTsCWSq6p2Ju57UR4Q4= | |||
github.com/google/go-github/v24 v24.0.1/go.mod h1:CRqaW1Uns1TCkP0wqTpxYyRxRjxwvKU/XSS44u6X74M= | |||
@@ -400,7 +388,6 @@ github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ | |||
github.com/google/uuid v1.1.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= | |||
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= | |||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= | |||
github.com/googleapis/gax-go v2.0.0+incompatible h1:j0GKcs05QVmm7yesiZq2+9cxHkNK9YM6zKx4D2qucQU= | |||
github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= | |||
github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= | |||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= | |||
@@ -450,6 +437,8 @@ github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= | |||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= | |||
github.com/huandu/xstrings v1.3.0 h1:gvV6jG9dTgFEncxo+AF7PH6MZXi/vZl25owA/8Dg8Wo= | |||
github.com/huandu/xstrings v1.3.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= | |||
github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM= | |||
github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= | |||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= | |||
github.com/issue9/assert v1.3.1/go.mod h1:9Ger+iz8X7r1zMYYwEhh++2wMGWcNN2oVI+zIQXxcio= | |||
github.com/issue9/assert v1.3.2 h1:IaTa37u4m1fUuTH9K9ldO5IONKVDXjLiUO1T9vj0OF0= | |||
@@ -462,8 +451,9 @@ github.com/jaytaylor/html2text v0.0.0-20160923191438-8fb95d837f7d/go.mod h1:CVKl | |||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= | |||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= | |||
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= | |||
github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA= | |||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= | |||
github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc= | |||
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= | |||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM= | |||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= | |||
github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U= | |||
@@ -485,8 +475,8 @@ github.com/kballard/go-shellquote v0.0.0-20170619183022-cd60e84ee657 h1:vE7J1m7c | |||
github.com/kballard/go-shellquote v0.0.0-20170619183022-cd60e84ee657/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= | |||
github.com/kelseyhightower/envconfig v1.3.0 h1:IvRS4f2VcIQy6j4ORGIf9145T/AsUB+oY8LyvN8BXNM= | |||
github.com/kelseyhightower/envconfig v1.3.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= | |||
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v2wtGp9Gmz1Ze3eVRAWJMLokvN3QjdzCHLY= | |||
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= | |||
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= | |||
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= | |||
github.com/keybase/go-crypto v0.0.0-20200123153347-de78d2cb44f4 h1:cTxwSmnaqLoo+4tLukHoB9iqHOu3LmLhRmgUxZo6Vp4= | |||
github.com/keybase/go-crypto v0.0.0-20200123153347-de78d2cb44f4/go.mod h1:ghbZscTyKdM07+Fw3KSi0hcJm+AlEUWj8QLlPtijN/M= | |||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= | |||
@@ -499,8 +489,9 @@ github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgo | |||
github.com/kljensen/snowball v0.6.0/go.mod h1:27N7E8fVU5H68RlUmnWwZCfxgt4POBJfENGMvNRhldw= | |||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= | |||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= | |||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= | |||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= | |||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= | |||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= | |||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= | |||
github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= | |||
github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= | |||
@@ -531,6 +522,8 @@ github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7 | |||
github.com/markbates/going v1.0.0/go.mod h1:I6mnB4BPnEeqo85ynXIx1ZFLLbtiLHNXVgWeFO9OGOA= | |||
github.com/markbates/goth v1.61.2 h1:jDowrUH5qw8KGuQdKwFhLzkXkTYCIPfz3LHADJsiPIs= | |||
github.com/markbates/goth v1.61.2/go.mod h1:qh2QfwZoWRucQ+DR5KVKC6dUGkNCToWh4vS45GIzFsY= | |||
github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A= | |||
github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= | |||
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA= | |||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= | |||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= | |||
@@ -586,7 +579,6 @@ github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJE | |||
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= | |||
github.com/nfnt/resize v0.0.0-20160724205520-891127d8d1b5 h1:BvoENQQU+fZ9uukda/RzCAL/191HHwJA5b13R6diVlY= | |||
github.com/nfnt/resize v0.0.0-20160724205520-891127d8d1b5/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= | |||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= | |||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= | |||
github.com/niklasfasching/go-org v0.1.9 h1:Toz8WMIt+qJb52uYEk1YD/muLuOOmRt1CfkV+bKVMkI= | |||
github.com/niklasfasching/go-org v0.1.9/go.mod h1:AsLD6X7djzRIz4/RFZu8vwRL0VGjUvGZCCH1Nz0VdrU= | |||
@@ -602,8 +594,8 @@ github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W | |||
github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w= | |||
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= | |||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= | |||
github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo= | |||
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= | |||
github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= | |||
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= | |||
github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU= | |||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= | |||
@@ -619,6 +611,9 @@ github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUr | |||
github.com/philhofer/fwd v1.0.0 h1:UbZqGr5Y38ApvM/V/jEljVxwocdweyH+vmYvRPBnbqQ= | |||
github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= | |||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= | |||
github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= | |||
github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI= | |||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= | |||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= | |||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= | |||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= | |||
@@ -664,10 +659,10 @@ github.com/quasoft/websspi v1.0.0 h1:5nDgdM5xSur9s+B5w2xQ5kxf5nUGqgFgU4W0aDLZ8Mw | |||
github.com/quasoft/websspi v1.0.0/go.mod h1:HmVdl939dQ0WIXZhyik+ARdI03M6bQzaSEKcgpFmewk= | |||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= | |||
github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= | |||
github.com/remyoudompheng/bigfft v0.0.0-20190321074620-2f0d2b0e0001 h1:YDeskXpkNDhPdWN3REluVa46HQOVuVkjkd2sWnrABNQ= | |||
github.com/remyoudompheng/bigfft v0.0.0-20190321074620-2f0d2b0e0001/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= | |||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= | |||
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= | |||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= | |||
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= | |||
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= | |||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= | |||
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= | |||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= | |||
@@ -711,6 +706,9 @@ github.com/siddontang/ledisdb v0.0.0-20190202134119-8ceb77e66a92/go.mod h1:mF1Dp | |||
github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA= | |||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= | |||
github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo= | |||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= | |||
github.com/skeema/knownhosts v1.1.1 h1:MTk78x9FPgDFVFkDLTrsnnfCJl7g1C/nnKvePgrIngE= | |||
github.com/skeema/knownhosts v1.1.1/go.mod h1:g4fPeYpque7P0xefxtGzV81ihjC8sX2IqpAoNkjxbMo= | |||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= | |||
github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= | |||
github.com/smartystreets/assertions v1.0.1/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= | |||
@@ -793,8 +791,8 @@ github.com/willf/bitset v1.1.10 h1:NotGKqX0KwQ72NUzqrjZq5ipPNDQex9lo3WpaS8L2sc= | |||
github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= | |||
github.com/xanzy/go-gitlab v0.31.0 h1:+nHztQuCXGSMluKe5Q9IRaPdz6tO8O0gMkQ0vqGpiBk= | |||
github.com/xanzy/go-gitlab v0.31.0/go.mod h1:sPLojNBn68fMUWSxIJtdVVIP8uSBYqesTfDUseX11Ug= | |||
github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70= | |||
github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= | |||
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= | |||
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= | |||
github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c h1:u40Z8hqBAAQyv+vATcGgV0YCnDjqSL7/q/JyPhhJSPk= | |||
github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= | |||
github.com/xdg/stringprep v1.0.0 h1:d9X0esnoa3dFsV0FG35rAT0RIhYFlPq7MiP+DW89La0= | |||
@@ -806,9 +804,7 @@ github.com/yohcop/openid-go v1.0.0/go.mod h1:/408xiwkeItSPJZSTPF7+VtZxPkPrRRpRNK | |||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= | |||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= | |||
github.com/yuin/goldmark v1.1.30/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= | |||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= | |||
github.com/yuin/goldmark v1.4.5/go.mod h1:rmuwmfZ0+bvzB24eSC//bk1R1Zp3hM0OXYv/G2LIilg= | |||
github.com/yuin/goldmark v1.4.6/go.mod h1:rmuwmfZ0+bvzB24eSC//bk1R1Zp3hM0OXYv/G2LIilg= | |||
github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE= | |||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= | |||
github.com/yuin/goldmark-highlighting v0.0.0-20220208100518-594be1970594 h1:yHfZyN55+5dp1wG7wDKv8HQ044moxkyGq12KFFMFDxg= | |||
@@ -853,9 +849,13 @@ golang.org/x/crypto v0.0.0-20190907121410-71b5226ff739/go.mod h1:yigFU9vqHzYiE8U | |||
golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | |||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | |||
golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= | |||
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= | |||
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 h1:cg5LA/zNPRzIXIWSCxQW10Rvpy94aQh3LT/ShoCpkHw= | |||
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= | |||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= | |||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= | |||
golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= | |||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= | |||
golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= | |||
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= | |||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= | |||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= | |||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= | |||
@@ -872,10 +872,10 @@ golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHl | |||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= | |||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= | |||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= | |||
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= | |||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= | |||
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= | |||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= | |||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= | |||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= | |||
golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= | |||
golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= | |||
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | |||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | |||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | |||
@@ -903,12 +903,16 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL | |||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | |||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | |||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | |||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | |||
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= | |||
golang.org/x/net v0.0.0-20200513185701-a91f0712d120 h1:EZ3cVSzKOlJxAd8e8YAJ7no8nNypTxexh/YE/xW3ZEY= | |||
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= | |||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= | |||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= | |||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= | |||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= | |||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= | |||
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= | |||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= | |||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= | |||
golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= | |||
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= | |||
golang.org/x/oauth2 v0.0.0-20180620175406-ef147856a6dd/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= | |||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= | |||
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= | |||
@@ -926,10 +930,11 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ | |||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a h1:WXEvlFVvvGxCJLG6REjsT03iWnKLEWinaScsxF2Vm2o= | |||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= | |||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |||
golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= | |||
golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |||
golang.org/x/sys v0.0.0-20180824143301-4910a1d54f87/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | |||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | |||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | |||
@@ -960,21 +965,39 @@ golang.org/x/sys v0.0.0-20190907184412-d223b2b6db03/go.mod h1:h1NjWce9XRLGQEsW7w | |||
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f h1:mOhmO9WsBaJCNmaZHPtHs9wOcdqdKCjF6OPJlmDM3KI= | |||
golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= | |||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | |||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | |||
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | |||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | |||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | |||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | |||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | |||
golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | |||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | |||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | |||
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= | |||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | |||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= | |||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= | |||
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= | |||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= | |||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= | |||
golang.org/x/term v0.12.0 h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU= | |||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | |||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | |||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= | |||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= | |||
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= | |||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | |||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | |||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= | |||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= | |||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= | |||
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= | |||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= | |||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= | |||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= | |||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= | |||
@@ -1003,16 +1026,13 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn | |||
golang.org/x/tools v0.0.0-20200225230052-807dcd883420/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= | |||
golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= | |||
golang.org/x/tools v0.0.0-20200509030707-2212a7e161a5/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= | |||
golang.org/x/tools v0.0.0-20200515220128-d3bf790afa53 h1:vmsb6v0zUdmUlXfwKaYrHPPRCV0lHq/IwNIf0ASGjyQ= | |||
golang.org/x/tools v0.0.0-20200515220128-d3bf790afa53/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= | |||
golang.org/x/tools v0.1.1 h1:wGiQel/hW0NnEkJUk8lbzkX2gFJU6PFxf1v5OlCfuOs= | |||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= | |||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= | |||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= | |||
golang.org/x/tools v0.9.3 h1:Gn1I8+64MsuTb/HpH+LmQtNas23LhUVr3rYZ0eKuaMM= | |||
golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= | |||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | |||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | |||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= | |||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | |||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= | |||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | |||
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= | |||
google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= | |||
google.golang.org/api v0.0.0-20181220000619-583d854617af/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= | |||
@@ -1058,13 +1078,6 @@ google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiq | |||
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= | |||
google.golang.org/grpc v1.21.1 h1:j6XxA85m/6txkUCHvzlV5f+HBNl/1r5cZ2A/3IEFOO8= | |||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= | |||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= | |||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= | |||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= | |||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= | |||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= | |||
google.golang.org/protobuf v1.22.0 h1:cJv5/xdbk1NnMPR1VP9+HU6gupuG9MLBoH1r6RHZ2MY= | |||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= | |||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= | |||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= | |||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= | |||
@@ -1073,8 +1086,8 @@ gopkg.in/asn1-ber.v1 v1.0.0-20150924051756-4e86f4367175/go.mod h1:cuepJuh7vyXfUy | |||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | |||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | |||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | |||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= | |||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | |||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= | |||
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= | |||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= | |||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE= | |||
@@ -1105,10 +1118,11 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | |||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | |||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | |||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | |||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= | |||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | |||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= | |||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= | |||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= | |||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | |||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= | |||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | |||
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= | |||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= | |||
honnef.co/go/tools v0.0.0-20180920025451-e3ad64cb4ed3/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= | |||
@@ -117,6 +117,7 @@ type mirrorSyncResult struct { | |||
// parseRemoteUpdateOutput detects create, update and delete operations of references from upstream. | |||
func parseRemoteUpdateOutput(output string) []*mirrorSyncResult { | |||
log.Info("runSync ready to parseRemoteUpdateOutput,output=%s", output) | |||
results := make([]*mirrorSyncResult, 0, 3) | |||
lines := strings.Split(output, "\n") | |||
for i := range lines { | |||
@@ -168,6 +169,7 @@ func runSync(m *models.Mirror) ([]*mirrorSyncResult, bool) { | |||
repoPath := m.Repo.RepoPath() | |||
wikiPath := m.Repo.WikiPath() | |||
timeout := time.Duration(setting.Git.Timeout.Mirror) * time.Second | |||
log.Info("try to runSync.repoPath=%s wikiPath=%s timeout=%d repoID=%d", repoPath, wikiPath, timeout, m.RepoID) | |||
gitArgs := []string{"remote", "update"} | |||
if m.EnablePrune { | |||
@@ -179,6 +181,7 @@ func runSync(m *models.Mirror) ([]*mirrorSyncResult, bool) { | |||
if err := git.NewCommand(gitArgs...). | |||
SetDescription(fmt.Sprintf("Mirror.runSync: %s", m.Repo.FullName())). | |||
RunInDirTimeoutPipeline(timeout, repoPath, &stdoutBuilder, &stderrBuilder); err != nil { | |||
log.Error("runSync RunInDirTimeoutPipeline repoID=%d err.%v", m.RepoID, err) | |||
stdout := stdoutBuilder.String() | |||
stderr := stderrBuilder.String() | |||
// sanitize the output, since it may contain the remote address, which may | |||
@@ -196,7 +199,7 @@ func runSync(m *models.Mirror) ([]*mirrorSyncResult, bool) { | |||
return nil, false | |||
} | |||
log.Error("Failed to update mirror repository %v:\nStdout: %s\nStderr: %s\nErr: %v", m.Repo, stdoutMessage, stderrMessage, err) | |||
log.Error("runSync Failed to update mirror repository %v:\nStdout: %s\nStderr: %s\nErr: %v", m.Repo, stdoutMessage, stderrMessage, err) | |||
desc := fmt.Sprintf("Failed to update mirror repository '%s': %s", repoPath, stderrMessage) | |||
if err = models.CreateRepositoryNotice(desc); err != nil { | |||
log.Error("CreateRepositoryNotice: %v", err) | |||
@@ -204,6 +207,7 @@ func runSync(m *models.Mirror) ([]*mirrorSyncResult, bool) { | |||
return nil, false | |||
} | |||
output := stderrBuilder.String() | |||
log.Info("runSync RunInDirTimeoutPipeline success.repoID=%d output=%s", m.RepoID, output) | |||
gitRepo, err := git.OpenRepository(repoPath) | |||
if err != nil { | |||
@@ -212,20 +216,22 @@ func runSync(m *models.Mirror) ([]*mirrorSyncResult, bool) { | |||
} | |||
if err = repo_module.SyncReleasesWithTags(m.Repo, gitRepo); err != nil { | |||
gitRepo.Close() | |||
log.Error("Failed to synchronize tags to releases for repository: %v", err) | |||
log.Error("runSync Failed to synchronize tags to releases for repository: %v", err) | |||
} | |||
gitRepo.Close() | |||
if err := m.Repo.UpdateSize(models.DefaultDBContext()); err != nil { | |||
log.Error("Failed to update size for mirror repository: %v", err) | |||
log.Error("runSync Failed to update size for mirror repository: %v", err) | |||
} | |||
if m.Repo.HasWiki() { | |||
log.Info("runSync Repo has wiki.repoID=%d ", m.RepoID) | |||
stderrBuilder.Reset() | |||
stdoutBuilder.Reset() | |||
if err := git.NewCommand("remote", "update", "--prune"). | |||
SetDescription(fmt.Sprintf("Mirror.runSync Wiki: %s ", m.Repo.FullName())). | |||
RunInDirTimeoutPipeline(timeout, wikiPath, &stdoutBuilder, &stderrBuilder); err != nil { | |||
log.Error("runSync wiki RunInDirTimeoutPipeline repoID=%d err.%v", m.RepoID, err) | |||
stdout := stdoutBuilder.String() | |||
stderr := stderrBuilder.String() | |||
// sanitize the output, since it may contain the remote address, which may | |||
@@ -251,7 +257,7 @@ func runSync(m *models.Mirror) ([]*mirrorSyncResult, bool) { | |||
return nil, false | |||
} | |||
} | |||
log.Info("runSync ready to GetBranches.repoID=%d ", m.RepoID) | |||
branches, _, err := repo_module.GetBranches(m.Repo, 0, 0) | |||
if err != nil { | |||
log.Error("GetBranches: %v", err) | |||
@@ -261,7 +267,7 @@ func runSync(m *models.Mirror) ([]*mirrorSyncResult, bool) { | |||
for i := range branches { | |||
cache.Remove(m.Repo.GetCommitsCountCacheKey(branches[i].Name, true)) | |||
} | |||
log.Info("runSync Remove success.repoID=%d ", m.RepoID) | |||
m.UpdatedUnix = timeutil.TimeStampNow() | |||
return parseRemoteUpdateOutput(output), true | |||
} | |||
@@ -298,16 +304,19 @@ func Password(m *models.Mirror) string { | |||
// Update checks and updates mirror repositories. | |||
func Update(ctx context.Context) error { | |||
log.Trace("Doing: Update") | |||
log.Info("runSync update_mirrors starting") | |||
if err := models.MirrorsIterate(func(idx int, bean interface{}) error { | |||
m := bean.(*models.Mirror) | |||
if m.Repo == nil { | |||
log.Error("Disconnected mirror repository found: %d", m.ID) | |||
log.Error("runSync Disconnected mirror repository found: %d", m.ID) | |||
return nil | |||
} | |||
log.Info("runSync update_mirrors Iterate repoId = %d", m.Repo) | |||
select { | |||
case <-ctx.Done(): | |||
return fmt.Errorf("Aborted") | |||
default: | |||
log.Info("runSync update_mirrors mirrorQueue add repoId = %d", m.Repo) | |||
mirrorQueue.Add(m.RepoID) | |||
return nil | |||
} | |||
@@ -335,7 +344,7 @@ func SyncMirrors(ctx context.Context) { | |||
} | |||
func syncMirror(repoID string) { | |||
log.Trace("SyncMirrors [repo_id: %v]", repoID) | |||
log.Info("runSync SyncMirrors [repo_id: %v]", repoID) | |||
defer func() { | |||
err := recover() | |||
if err == nil { | |||
@@ -355,10 +364,12 @@ func syncMirror(repoID string) { | |||
results, ok := runSync(m) | |||
if !ok { | |||
log.Info("runSync failed.repoID=%d ", m.RepoID) | |||
return | |||
} | |||
m.ScheduleNextUpdate() | |||
log.Info("runSync ready to UpdateMirror.repoID=%d m=%+v", m.RepoID, m) | |||
if err = models.UpdateMirror(m); err != nil { | |||
log.Error("UpdateMirror [%s]: %v", repoID, err) | |||
return | |||
@@ -366,7 +377,7 @@ func syncMirror(repoID string) { | |||
var gitRepo *git.Repository | |||
if len(results) == 0 { | |||
log.Trace("SyncMirrors [repo_id: %d]: no commits fetched", m.RepoID) | |||
log.Info("runSync SyncMirrors [repo_id: %d]: no commits fetched", m.RepoID) | |||
} else { | |||
gitRepo, err = git.OpenRepository(m.Repo.RepoPath()) | |||
if err != nil { | |||
@@ -377,6 +388,7 @@ func syncMirror(repoID string) { | |||
} | |||
for _, result := range results { | |||
log.Info("runSync result in loop.repoID=%d result=%+v", m.RepoID, result) | |||
// Discard GitHub pull requests, i.e. refs/pull/* | |||
if strings.HasPrefix(result.refName, "refs/pull/") { | |||
continue | |||
@@ -419,9 +431,10 @@ func syncMirror(repoID string) { | |||
} | |||
theCommits.CompareURL = m.Repo.ComposeCompareURL(oldCommitID, newCommitID) | |||
log.Info("runSync ready to NotifySyncPushCommits.repoID=%d result=%+v", m.RepoID, result) | |||
notification.NotifySyncPushCommits(m.Repo.MustOwner(), m.Repo, result.refName, oldCommitID, newCommitID, theCommits) | |||
} | |||
log.Info("runSync ready to GetLatestCommitTime.repoID=%d repoPath=%d", m.RepoID, m.Repo.RepoPath()) | |||
// Get latest commit date and update to current repository updated time | |||
commitDate, err := git.GetLatestCommitTime(m.Repo.RepoPath()) | |||
@@ -429,7 +442,7 @@ func syncMirror(repoID string) { | |||
log.Error("GetLatestCommitDate [%d]: %v", m.RepoID, err) | |||
return | |||
} | |||
log.Info("runSync ready to UpdateRepositoryUpdatedTime.repoID=%d commitDate=%d", m.RepoID, commitDate.Unix()) | |||
if err = models.UpdateRepositoryUpdatedTime(m.RepoID, commitDate); err != nil { | |||
log.Error("Update repository 'updated_unix' [%d]: %v", m.RepoID, err) | |||
return | |||
@@ -443,5 +456,6 @@ func InitSyncMirrors() { | |||
// StartToMirror adds repoID to mirror queue | |||
func StartToMirror(repoID int64) { | |||
log.Info("runSync update_mirrors StartToMirror repoId = %d", repoID) | |||
go mirrorQueue.Add(repoID) | |||
} |
@@ -1,5 +0,0 @@ | |||
module gitea.com/jolheiser/gitea-vet | |||
go 1.14 | |||
require golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224 |
@@ -1,20 +0,0 @@ | |||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= | |||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | |||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | |||
golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ= | |||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= | |||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | |||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | |||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | |||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | |||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | |||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= | |||
golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224 h1:azwY/v0y0K4mFHVsg5+UrTgchqALYWpqVo6vL5OmkmI= | |||
golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= | |||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | |||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | |||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= | |||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= |
@@ -1,9 +0,0 @@ | |||
module gitea.com/lunny/levelqueue | |||
require ( | |||
github.com/golang/snappy v0.0.1 // indirect | |||
github.com/stretchr/testify v1.3.0 | |||
github.com/syndtr/goleveldb v1.0.0 | |||
) | |||
go 1.13 |
@@ -1,42 +0,0 @@ | |||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= | |||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | |||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= | |||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= | |||
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= | |||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= | |||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w= | |||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= | |||
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= | |||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= | |||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= | |||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= | |||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= | |||
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= | |||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= | |||
github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU= | |||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= | |||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | |||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | |||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | |||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= | |||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= | |||
github.com/syndtr/goleveldb v0.0.0-20190203031304-2f17a3356c66 h1:AwmkkZT+TucFotNCL+aNJ/0KCMsRtlXN9fs8uoOMSRk= | |||
github.com/syndtr/goleveldb v0.0.0-20190203031304-2f17a3356c66/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= | |||
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= | |||
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= | |||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd h1:nTDtHvHSdCn1m6ITfMRqtOd/9+7a3s8RBNOZ3eYZzJA= | |||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | |||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA= | |||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e h1:o3PsSEY8E4eXWkXrIP9YJALUkVZqzHJT5DOasTyn8Vs= | |||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | |||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= | |||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | |||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= | |||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | |||
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= | |||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= | |||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= | |||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= | |||
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= | |||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
@@ -1,9 +0,0 @@ | |||
module gitea.com/macaron/binding | |||
go 1.11 | |||
require ( | |||
gitea.com/macaron/macaron v1.3.3-0.20190821202302-9646c0587edb | |||
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 | |||
github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e | |||
) |
@@ -1,30 +0,0 @@ | |||
gitea.com/macaron/inject v0.0.0-20190803172902-8375ba841591 h1:UbCTjPcLrNxR9LzKDjQBMT2zoxZuEnca1pZCpgeMuhQ= | |||
gitea.com/macaron/inject v0.0.0-20190803172902-8375ba841591/go.mod h1:h6E4kLao1Yko6DOU6QDnQPcuoNzvbZqzj2mtPcEn1aM= | |||
gitea.com/macaron/macaron v1.3.3-0.20190821202302-9646c0587edb h1:amL0md6orTj1tXY16ANzVU9FmzQB+W7aJwp8pVDbrmA= | |||
gitea.com/macaron/macaron v1.3.3-0.20190821202302-9646c0587edb/go.mod h1:0coI+mSPSwbsyAbOuFllVS38awuk9mevhLD52l50Gjs= | |||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= | |||
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1ks85zJ1lfDGgIiMDuIptTOhJq+zKyg= | |||
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= | |||
github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= | |||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= | |||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= | |||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= | |||
github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304 h1:Jpy1PXuP99tXNrhbq2BaPz9B+jNAvH1JPQQpG/9GCXY= | |||
github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= | |||
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= | |||
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 h1:WN9BUFbdyOsSH/XohnWpXOlq9NBD5sGAB2FciQMUEe8= | |||
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= | |||
github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e h1:GSGeB9EAKY2spCABz6xOX5DbxZEXolK+nBSvmsQwRjM= | |||
github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM= | |||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= | |||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | |||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc= | |||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | |||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | |||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | |||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | |||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | |||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= | |||
gopkg.in/ini.v1 v1.44.0 h1:YRJzTUp0kSYWUVFF5XAbDFfyiqwsl0Vb9R8TVP5eRi0= | |||
gopkg.in/ini.v1 v1.44.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= |
@@ -1,30 +0,0 @@ | |||
module gitea.com/macaron/cache | |||
go 1.11 | |||
require ( | |||
gitea.com/macaron/macaron v1.3.3-0.20190821202302-9646c0587edb | |||
github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668 | |||
github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76 // indirect | |||
github.com/edsrzf/mmap-go v1.0.0 // indirect | |||
github.com/go-redis/redis v6.15.2+incompatible | |||
github.com/go-sql-driver/mysql v1.4.1 | |||
github.com/lib/pq v1.2.0 | |||
github.com/lunny/log v0.0.0-20160921050905-7887c61bf0de // indirect | |||
github.com/lunny/nodb v0.0.0-20160621015157-fc1ef06ad4af | |||
github.com/mattn/go-sqlite3 v1.11.0 // indirect | |||
github.com/onsi/ginkgo v1.8.0 // indirect | |||
github.com/onsi/gomega v1.5.0 // indirect | |||
github.com/pelletier/go-toml v1.4.0 // indirect | |||
github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726 // indirect | |||
github.com/siddontang/go-snappy v0.0.0-20140704025258-d8f7bb82a96d // indirect | |||
github.com/siddontang/ledisdb v0.0.0-20190202134119-8ceb77e66a92 | |||
github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d // indirect | |||
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 | |||
github.com/syndtr/goleveldb v1.0.0 // indirect | |||
github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e | |||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 // indirect | |||
golang.org/x/sys v0.0.0-20190730183949-1393eb018365 // indirect | |||
google.golang.org/appengine v1.6.1 // indirect | |||
gopkg.in/ini.v1 v1.44.2 | |||
) |
@@ -1,106 +0,0 @@ | |||
gitea.com/macaron/inject v0.0.0-20190803172902-8375ba841591 h1:UbCTjPcLrNxR9LzKDjQBMT2zoxZuEnca1pZCpgeMuhQ= | |||
gitea.com/macaron/inject v0.0.0-20190803172902-8375ba841591/go.mod h1:h6E4kLao1Yko6DOU6QDnQPcuoNzvbZqzj2mtPcEn1aM= | |||
gitea.com/macaron/macaron v1.3.3-0.20190821202302-9646c0587edb h1:amL0md6orTj1tXY16ANzVU9FmzQB+W7aJwp8pVDbrmA= | |||
gitea.com/macaron/macaron v1.3.3-0.20190821202302-9646c0587edb/go.mod h1:0coI+mSPSwbsyAbOuFllVS38awuk9mevhLD52l50Gjs= | |||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= | |||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= | |||
github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668 h1:U/lr3Dgy4WK+hNk4tyD+nuGjpVLPEHuJSFXMw11/HPA= | |||
github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= | |||
github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76 h1:Lgdd/Qp96Qj8jqLpq2cI1I1X7BJnu06efS+XkhRoLUQ= | |||
github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY= | |||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | |||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | |||
github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= | |||
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= | |||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= | |||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= | |||
github.com/go-redis/redis v6.15.2+incompatible h1:9SpNVG76gr6InJGxoZ6IuuxaCOQwDAhzyXg+Bs+0Sb4= | |||
github.com/go-redis/redis v6.15.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= | |||
github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= | |||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= | |||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= | |||
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= | |||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= | |||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w= | |||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= | |||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= | |||
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1ks85zJ1lfDGgIiMDuIptTOhJq+zKyg= | |||
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= | |||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= | |||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= | |||
github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= | |||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= | |||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= | |||
github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0= | |||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= | |||
github.com/lunny/log v0.0.0-20160921050905-7887c61bf0de h1:nyxwRdWHAVxpFcDThedEgQ07DbcRc5xgNObtbTp76fk= | |||
github.com/lunny/log v0.0.0-20160921050905-7887c61bf0de/go.mod h1:3q8WtuPQsoRbatJuy3nvq/hRSvuBJrHHr+ybPPiNvHQ= | |||
github.com/lunny/nodb v0.0.0-20160621015157-fc1ef06ad4af h1:UaWHNBdukWrSG3DRvHFR/hyfg681fceqQDYVTBncKfQ= | |||
github.com/lunny/nodb v0.0.0-20160621015157-fc1ef06ad4af/go.mod h1:Cqz6pqow14VObJ7peltM+2n3PWOz7yTrfUuGbVFkzN0= | |||
github.com/mattn/go-sqlite3 v1.11.0 h1:LDdKkqtYlom37fkvqs8rMPFKAMe8+SgjbwZ6ex1/A/Q= | |||
github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= | |||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= | |||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= | |||
github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w= | |||
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= | |||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= | |||
github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo= | |||
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= | |||
github.com/pelletier/go-toml v1.4.0 h1:u3Z1r+oOXJIkxqw34zVhyPgjBsm6X2wn21NWs/HfSeg= | |||
github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo= | |||
github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726 h1:xT+JlYxNGqyT+XcU8iUrN18JYed2TvG9yN5ULG2jATM= | |||
github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw= | |||
github.com/siddontang/go-snappy v0.0.0-20140704025258-d8f7bb82a96d h1:qQWKKOvHN7Q9c6GdmUteCef2F9ubxMpxY1IKwpIKz68= | |||
github.com/siddontang/go-snappy v0.0.0-20140704025258-d8f7bb82a96d/go.mod h1:vq0tzqLRu6TS7Id0wMo2N5QzJoKedVeovOpHjnykSzY= | |||
github.com/siddontang/ledisdb v0.0.0-20190202134119-8ceb77e66a92 h1:qvsJwGToa8rxb42cDRhkbKeX2H5N8BH+s2aUikGt8mI= | |||
github.com/siddontang/ledisdb v0.0.0-20190202134119-8ceb77e66a92/go.mod h1:mF1DpOSOUiJRMR+FDqaqu3EBqrybQtrDDszLUZ6oxPg= | |||
github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d h1:NVwnfyR3rENtlz62bcrkXME3INVUa4lcdGt+opvxExs= | |||
github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA= | |||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= | |||
github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304 h1:Jpy1PXuP99tXNrhbq2BaPz9B+jNAvH1JPQQpG/9GCXY= | |||
github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= | |||
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= | |||
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 h1:WN9BUFbdyOsSH/XohnWpXOlq9NBD5sGAB2FciQMUEe8= | |||
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= | |||
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= | |||
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= | |||
github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e h1:GSGeB9EAKY2spCABz6xOX5DbxZEXolK+nBSvmsQwRjM= | |||
github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM= | |||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | |||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | |||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc= | |||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | |||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | |||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | |||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | |||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= | |||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 h1:Ao/3l156eZf2AW5wK8a7/smtodRU+gha3+BeqJ69lRk= | |||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | |||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | |||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | |||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/sys v0.0.0-20190730183949-1393eb018365 h1:SaXEMXhWzMJThc05vu6uh61Q245r4KaWMrsTedk0FDc= | |||
golang.org/x/sys v0.0.0-20190730183949-1393eb018365/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | |||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= | |||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= | |||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | |||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= | |||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= | |||
google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I= | |||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= | |||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= | |||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | |||
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= | |||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= | |||
gopkg.in/ini.v1 v1.44.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= | |||
gopkg.in/ini.v1 v1.44.2 h1:N6kNUPqiIyxP+s/aINPzRvNpcTVV30qLC0t6ZjZFlUU= | |||
gopkg.in/ini.v1 v1.44.2/go.mod h1:M3Cogqpuv0QCi3ExAY5V4uOt4qb/R3xZubo9m8lK5wg= | |||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= | |||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= | |||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | |||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= | |||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
@@ -1,10 +0,0 @@ | |||
module gitea.com/macaron/captcha | |||
go 1.11 | |||
require ( | |||
gitea.com/macaron/cache v0.0.0-20190822004001-a6e7fee4ee76 | |||
gitea.com/macaron/macaron v1.3.3-0.20190821202302-9646c0587edb | |||
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 | |||
github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e | |||
) |
@@ -1,78 +0,0 @@ | |||
gitea.com/macaron/cache v0.0.0-20190822004001-a6e7fee4ee76 h1:mMsMEg90c5KXQgRWsH8D6GHXfZIW1RAe5S9VYIb12lM= | |||
gitea.com/macaron/cache v0.0.0-20190822004001-a6e7fee4ee76/go.mod h1:NFHb9Of+LUnU86bU20CiXXg6ZlgCJ4XytP14UsHOXFs= | |||
gitea.com/macaron/inject v0.0.0-20190803172902-8375ba841591 h1:UbCTjPcLrNxR9LzKDjQBMT2zoxZuEnca1pZCpgeMuhQ= | |||
gitea.com/macaron/inject v0.0.0-20190803172902-8375ba841591/go.mod h1:h6E4kLao1Yko6DOU6QDnQPcuoNzvbZqzj2mtPcEn1aM= | |||
gitea.com/macaron/macaron v1.3.3-0.20190821202302-9646c0587edb h1:amL0md6orTj1tXY16ANzVU9FmzQB+W7aJwp8pVDbrmA= | |||
gitea.com/macaron/macaron v1.3.3-0.20190821202302-9646c0587edb/go.mod h1:0coI+mSPSwbsyAbOuFllVS38awuk9mevhLD52l50Gjs= | |||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= | |||
github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= | |||
github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY= | |||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | |||
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= | |||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= | |||
github.com/go-redis/redis v6.15.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= | |||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= | |||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= | |||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= | |||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= | |||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= | |||
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1ks85zJ1lfDGgIiMDuIptTOhJq+zKyg= | |||
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= | |||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= | |||
github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= | |||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= | |||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= | |||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= | |||
github.com/lunny/log v0.0.0-20160921050905-7887c61bf0de/go.mod h1:3q8WtuPQsoRbatJuy3nvq/hRSvuBJrHHr+ybPPiNvHQ= | |||
github.com/lunny/nodb v0.0.0-20160621015157-fc1ef06ad4af/go.mod h1:Cqz6pqow14VObJ7peltM+2n3PWOz7yTrfUuGbVFkzN0= | |||
github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= | |||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= | |||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= | |||
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= | |||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= | |||
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= | |||
github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo= | |||
github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw= | |||
github.com/siddontang/go-snappy v0.0.0-20140704025258-d8f7bb82a96d/go.mod h1:vq0tzqLRu6TS7Id0wMo2N5QzJoKedVeovOpHjnykSzY= | |||
github.com/siddontang/ledisdb v0.0.0-20190202134119-8ceb77e66a92/go.mod h1:mF1DpOSOUiJRMR+FDqaqu3EBqrybQtrDDszLUZ6oxPg= | |||
github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA= | |||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= | |||
github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304 h1:Jpy1PXuP99tXNrhbq2BaPz9B+jNAvH1JPQQpG/9GCXY= | |||
github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= | |||
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= | |||
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 h1:WN9BUFbdyOsSH/XohnWpXOlq9NBD5sGAB2FciQMUEe8= | |||
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= | |||
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= | |||
github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e h1:GSGeB9EAKY2spCABz6xOX5DbxZEXolK+nBSvmsQwRjM= | |||
github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM= | |||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | |||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | |||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc= | |||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | |||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | |||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | |||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | |||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= | |||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | |||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | |||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | |||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/sys v0.0.0-20190730183949-1393eb018365/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | |||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= | |||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | |||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= | |||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= | |||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= | |||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | |||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= | |||
gopkg.in/ini.v1 v1.44.0 h1:YRJzTUp0kSYWUVFF5XAbDFfyiqwsl0Vb9R8TVP5eRi0= | |||
gopkg.in/ini.v1 v1.44.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= | |||
gopkg.in/ini.v1 v1.44.2 h1:N6kNUPqiIyxP+s/aINPzRvNpcTVV30qLC0t6ZjZFlUU= | |||
gopkg.in/ini.v1 v1.44.2/go.mod h1:M3Cogqpuv0QCi3ExAY5V4uOt4qb/R3xZubo9m8lK5wg= | |||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= | |||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | |||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
@@ -1,5 +0,0 @@ | |||
module gitea.com/macaron/cors | |||
go 1.11 | |||
require gitea.com/macaron/macaron v1.3.3-0.20190803174002-53e005ff4827 |
@@ -1,31 +0,0 @@ | |||
gitea.com/macaron/inject v0.0.0-20190803172902-8375ba841591 h1:UbCTjPcLrNxR9LzKDjQBMT2zoxZuEnca1pZCpgeMuhQ= | |||
gitea.com/macaron/inject v0.0.0-20190803172902-8375ba841591/go.mod h1:h6E4kLao1Yko6DOU6QDnQPcuoNzvbZqzj2mtPcEn1aM= | |||
gitea.com/macaron/macaron v1.3.3-0.20190803174002-53e005ff4827 h1:/rT4MEFjhdViy2BFWKUwbC0JSNSziEbBCM7q4/B9qgo= | |||
gitea.com/macaron/macaron v1.3.3-0.20190803174002-53e005ff4827/go.mod h1:/rvxMjIkOq4BM8uPUb+VHuU02ZfAO6R4+wD//tiCiRw= | |||
github.com/Unknwon/com v0.0.0-20190321035513-0fed4efef755 h1:1B7wb36fHLSwZfHg6ngZhhtIEHQjiC5H4p7qQGBEffg= | |||
github.com/Unknwon/com v0.0.0-20190321035513-0fed4efef755/go.mod h1:voKvFVpXBJxdIPeqjoJuLK+UVcRlo/JLjeToGxPYu68= | |||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= | |||
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1ks85zJ1lfDGgIiMDuIptTOhJq+zKyg= | |||
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= | |||
github.com/jtolds/gls v4.2.1+incompatible h1:fSuqC+Gmlu6l/ZYAoZzx2pyucC8Xza35fpRVWLVmUEE= | |||
github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= | |||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= | |||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= | |||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= | |||
github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304 h1:Jpy1PXuP99tXNrhbq2BaPz9B+jNAvH1JPQQpG/9GCXY= | |||
github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= | |||
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c h1:Ho+uVpkel/udgjbwB5Lktg9BtvJSh2DT0Hi6LPSyI2w= | |||
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= | |||
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 h1:WN9BUFbdyOsSH/XohnWpXOlq9NBD5sGAB2FciQMUEe8= | |||
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= | |||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | |||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc= | |||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | |||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | |||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | |||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | |||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | |||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= | |||
gopkg.in/ini.v1 v1.44.0 h1:YRJzTUp0kSYWUVFF5XAbDFfyiqwsl0Vb9R8TVP5eRi0= | |||
gopkg.in/ini.v1 v1.44.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= |
@@ -1,12 +0,0 @@ | |||
module gitea.com/macaron/csrf | |||
go 1.11 | |||
require ( | |||
gitea.com/macaron/macaron v1.3.3-0.20190821202302-9646c0587edb | |||
gitea.com/macaron/session v0.0.0-20190821211443-122c47c5f705 | |||
github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c // indirect | |||
github.com/smartystreets/assertions v1.0.1 // indirect | |||
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 | |||
github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e | |||
) |
@@ -1,83 +0,0 @@ | |||
gitea.com/macaron/inject v0.0.0-20190803172902-8375ba841591 h1:UbCTjPcLrNxR9LzKDjQBMT2zoxZuEnca1pZCpgeMuhQ= | |||
gitea.com/macaron/inject v0.0.0-20190803172902-8375ba841591/go.mod h1:h6E4kLao1Yko6DOU6QDnQPcuoNzvbZqzj2mtPcEn1aM= | |||
gitea.com/macaron/macaron v1.3.3-0.20190821202302-9646c0587edb h1:amL0md6orTj1tXY16ANzVU9FmzQB+W7aJwp8pVDbrmA= | |||
gitea.com/macaron/macaron v1.3.3-0.20190821202302-9646c0587edb/go.mod h1:0coI+mSPSwbsyAbOuFllVS38awuk9mevhLD52l50Gjs= | |||
gitea.com/macaron/session v0.0.0-20190821211443-122c47c5f705 h1:mvkQGAlON1Z6Y8pqa/+FpYIskk54mazuECUfZK5oTg0= | |||
gitea.com/macaron/session v0.0.0-20190821211443-122c47c5f705/go.mod h1:1ujH0jD6Ca4iK9NL0Q2a7fG2chvXx5hVa7hBfABwpkA= | |||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= | |||
github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= | |||
github.com/couchbase/gomemcached v0.0.0-20190515232915-c4b4ca0eb21d/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c= | |||
github.com/couchbase/goutils v0.0.0-20190315194238-f9d42b11473b/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs= | |||
github.com/couchbaselabs/go-couchbase v0.0.0-20190708161019-23e7ca2ce2b7/go.mod h1:mby/05p8HE5yHEAKiIH/555NoblMs7PtW6NrYshDruc= | |||
github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY= | |||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | |||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | |||
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= | |||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= | |||
github.com/go-redis/redis v6.15.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= | |||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= | |||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= | |||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= | |||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= | |||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= | |||
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= | |||
github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c h1:7lF+Vz0LqiRidnzC1Oq86fpX1q/iEv2KJdrCtttYjT4= | |||
github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= | |||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= | |||
github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= | |||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= | |||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= | |||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= | |||
github.com/lunny/log v0.0.0-20160921050905-7887c61bf0de/go.mod h1:3q8WtuPQsoRbatJuy3nvq/hRSvuBJrHHr+ybPPiNvHQ= | |||
github.com/lunny/nodb v0.0.0-20160621015157-fc1ef06ad4af/go.mod h1:Cqz6pqow14VObJ7peltM+2n3PWOz7yTrfUuGbVFkzN0= | |||
github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= | |||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= | |||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= | |||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= | |||
github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo= | |||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= | |||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | |||
github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw= | |||
github.com/siddontang/go-snappy v0.0.0-20140704025258-d8f7bb82a96d/go.mod h1:vq0tzqLRu6TS7Id0wMo2N5QzJoKedVeovOpHjnykSzY= | |||
github.com/siddontang/ledisdb v0.0.0-20190202134119-8ceb77e66a92/go.mod h1:mF1DpOSOUiJRMR+FDqaqu3EBqrybQtrDDszLUZ6oxPg= | |||
github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA= | |||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= | |||
github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= | |||
github.com/smartystreets/assertions v1.0.1 h1:voD4ITNjPL5jjBfgR/r8fPIIBrliWrWHeiJApdr3r4w= | |||
github.com/smartystreets/assertions v1.0.1/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= | |||
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= | |||
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 h1:WN9BUFbdyOsSH/XohnWpXOlq9NBD5sGAB2FciQMUEe8= | |||
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= | |||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | |||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= | |||
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= | |||
github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e h1:GSGeB9EAKY2spCABz6xOX5DbxZEXolK+nBSvmsQwRjM= | |||
github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM= | |||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | |||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | |||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc= | |||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | |||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | |||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | |||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | |||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= | |||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | |||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | |||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | |||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | |||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= | |||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | |||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= | |||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= | |||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= | |||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | |||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= | |||
gopkg.in/ini.v1 v1.44.0 h1:YRJzTUp0kSYWUVFF5XAbDFfyiqwsl0Vb9R8TVP5eRi0= | |||
gopkg.in/ini.v1 v1.44.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= | |||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= | |||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | |||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
@@ -1,9 +0,0 @@ | |||
module gitea.com/macaron/gzip | |||
go 1.12 | |||
require ( | |||
gitea.com/macaron/macaron v1.3.3-0.20190821202302-9646c0587edb | |||
github.com/klauspost/compress v1.9.2 | |||
github.com/stretchr/testify v1.4.0 | |||
) |
@@ -1,42 +0,0 @@ | |||
gitea.com/macaron/inject v0.0.0-20190803172902-8375ba841591 h1:UbCTjPcLrNxR9LzKDjQBMT2zoxZuEnca1pZCpgeMuhQ= | |||
gitea.com/macaron/inject v0.0.0-20190803172902-8375ba841591/go.mod h1:h6E4kLao1Yko6DOU6QDnQPcuoNzvbZqzj2mtPcEn1aM= | |||
gitea.com/macaron/macaron v1.3.3-0.20190821202302-9646c0587edb h1:amL0md6orTj1tXY16ANzVU9FmzQB+W7aJwp8pVDbrmA= | |||
gitea.com/macaron/macaron v1.3.3-0.20190821202302-9646c0587edb/go.mod h1:0coI+mSPSwbsyAbOuFllVS38awuk9mevhLD52l50Gjs= | |||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= | |||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | |||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= | |||
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1ks85zJ1lfDGgIiMDuIptTOhJq+zKyg= | |||
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= | |||
github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= | |||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= | |||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= | |||
github.com/klauspost/compress v1.9.2 h1:LfVyl+ZlLlLDeQ/d2AqfGIIH4qEDu0Ed2S5GyhCWIWY= | |||
github.com/klauspost/compress v1.9.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= | |||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | |||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | |||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= | |||
github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304 h1:Jpy1PXuP99tXNrhbq2BaPz9B+jNAvH1JPQQpG/9GCXY= | |||
github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= | |||
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= | |||
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 h1:WN9BUFbdyOsSH/XohnWpXOlq9NBD5sGAB2FciQMUEe8= | |||
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= | |||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | |||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= | |||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= | |||
github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e h1:GSGeB9EAKY2spCABz6xOX5DbxZEXolK+nBSvmsQwRjM= | |||
github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM= | |||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | |||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc= | |||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | |||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | |||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | |||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | |||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | |||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= | |||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= | |||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | |||
gopkg.in/ini.v1 v1.44.0 h1:YRJzTUp0kSYWUVFF5XAbDFfyiqwsl0Vb9R8TVP5eRi0= | |||
gopkg.in/ini.v1 v1.44.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= | |||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= | |||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
@@ -1,11 +0,0 @@ | |||
module gitea.com/macaron/i18n | |||
go 1.11 | |||
require ( | |||
gitea.com/macaron/macaron v1.3.3-0.20190821202302-9646c0587edb | |||
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 | |||
github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e | |||
github.com/unknwon/i18n v0.0.0-20190805065654-5c6446a380b6 | |||
golang.org/x/text v0.3.2 | |||
) |
@@ -1,35 +0,0 @@ | |||
gitea.com/macaron/inject v0.0.0-20190803172902-8375ba841591 h1:UbCTjPcLrNxR9LzKDjQBMT2zoxZuEnca1pZCpgeMuhQ= | |||
gitea.com/macaron/inject v0.0.0-20190803172902-8375ba841591/go.mod h1:h6E4kLao1Yko6DOU6QDnQPcuoNzvbZqzj2mtPcEn1aM= | |||
gitea.com/macaron/macaron v1.3.3-0.20190821202302-9646c0587edb h1:amL0md6orTj1tXY16ANzVU9FmzQB+W7aJwp8pVDbrmA= | |||
gitea.com/macaron/macaron v1.3.3-0.20190821202302-9646c0587edb/go.mod h1:0coI+mSPSwbsyAbOuFllVS38awuk9mevhLD52l50Gjs= | |||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= | |||
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1ks85zJ1lfDGgIiMDuIptTOhJq+zKyg= | |||
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= | |||
github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= | |||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= | |||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= | |||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= | |||
github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304 h1:Jpy1PXuP99tXNrhbq2BaPz9B+jNAvH1JPQQpG/9GCXY= | |||
github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= | |||
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= | |||
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 h1:WN9BUFbdyOsSH/XohnWpXOlq9NBD5sGAB2FciQMUEe8= | |||
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= | |||
github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e h1:GSGeB9EAKY2spCABz6xOX5DbxZEXolK+nBSvmsQwRjM= | |||
github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM= | |||
github.com/unknwon/i18n v0.0.0-20190805065654-5c6446a380b6 h1:sRrkJEHtNoaSvyXMbRgofEOX4/3gMiraevQKJdIBhYE= | |||
github.com/unknwon/i18n v0.0.0-20190805065654-5c6446a380b6/go.mod h1:+5rDk6sDGpl3azws3O+f+GpFSyN9GVr0K8cvQLQM2ZQ= | |||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | |||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc= | |||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | |||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | |||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | |||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | |||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | |||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= | |||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= | |||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | |||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= | |||
gopkg.in/ini.v1 v1.44.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= | |||
gopkg.in/ini.v1 v1.46.0 h1:VeDZbLYGaupuvIrsYCEOe/L/2Pcs5n7hdO1ZTjporag= | |||
gopkg.in/ini.v1 v1.46.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= |
@@ -1,5 +0,0 @@ | |||
module gitea.com/macaron/inject | |||
go 1.11 | |||
require github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 |
@@ -1,13 +0,0 @@ | |||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= | |||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= | |||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= | |||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= | |||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= | |||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= | |||
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 h1:WN9BUFbdyOsSH/XohnWpXOlq9NBD5sGAB2FciQMUEe8= | |||
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= | |||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | |||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | |||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | |||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | |||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= |
@@ -1,12 +0,0 @@ | |||
module gitea.com/macaron/macaron | |||
go 1.11 | |||
require ( | |||
gitea.com/macaron/inject v0.0.0-20190805023432-d4c86e31027a | |||
github.com/smartystreets/assertions v1.0.1 // indirect | |||
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 | |||
github.com/unknwon/com v1.0.1 | |||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 | |||
gopkg.in/ini.v1 v1.44.0 | |||
) |
@@ -1,31 +0,0 @@ | |||
gitea.com/macaron/inject v0.0.0-20190805023432-d4c86e31027a h1:aOKEXkDTnh4euoH0so/THLXeHtQuqHmDPb1xEk6Ehok= | |||
gitea.com/macaron/inject v0.0.0-20190805023432-d4c86e31027a/go.mod h1:h6E4kLao1Yko6DOU6QDnQPcuoNzvbZqzj2mtPcEn1aM= | |||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= | |||
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1ks85zJ1lfDGgIiMDuIptTOhJq+zKyg= | |||
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= | |||
github.com/jtolds/gls v4.2.1+incompatible h1:fSuqC+Gmlu6l/ZYAoZzx2pyucC8Xza35fpRVWLVmUEE= | |||
github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= | |||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= | |||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= | |||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= | |||
github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304 h1:Jpy1PXuP99tXNrhbq2BaPz9B+jNAvH1JPQQpG/9GCXY= | |||
github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= | |||
github.com/smartystreets/assertions v1.0.1 h1:voD4ITNjPL5jjBfgR/r8fPIIBrliWrWHeiJApdr3r4w= | |||
github.com/smartystreets/assertions v1.0.1/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= | |||
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c h1:Ho+uVpkel/udgjbwB5Lktg9BtvJSh2DT0Hi6LPSyI2w= | |||
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= | |||
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 h1:WN9BUFbdyOsSH/XohnWpXOlq9NBD5sGAB2FciQMUEe8= | |||
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= | |||
github.com/unknwon/com v1.0.1 h1:3d1LTxD+Lnf3soQiD4Cp/0BRB+Rsa/+RTvz8GMMzIXs= | |||
github.com/unknwon/com v1.0.1/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM= | |||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | |||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc= | |||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | |||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | |||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | |||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | |||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | |||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= | |||
gopkg.in/ini.v1 v1.44.0 h1:YRJzTUp0kSYWUVFF5XAbDFfyiqwsl0Vb9R8TVP5eRi0= | |||
gopkg.in/ini.v1 v1.44.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= |
@@ -1,32 +0,0 @@ | |||
module gitea.com/macaron/session | |||
go 1.11 | |||
require ( | |||
gitea.com/macaron/macaron v1.3.3-0.20190821202302-9646c0587edb | |||
github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668 | |||
github.com/couchbase/gomemcached v0.0.0-20190515232915-c4b4ca0eb21d // indirect | |||
github.com/couchbase/goutils v0.0.0-20191018232750-b49639060d85 // indirect | |||
github.com/couchbaselabs/go-couchbase v0.0.0-20190708161019-23e7ca2ce2b7 | |||
github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76 // indirect | |||
github.com/edsrzf/mmap-go v1.0.0 // indirect | |||
github.com/go-redis/redis v6.15.2+incompatible | |||
github.com/go-sql-driver/mysql v1.4.1 | |||
github.com/lib/pq v1.2.0 | |||
github.com/lunny/log v0.0.0-20160921050905-7887c61bf0de // indirect | |||
github.com/lunny/nodb v0.0.0-20160621015157-fc1ef06ad4af | |||
github.com/mattn/go-sqlite3 v1.11.0 // indirect | |||
github.com/pelletier/go-toml v1.4.0 // indirect | |||
github.com/pkg/errors v0.8.1 // indirect | |||
github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726 // indirect | |||
github.com/siddontang/go-snappy v0.0.0-20140704025258-d8f7bb82a96d // indirect | |||
github.com/siddontang/ledisdb v0.0.0-20190202134119-8ceb77e66a92 | |||
github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d // indirect | |||
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 | |||
github.com/stretchr/testify v1.3.0 // indirect | |||
github.com/syndtr/goleveldb v1.0.0 // indirect | |||
github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e | |||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 // indirect | |||
google.golang.org/appengine v1.6.1 // indirect | |||
gopkg.in/ini.v1 v1.44.0 | |||
) |
@@ -1,116 +0,0 @@ | |||
gitea.com/macaron/inject v0.0.0-20190803172902-8375ba841591 h1:UbCTjPcLrNxR9LzKDjQBMT2zoxZuEnca1pZCpgeMuhQ= | |||
gitea.com/macaron/inject v0.0.0-20190803172902-8375ba841591/go.mod h1:h6E4kLao1Yko6DOU6QDnQPcuoNzvbZqzj2mtPcEn1aM= | |||
gitea.com/macaron/macaron v1.3.3-0.20190821202302-9646c0587edb h1:amL0md6orTj1tXY16ANzVU9FmzQB+W7aJwp8pVDbrmA= | |||
gitea.com/macaron/macaron v1.3.3-0.20190821202302-9646c0587edb/go.mod h1:0coI+mSPSwbsyAbOuFllVS38awuk9mevhLD52l50Gjs= | |||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= | |||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= | |||
github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668 h1:U/lr3Dgy4WK+hNk4tyD+nuGjpVLPEHuJSFXMw11/HPA= | |||
github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= | |||
github.com/couchbase/gomemcached v0.0.0-20190515232915-c4b4ca0eb21d h1:XMf4E1U+b9E3ElF0mjvfXZdflBRZz4gLp16nQ/QSHQM= | |||
github.com/couchbase/gomemcached v0.0.0-20190515232915-c4b4ca0eb21d/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c= | |||
github.com/couchbase/goutils v0.0.0-20191018232750-b49639060d85 h1:0WMIDtuXCKEm4wtAJgAAXa/qtM5O9MariLwgHaRlYmk= | |||
github.com/couchbase/goutils v0.0.0-20191018232750-b49639060d85/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs= | |||
github.com/couchbaselabs/go-couchbase v0.0.0-20190708161019-23e7ca2ce2b7 h1:1XjEY/gnjQ+AfXef2U6dxCquhiRzkEpxZuWqs+QxTL8= | |||
github.com/couchbaselabs/go-couchbase v0.0.0-20190708161019-23e7ca2ce2b7/go.mod h1:mby/05p8HE5yHEAKiIH/555NoblMs7PtW6NrYshDruc= | |||
github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76 h1:Lgdd/Qp96Qj8jqLpq2cI1I1X7BJnu06efS+XkhRoLUQ= | |||
github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY= | |||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | |||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | |||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | |||
github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= | |||
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= | |||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= | |||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= | |||
github.com/go-redis/redis v6.15.2+incompatible h1:9SpNVG76gr6InJGxoZ6IuuxaCOQwDAhzyXg+Bs+0Sb4= | |||
github.com/go-redis/redis v6.15.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= | |||
github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= | |||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= | |||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= | |||
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= | |||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= | |||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w= | |||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= | |||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= | |||
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1ks85zJ1lfDGgIiMDuIptTOhJq+zKyg= | |||
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= | |||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= | |||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= | |||
github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= | |||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= | |||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= | |||
github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0= | |||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= | |||
github.com/lunny/log v0.0.0-20160921050905-7887c61bf0de h1:nyxwRdWHAVxpFcDThedEgQ07DbcRc5xgNObtbTp76fk= | |||
github.com/lunny/log v0.0.0-20160921050905-7887c61bf0de/go.mod h1:3q8WtuPQsoRbatJuy3nvq/hRSvuBJrHHr+ybPPiNvHQ= | |||
github.com/lunny/nodb v0.0.0-20160621015157-fc1ef06ad4af h1:UaWHNBdukWrSG3DRvHFR/hyfg681fceqQDYVTBncKfQ= | |||
github.com/lunny/nodb v0.0.0-20160621015157-fc1ef06ad4af/go.mod h1:Cqz6pqow14VObJ7peltM+2n3PWOz7yTrfUuGbVFkzN0= | |||
github.com/mattn/go-sqlite3 v1.11.0 h1:LDdKkqtYlom37fkvqs8rMPFKAMe8+SgjbwZ6ex1/A/Q= | |||
github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= | |||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= | |||
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= | |||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= | |||
github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU= | |||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= | |||
github.com/pelletier/go-toml v1.4.0 h1:u3Z1r+oOXJIkxqw34zVhyPgjBsm6X2wn21NWs/HfSeg= | |||
github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo= | |||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= | |||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= | |||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | |||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | |||
github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726 h1:xT+JlYxNGqyT+XcU8iUrN18JYed2TvG9yN5ULG2jATM= | |||
github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw= | |||
github.com/siddontang/go-snappy v0.0.0-20140704025258-d8f7bb82a96d h1:qQWKKOvHN7Q9c6GdmUteCef2F9ubxMpxY1IKwpIKz68= | |||
github.com/siddontang/go-snappy v0.0.0-20140704025258-d8f7bb82a96d/go.mod h1:vq0tzqLRu6TS7Id0wMo2N5QzJoKedVeovOpHjnykSzY= | |||
github.com/siddontang/ledisdb v0.0.0-20190202134119-8ceb77e66a92 h1:qvsJwGToa8rxb42cDRhkbKeX2H5N8BH+s2aUikGt8mI= | |||
github.com/siddontang/ledisdb v0.0.0-20190202134119-8ceb77e66a92/go.mod h1:mF1DpOSOUiJRMR+FDqaqu3EBqrybQtrDDszLUZ6oxPg= | |||
github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d h1:NVwnfyR3rENtlz62bcrkXME3INVUa4lcdGt+opvxExs= | |||
github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA= | |||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= | |||
github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304 h1:Jpy1PXuP99tXNrhbq2BaPz9B+jNAvH1JPQQpG/9GCXY= | |||
github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= | |||
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= | |||
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 h1:WN9BUFbdyOsSH/XohnWpXOlq9NBD5sGAB2FciQMUEe8= | |||
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= | |||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | |||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= | |||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= | |||
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= | |||
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= | |||
github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e h1:GSGeB9EAKY2spCABz6xOX5DbxZEXolK+nBSvmsQwRjM= | |||
github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM= | |||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | |||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | |||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc= | |||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | |||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | |||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | |||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | |||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= | |||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 h1:Ao/3l156eZf2AW5wK8a7/smtodRU+gha3+BeqJ69lRk= | |||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | |||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | |||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | |||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c h1:+EXw7AwNOKzPFXMZ1yNjO40aWCh3PIquJB2fYlv9wcs= | |||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | |||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= | |||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= | |||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | |||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= | |||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= | |||
google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I= | |||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= | |||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= | |||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | |||
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= | |||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= | |||
gopkg.in/ini.v1 v1.44.0 h1:YRJzTUp0kSYWUVFF5XAbDFfyiqwsl0Vb9R8TVP5eRi0= | |||
gopkg.in/ini.v1 v1.44.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= | |||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= | |||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= | |||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | |||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= | |||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
@@ -1,9 +0,0 @@ | |||
module gitea.com/macaron/toolbox | |||
go 1.11 | |||
require ( | |||
gitea.com/macaron/macaron v1.3.3-0.20190821202302-9646c0587edb | |||
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 | |||
github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e | |||
) |
@@ -1,30 +0,0 @@ | |||
gitea.com/macaron/inject v0.0.0-20190803172902-8375ba841591 h1:UbCTjPcLrNxR9LzKDjQBMT2zoxZuEnca1pZCpgeMuhQ= | |||
gitea.com/macaron/inject v0.0.0-20190803172902-8375ba841591/go.mod h1:h6E4kLao1Yko6DOU6QDnQPcuoNzvbZqzj2mtPcEn1aM= | |||
gitea.com/macaron/macaron v1.3.3-0.20190821202302-9646c0587edb h1:amL0md6orTj1tXY16ANzVU9FmzQB+W7aJwp8pVDbrmA= | |||
gitea.com/macaron/macaron v1.3.3-0.20190821202302-9646c0587edb/go.mod h1:0coI+mSPSwbsyAbOuFllVS38awuk9mevhLD52l50Gjs= | |||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= | |||
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1ks85zJ1lfDGgIiMDuIptTOhJq+zKyg= | |||
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= | |||
github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= | |||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= | |||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= | |||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= | |||
github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304 h1:Jpy1PXuP99tXNrhbq2BaPz9B+jNAvH1JPQQpG/9GCXY= | |||
github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= | |||
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= | |||
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 h1:WN9BUFbdyOsSH/XohnWpXOlq9NBD5sGAB2FciQMUEe8= | |||
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= | |||
github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e h1:GSGeB9EAKY2spCABz6xOX5DbxZEXolK+nBSvmsQwRjM= | |||
github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM= | |||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= | |||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | |||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc= | |||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | |||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | |||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | |||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | |||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | |||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= | |||
gopkg.in/ini.v1 v1.44.0 h1:YRJzTUp0kSYWUVFF5XAbDFfyiqwsl0Vb9R8TVP5eRi0= | |||
gopkg.in/ini.v1 v1.44.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= |
@@ -1,10 +0,0 @@ | |||
module github.com/360EntSecGroup-Skylar/excelize/v2 | |||
go 1.12 | |||
require ( | |||
github.com/davecgh/go-spew v1.1.1 // indirect | |||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 | |||
github.com/stretchr/testify v1.3.0 | |||
golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a | |||
) |
@@ -1,14 +0,0 @@ | |||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= | |||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | |||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | |||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | |||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= | |||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= | |||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | |||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | |||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | |||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= | |||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= | |||
golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a h1:gHevYm0pO4QUbwy8Dmdr01R5r1BuKtfYqRqF0h/Cbh0= | |||
golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= | |||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= |
@@ -0,0 +1 @@ | |||
*.exe |
@@ -0,0 +1 @@ | |||
* @microsoft/containerplat |
@@ -0,0 +1,22 @@ | |||
The MIT License (MIT) | |||
Copyright (c) 2015 Microsoft | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
in the Software without restriction, including without limitation the rights | |||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
copies of the Software, and to permit persons to whom the Software is | |||
furnished to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in all | |||
copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
SOFTWARE. | |||
@@ -0,0 +1,37 @@ | |||
# go-winio [![Build Status](https://github.com/microsoft/go-winio/actions/workflows/ci.yml/badge.svg)](https://github.com/microsoft/go-winio/actions/workflows/ci.yml) | |||
This repository contains utilities for efficiently performing Win32 IO operations in | |||
Go. Currently, this is focused on accessing named pipes and other file handles, and | |||
for using named pipes as a net transport. | |||
This code relies on IO completion ports to avoid blocking IO on system threads, allowing Go | |||
to reuse the thread to schedule another goroutine. This limits support to Windows Vista and | |||
newer operating systems. This is similar to the implementation of network sockets in Go's net | |||
package. | |||
Please see the LICENSE file for licensing information. | |||
## Contributing | |||
This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) | |||
declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://cla.microsoft.com. | |||
When you submit a pull request, a CLA-bot will automatically determine whether you need to provide a CLA and decorate the PR | |||
appropriately (e.g., label, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA. | |||
We also require that contributors sign their commits using git commit -s or git commit --signoff to certify they either authored the work themselves | |||
or otherwise have permission to use it in this project. Please see https://developercertificate.org/ for more info, as well as to make sure that you can | |||
attest to the rules listed. Our CI uses the DCO Github app to ensure that all commits in a given PR are signed-off. | |||
## Code of Conduct | |||
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). | |||
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or | |||
contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. | |||
## Special Thanks | |||
Thanks to natefinch for the inspiration for this library. See https://github.com/natefinch/npipe | |||
for another named pipe implementation. |
@@ -0,0 +1,280 @@ | |||
// +build windows | |||
package winio | |||
import ( | |||
"encoding/binary" | |||
"errors" | |||
"fmt" | |||
"io" | |||
"io/ioutil" | |||
"os" | |||
"runtime" | |||
"syscall" | |||
"unicode/utf16" | |||
) | |||
//sys backupRead(h syscall.Handle, b []byte, bytesRead *uint32, abort bool, processSecurity bool, context *uintptr) (err error) = BackupRead | |||
//sys backupWrite(h syscall.Handle, b []byte, bytesWritten *uint32, abort bool, processSecurity bool, context *uintptr) (err error) = BackupWrite | |||
const ( | |||
BackupData = uint32(iota + 1) | |||
BackupEaData | |||
BackupSecurity | |||
BackupAlternateData | |||
BackupLink | |||
BackupPropertyData | |||
BackupObjectId | |||
BackupReparseData | |||
BackupSparseBlock | |||
BackupTxfsData | |||
) | |||
const ( | |||
StreamSparseAttributes = uint32(8) | |||
) | |||
const ( | |||
WRITE_DAC = 0x40000 | |||
WRITE_OWNER = 0x80000 | |||
ACCESS_SYSTEM_SECURITY = 0x1000000 | |||
) | |||
// BackupHeader represents a backup stream of a file. | |||
type BackupHeader struct { | |||
Id uint32 // The backup stream ID | |||
Attributes uint32 // Stream attributes | |||
Size int64 // The size of the stream in bytes | |||
Name string // The name of the stream (for BackupAlternateData only). | |||
Offset int64 // The offset of the stream in the file (for BackupSparseBlock only). | |||
} | |||
type win32StreamId struct { | |||
StreamId uint32 | |||
Attributes uint32 | |||
Size uint64 | |||
NameSize uint32 | |||
} | |||
// BackupStreamReader reads from a stream produced by the BackupRead Win32 API and produces a series | |||
// of BackupHeader values. | |||
type BackupStreamReader struct { | |||
r io.Reader | |||
bytesLeft int64 | |||
} | |||
// NewBackupStreamReader produces a BackupStreamReader from any io.Reader. | |||
func NewBackupStreamReader(r io.Reader) *BackupStreamReader { | |||
return &BackupStreamReader{r, 0} | |||
} | |||
// Next returns the next backup stream and prepares for calls to Read(). It skips the remainder of the current stream if | |||
// it was not completely read. | |||
func (r *BackupStreamReader) Next() (*BackupHeader, error) { | |||
if r.bytesLeft > 0 { | |||
if s, ok := r.r.(io.Seeker); ok { | |||
// Make sure Seek on io.SeekCurrent sometimes succeeds | |||
// before trying the actual seek. | |||
if _, err := s.Seek(0, io.SeekCurrent); err == nil { | |||
if _, err = s.Seek(r.bytesLeft, io.SeekCurrent); err != nil { | |||
return nil, err | |||
} | |||
r.bytesLeft = 0 | |||
} | |||
} | |||
if _, err := io.Copy(ioutil.Discard, r); err != nil { | |||
return nil, err | |||
} | |||
} | |||
var wsi win32StreamId | |||
if err := binary.Read(r.r, binary.LittleEndian, &wsi); err != nil { | |||
return nil, err | |||
} | |||
hdr := &BackupHeader{ | |||
Id: wsi.StreamId, | |||
Attributes: wsi.Attributes, | |||
Size: int64(wsi.Size), | |||
} | |||
if wsi.NameSize != 0 { | |||
name := make([]uint16, int(wsi.NameSize/2)) | |||
if err := binary.Read(r.r, binary.LittleEndian, name); err != nil { | |||
return nil, err | |||
} | |||
hdr.Name = syscall.UTF16ToString(name) | |||
} | |||
if wsi.StreamId == BackupSparseBlock { | |||
if err := binary.Read(r.r, binary.LittleEndian, &hdr.Offset); err != nil { | |||
return nil, err | |||
} | |||
hdr.Size -= 8 | |||
} | |||
r.bytesLeft = hdr.Size | |||
return hdr, nil | |||
} | |||
// Read reads from the current backup stream. | |||
func (r *BackupStreamReader) Read(b []byte) (int, error) { | |||
if r.bytesLeft == 0 { | |||
return 0, io.EOF | |||
} | |||
if int64(len(b)) > r.bytesLeft { | |||
b = b[:r.bytesLeft] | |||
} | |||
n, err := r.r.Read(b) | |||
r.bytesLeft -= int64(n) | |||
if err == io.EOF { | |||
err = io.ErrUnexpectedEOF | |||
} else if r.bytesLeft == 0 && err == nil { | |||
err = io.EOF | |||
} | |||
return n, err | |||
} | |||
// BackupStreamWriter writes a stream compatible with the BackupWrite Win32 API. | |||
type BackupStreamWriter struct { | |||
w io.Writer | |||
bytesLeft int64 | |||
} | |||
// NewBackupStreamWriter produces a BackupStreamWriter on top of an io.Writer. | |||
func NewBackupStreamWriter(w io.Writer) *BackupStreamWriter { | |||
return &BackupStreamWriter{w, 0} | |||
} | |||
// WriteHeader writes the next backup stream header and prepares for calls to Write(). | |||
func (w *BackupStreamWriter) WriteHeader(hdr *BackupHeader) error { | |||
if w.bytesLeft != 0 { | |||
return fmt.Errorf("missing %d bytes", w.bytesLeft) | |||
} | |||
name := utf16.Encode([]rune(hdr.Name)) | |||
wsi := win32StreamId{ | |||
StreamId: hdr.Id, | |||
Attributes: hdr.Attributes, | |||
Size: uint64(hdr.Size), | |||
NameSize: uint32(len(name) * 2), | |||
} | |||
if hdr.Id == BackupSparseBlock { | |||
// Include space for the int64 block offset | |||
wsi.Size += 8 | |||
} | |||
if err := binary.Write(w.w, binary.LittleEndian, &wsi); err != nil { | |||
return err | |||
} | |||
if len(name) != 0 { | |||
if err := binary.Write(w.w, binary.LittleEndian, name); err != nil { | |||
return err | |||
} | |||
} | |||
if hdr.Id == BackupSparseBlock { | |||
if err := binary.Write(w.w, binary.LittleEndian, hdr.Offset); err != nil { | |||
return err | |||
} | |||
} | |||
w.bytesLeft = hdr.Size | |||
return nil | |||
} | |||
// Write writes to the current backup stream. | |||
func (w *BackupStreamWriter) Write(b []byte) (int, error) { | |||
if w.bytesLeft < int64(len(b)) { | |||
return 0, fmt.Errorf("too many bytes by %d", int64(len(b))-w.bytesLeft) | |||
} | |||
n, err := w.w.Write(b) | |||
w.bytesLeft -= int64(n) | |||
return n, err | |||
} | |||
// BackupFileReader provides an io.ReadCloser interface on top of the BackupRead Win32 API. | |||
type BackupFileReader struct { | |||
f *os.File | |||
includeSecurity bool | |||
ctx uintptr | |||
} | |||
// NewBackupFileReader returns a new BackupFileReader from a file handle. If includeSecurity is true, | |||
// Read will attempt to read the security descriptor of the file. | |||
func NewBackupFileReader(f *os.File, includeSecurity bool) *BackupFileReader { | |||
r := &BackupFileReader{f, includeSecurity, 0} | |||
return r | |||
} | |||
// Read reads a backup stream from the file by calling the Win32 API BackupRead(). | |||
func (r *BackupFileReader) Read(b []byte) (int, error) { | |||
var bytesRead uint32 | |||
err := backupRead(syscall.Handle(r.f.Fd()), b, &bytesRead, false, r.includeSecurity, &r.ctx) | |||
if err != nil { | |||
return 0, &os.PathError{"BackupRead", r.f.Name(), err} | |||
} | |||
runtime.KeepAlive(r.f) | |||
if bytesRead == 0 { | |||
return 0, io.EOF | |||
} | |||
return int(bytesRead), nil | |||
} | |||
// Close frees Win32 resources associated with the BackupFileReader. It does not close | |||
// the underlying file. | |||
func (r *BackupFileReader) Close() error { | |||
if r.ctx != 0 { | |||
backupRead(syscall.Handle(r.f.Fd()), nil, nil, true, false, &r.ctx) | |||
runtime.KeepAlive(r.f) | |||
r.ctx = 0 | |||
} | |||
return nil | |||
} | |||
// BackupFileWriter provides an io.WriteCloser interface on top of the BackupWrite Win32 API. | |||
type BackupFileWriter struct { | |||
f *os.File | |||
includeSecurity bool | |||
ctx uintptr | |||
} | |||
// NewBackupFileWriter returns a new BackupFileWriter from a file handle. If includeSecurity is true, | |||
// Write() will attempt to restore the security descriptor from the stream. | |||
func NewBackupFileWriter(f *os.File, includeSecurity bool) *BackupFileWriter { | |||
w := &BackupFileWriter{f, includeSecurity, 0} | |||
return w | |||
} | |||
// Write restores a portion of the file using the provided backup stream. | |||
func (w *BackupFileWriter) Write(b []byte) (int, error) { | |||
var bytesWritten uint32 | |||
err := backupWrite(syscall.Handle(w.f.Fd()), b, &bytesWritten, false, w.includeSecurity, &w.ctx) | |||
if err != nil { | |||
return 0, &os.PathError{"BackupWrite", w.f.Name(), err} | |||
} | |||
runtime.KeepAlive(w.f) | |||
if int(bytesWritten) != len(b) { | |||
return int(bytesWritten), errors.New("not all bytes could be written") | |||
} | |||
return len(b), nil | |||
} | |||
// Close frees Win32 resources associated with the BackupFileWriter. It does not | |||
// close the underlying file. | |||
func (w *BackupFileWriter) Close() error { | |||
if w.ctx != 0 { | |||
backupWrite(syscall.Handle(w.f.Fd()), nil, nil, true, false, &w.ctx) | |||
runtime.KeepAlive(w.f) | |||
w.ctx = 0 | |||
} | |||
return nil | |||
} | |||
// OpenForBackup opens a file or directory, potentially skipping access checks if the backup | |||
// or restore privileges have been acquired. | |||
// | |||
// If the file opened was a directory, it cannot be used with Readdir(). | |||
func OpenForBackup(path string, access uint32, share uint32, createmode uint32) (*os.File, error) { | |||
winPath, err := syscall.UTF16FromString(path) | |||
if err != nil { | |||
return nil, err | |||
} | |||
h, err := syscall.CreateFile(&winPath[0], access, share, nil, createmode, syscall.FILE_FLAG_BACKUP_SEMANTICS|syscall.FILE_FLAG_OPEN_REPARSE_POINT, 0) | |||
if err != nil { | |||
err = &os.PathError{Op: "open", Path: path, Err: err} | |||
return nil, err | |||
} | |||
return os.NewFile(uintptr(h), path), nil | |||
} |
@@ -0,0 +1,137 @@ | |||
package winio | |||
import ( | |||
"bytes" | |||
"encoding/binary" | |||
"errors" | |||
) | |||
type fileFullEaInformation struct { | |||
NextEntryOffset uint32 | |||
Flags uint8 | |||
NameLength uint8 | |||
ValueLength uint16 | |||
} | |||
var ( | |||
fileFullEaInformationSize = binary.Size(&fileFullEaInformation{}) | |||
errInvalidEaBuffer = errors.New("invalid extended attribute buffer") | |||
errEaNameTooLarge = errors.New("extended attribute name too large") | |||
errEaValueTooLarge = errors.New("extended attribute value too large") | |||
) | |||
// ExtendedAttribute represents a single Windows EA. | |||
type ExtendedAttribute struct { | |||
Name string | |||
Value []byte | |||
Flags uint8 | |||
} | |||
func parseEa(b []byte) (ea ExtendedAttribute, nb []byte, err error) { | |||
var info fileFullEaInformation | |||
err = binary.Read(bytes.NewReader(b), binary.LittleEndian, &info) | |||
if err != nil { | |||
err = errInvalidEaBuffer | |||
return | |||
} | |||
nameOffset := fileFullEaInformationSize | |||
nameLen := int(info.NameLength) | |||
valueOffset := nameOffset + int(info.NameLength) + 1 | |||
valueLen := int(info.ValueLength) | |||
nextOffset := int(info.NextEntryOffset) | |||
if valueLen+valueOffset > len(b) || nextOffset < 0 || nextOffset > len(b) { | |||
err = errInvalidEaBuffer | |||
return | |||
} | |||
ea.Name = string(b[nameOffset : nameOffset+nameLen]) | |||
ea.Value = b[valueOffset : valueOffset+valueLen] | |||
ea.Flags = info.Flags | |||
if info.NextEntryOffset != 0 { | |||
nb = b[info.NextEntryOffset:] | |||
} | |||
return | |||
} | |||
// DecodeExtendedAttributes decodes a list of EAs from a FILE_FULL_EA_INFORMATION | |||
// buffer retrieved from BackupRead, ZwQueryEaFile, etc. | |||
func DecodeExtendedAttributes(b []byte) (eas []ExtendedAttribute, err error) { | |||
for len(b) != 0 { | |||
ea, nb, err := parseEa(b) | |||
if err != nil { | |||
return nil, err | |||
} | |||
eas = append(eas, ea) | |||
b = nb | |||
} | |||
return | |||
} | |||
func writeEa(buf *bytes.Buffer, ea *ExtendedAttribute, last bool) error { | |||
if int(uint8(len(ea.Name))) != len(ea.Name) { | |||
return errEaNameTooLarge | |||
} | |||
if int(uint16(len(ea.Value))) != len(ea.Value) { | |||
return errEaValueTooLarge | |||
} | |||
entrySize := uint32(fileFullEaInformationSize + len(ea.Name) + 1 + len(ea.Value)) | |||
withPadding := (entrySize + 3) &^ 3 | |||
nextOffset := uint32(0) | |||
if !last { | |||
nextOffset = withPadding | |||
} | |||
info := fileFullEaInformation{ | |||
NextEntryOffset: nextOffset, | |||
Flags: ea.Flags, | |||
NameLength: uint8(len(ea.Name)), | |||
ValueLength: uint16(len(ea.Value)), | |||
} | |||
err := binary.Write(buf, binary.LittleEndian, &info) | |||
if err != nil { | |||
return err | |||
} | |||
_, err = buf.Write([]byte(ea.Name)) | |||
if err != nil { | |||
return err | |||
} | |||
err = buf.WriteByte(0) | |||
if err != nil { | |||
return err | |||
} | |||
_, err = buf.Write(ea.Value) | |||
if err != nil { | |||
return err | |||
} | |||
_, err = buf.Write([]byte{0, 0, 0}[0 : withPadding-entrySize]) | |||
if err != nil { | |||
return err | |||
} | |||
return nil | |||
} | |||
// EncodeExtendedAttributes encodes a list of EAs into a FILE_FULL_EA_INFORMATION | |||
// buffer for use with BackupWrite, ZwSetEaFile, etc. | |||
func EncodeExtendedAttributes(eas []ExtendedAttribute) ([]byte, error) { | |||
var buf bytes.Buffer | |||
for i := range eas { | |||
last := false | |||
if i == len(eas)-1 { | |||
last = true | |||
} | |||
err := writeEa(&buf, &eas[i], last) | |||
if err != nil { | |||
return nil, err | |||
} | |||
} | |||
return buf.Bytes(), nil | |||
} |
@@ -0,0 +1,329 @@ | |||
//go:build windows | |||
// +build windows | |||
package winio | |||
import ( | |||
"errors" | |||
"io" | |||
"runtime" | |||
"sync" | |||
"sync/atomic" | |||
"syscall" | |||
"time" | |||
) | |||
//sys cancelIoEx(file syscall.Handle, o *syscall.Overlapped) (err error) = CancelIoEx | |||
//sys createIoCompletionPort(file syscall.Handle, port syscall.Handle, key uintptr, threadCount uint32) (newport syscall.Handle, err error) = CreateIoCompletionPort | |||
//sys getQueuedCompletionStatus(port syscall.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) = GetQueuedCompletionStatus | |||
//sys setFileCompletionNotificationModes(h syscall.Handle, flags uint8) (err error) = SetFileCompletionNotificationModes | |||
//sys wsaGetOverlappedResult(h syscall.Handle, o *syscall.Overlapped, bytes *uint32, wait bool, flags *uint32) (err error) = ws2_32.WSAGetOverlappedResult | |||
type atomicBool int32 | |||
func (b *atomicBool) isSet() bool { return atomic.LoadInt32((*int32)(b)) != 0 } | |||
func (b *atomicBool) setFalse() { atomic.StoreInt32((*int32)(b), 0) } | |||
func (b *atomicBool) setTrue() { atomic.StoreInt32((*int32)(b), 1) } | |||
func (b *atomicBool) swap(new bool) bool { | |||
var newInt int32 | |||
if new { | |||
newInt = 1 | |||
} | |||
return atomic.SwapInt32((*int32)(b), newInt) == 1 | |||
} | |||
const ( | |||
cFILE_SKIP_COMPLETION_PORT_ON_SUCCESS = 1 | |||
cFILE_SKIP_SET_EVENT_ON_HANDLE = 2 | |||
) | |||
var ( | |||
ErrFileClosed = errors.New("file has already been closed") | |||
ErrTimeout = &timeoutError{} | |||
) | |||
type timeoutError struct{} | |||
func (e *timeoutError) Error() string { return "i/o timeout" } | |||
func (e *timeoutError) Timeout() bool { return true } | |||
func (e *timeoutError) Temporary() bool { return true } | |||
type timeoutChan chan struct{} | |||
var ioInitOnce sync.Once | |||
var ioCompletionPort syscall.Handle | |||
// ioResult contains the result of an asynchronous IO operation | |||
type ioResult struct { | |||
bytes uint32 | |||
err error | |||
} | |||
// ioOperation represents an outstanding asynchronous Win32 IO | |||
type ioOperation struct { | |||
o syscall.Overlapped | |||
ch chan ioResult | |||
} | |||
func initIo() { | |||
h, err := createIoCompletionPort(syscall.InvalidHandle, 0, 0, 0xffffffff) | |||
if err != nil { | |||
panic(err) | |||
} | |||
ioCompletionPort = h | |||
go ioCompletionProcessor(h) | |||
} | |||
// win32File implements Reader, Writer, and Closer on a Win32 handle without blocking in a syscall. | |||
// It takes ownership of this handle and will close it if it is garbage collected. | |||
type win32File struct { | |||
handle syscall.Handle | |||
wg sync.WaitGroup | |||
wgLock sync.RWMutex | |||
closing atomicBool | |||
socket bool | |||
readDeadline deadlineHandler | |||
writeDeadline deadlineHandler | |||
} | |||
type deadlineHandler struct { | |||
setLock sync.Mutex | |||
channel timeoutChan | |||
channelLock sync.RWMutex | |||
timer *time.Timer | |||
timedout atomicBool | |||
} | |||
// makeWin32File makes a new win32File from an existing file handle | |||
func makeWin32File(h syscall.Handle) (*win32File, error) { | |||
f := &win32File{handle: h} | |||
ioInitOnce.Do(initIo) | |||
_, err := createIoCompletionPort(h, ioCompletionPort, 0, 0xffffffff) | |||
if err != nil { | |||
return nil, err | |||
} | |||
err = setFileCompletionNotificationModes(h, cFILE_SKIP_COMPLETION_PORT_ON_SUCCESS|cFILE_SKIP_SET_EVENT_ON_HANDLE) | |||
if err != nil { | |||
return nil, err | |||
} | |||
f.readDeadline.channel = make(timeoutChan) | |||
f.writeDeadline.channel = make(timeoutChan) | |||
return f, nil | |||
} | |||
func MakeOpenFile(h syscall.Handle) (io.ReadWriteCloser, error) { | |||
// If we return the result of makeWin32File directly, it can result in an | |||
// interface-wrapped nil, rather than a nil interface value. | |||
f, err := makeWin32File(h) | |||
if err != nil { | |||
return nil, err | |||
} | |||
return f, nil | |||
} | |||
// closeHandle closes the resources associated with a Win32 handle | |||
func (f *win32File) closeHandle() { | |||
f.wgLock.Lock() | |||
// Atomically set that we are closing, releasing the resources only once. | |||
if !f.closing.swap(true) { | |||
f.wgLock.Unlock() | |||
// cancel all IO and wait for it to complete | |||
cancelIoEx(f.handle, nil) | |||
f.wg.Wait() | |||
// at this point, no new IO can start | |||
syscall.Close(f.handle) | |||
f.handle = 0 | |||
} else { | |||
f.wgLock.Unlock() | |||
} | |||
} | |||
// Close closes a win32File. | |||
func (f *win32File) Close() error { | |||
f.closeHandle() | |||
return nil | |||
} | |||
// IsClosed checks if the file has been closed | |||
func (f *win32File) IsClosed() bool { | |||
return f.closing.isSet() | |||
} | |||
// prepareIo prepares for a new IO operation. | |||
// The caller must call f.wg.Done() when the IO is finished, prior to Close() returning. | |||
func (f *win32File) prepareIo() (*ioOperation, error) { | |||
f.wgLock.RLock() | |||
if f.closing.isSet() { | |||
f.wgLock.RUnlock() | |||
return nil, ErrFileClosed | |||
} | |||
f.wg.Add(1) | |||
f.wgLock.RUnlock() | |||
c := &ioOperation{} | |||
c.ch = make(chan ioResult) | |||
return c, nil | |||
} | |||
// ioCompletionProcessor processes completed async IOs forever | |||
func ioCompletionProcessor(h syscall.Handle) { | |||
for { | |||
var bytes uint32 | |||
var key uintptr | |||
var op *ioOperation | |||
err := getQueuedCompletionStatus(h, &bytes, &key, &op, syscall.INFINITE) | |||
if op == nil { | |||
panic(err) | |||
} | |||
op.ch <- ioResult{bytes, err} | |||
} | |||
} | |||
// asyncIo processes the return value from ReadFile or WriteFile, blocking until | |||
// the operation has actually completed. | |||
func (f *win32File) asyncIo(c *ioOperation, d *deadlineHandler, bytes uint32, err error) (int, error) { | |||
if err != syscall.ERROR_IO_PENDING { | |||
return int(bytes), err | |||
} | |||
if f.closing.isSet() { | |||
cancelIoEx(f.handle, &c.o) | |||
} | |||
var timeout timeoutChan | |||
if d != nil { | |||
d.channelLock.Lock() | |||
timeout = d.channel | |||
d.channelLock.Unlock() | |||
} | |||
var r ioResult | |||
select { | |||
case r = <-c.ch: | |||
err = r.err | |||
if err == syscall.ERROR_OPERATION_ABORTED { | |||
if f.closing.isSet() { | |||
err = ErrFileClosed | |||
} | |||
} else if err != nil && f.socket { | |||
// err is from Win32. Query the overlapped structure to get the winsock error. | |||
var bytes, flags uint32 | |||
err = wsaGetOverlappedResult(f.handle, &c.o, &bytes, false, &flags) | |||
} | |||
case <-timeout: | |||
cancelIoEx(f.handle, &c.o) | |||
r = <-c.ch | |||
err = r.err | |||
if err == syscall.ERROR_OPERATION_ABORTED { | |||
err = ErrTimeout | |||
} | |||
} | |||
// runtime.KeepAlive is needed, as c is passed via native | |||
// code to ioCompletionProcessor, c must remain alive | |||
// until the channel read is complete. | |||
runtime.KeepAlive(c) | |||
return int(r.bytes), err | |||
} | |||
// Read reads from a file handle. | |||
func (f *win32File) Read(b []byte) (int, error) { | |||
c, err := f.prepareIo() | |||
if err != nil { | |||
return 0, err | |||
} | |||
defer f.wg.Done() | |||
if f.readDeadline.timedout.isSet() { | |||
return 0, ErrTimeout | |||
} | |||
var bytes uint32 | |||
err = syscall.ReadFile(f.handle, b, &bytes, &c.o) | |||
n, err := f.asyncIo(c, &f.readDeadline, bytes, err) | |||
runtime.KeepAlive(b) | |||
// Handle EOF conditions. | |||
if err == nil && n == 0 && len(b) != 0 { | |||
return 0, io.EOF | |||
} else if err == syscall.ERROR_BROKEN_PIPE { | |||
return 0, io.EOF | |||
} else { | |||
return n, err | |||
} | |||
} | |||
// Write writes to a file handle. | |||
func (f *win32File) Write(b []byte) (int, error) { | |||
c, err := f.prepareIo() | |||
if err != nil { | |||
return 0, err | |||
} | |||
defer f.wg.Done() | |||
if f.writeDeadline.timedout.isSet() { | |||
return 0, ErrTimeout | |||
} | |||
var bytes uint32 | |||
err = syscall.WriteFile(f.handle, b, &bytes, &c.o) | |||
n, err := f.asyncIo(c, &f.writeDeadline, bytes, err) | |||
runtime.KeepAlive(b) | |||
return n, err | |||
} | |||
func (f *win32File) SetReadDeadline(deadline time.Time) error { | |||
return f.readDeadline.set(deadline) | |||
} | |||
func (f *win32File) SetWriteDeadline(deadline time.Time) error { | |||
return f.writeDeadline.set(deadline) | |||
} | |||
func (f *win32File) Flush() error { | |||
return syscall.FlushFileBuffers(f.handle) | |||
} | |||
func (f *win32File) Fd() uintptr { | |||
return uintptr(f.handle) | |||
} | |||
func (d *deadlineHandler) set(deadline time.Time) error { | |||
d.setLock.Lock() | |||
defer d.setLock.Unlock() | |||
if d.timer != nil { | |||
if !d.timer.Stop() { | |||
<-d.channel | |||
} | |||
d.timer = nil | |||
} | |||
d.timedout.setFalse() | |||
select { | |||
case <-d.channel: | |||
d.channelLock.Lock() | |||
d.channel = make(chan struct{}) | |||
d.channelLock.Unlock() | |||
default: | |||
} | |||
if deadline.IsZero() { | |||
return nil | |||
} | |||
timeoutIO := func() { | |||
d.timedout.setTrue() | |||
close(d.channel) | |||
} | |||
now := time.Now() | |||
duration := deadline.Sub(now) | |||
if deadline.After(now) { | |||
// Deadline is in the future, set a timer to wait | |||
d.timer = time.AfterFunc(duration, timeoutIO) | |||
} else { | |||
// Deadline is in the past. Cancel all pending IO now. | |||
timeoutIO() | |||
} | |||
return nil | |||
} |
@@ -0,0 +1,73 @@ | |||
// +build windows | |||
package winio | |||
import ( | |||
"os" | |||
"runtime" | |||
"unsafe" | |||
"golang.org/x/sys/windows" | |||
) | |||
// FileBasicInfo contains file access time and file attributes information. | |||
type FileBasicInfo struct { | |||
CreationTime, LastAccessTime, LastWriteTime, ChangeTime windows.Filetime | |||
FileAttributes uint32 | |||
pad uint32 // padding | |||
} | |||
// GetFileBasicInfo retrieves times and attributes for a file. | |||
func GetFileBasicInfo(f *os.File) (*FileBasicInfo, error) { | |||
bi := &FileBasicInfo{} | |||
if err := windows.GetFileInformationByHandleEx(windows.Handle(f.Fd()), windows.FileBasicInfo, (*byte)(unsafe.Pointer(bi)), uint32(unsafe.Sizeof(*bi))); err != nil { | |||
return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err} | |||
} | |||
runtime.KeepAlive(f) | |||
return bi, nil | |||
} | |||
// SetFileBasicInfo sets times and attributes for a file. | |||
func SetFileBasicInfo(f *os.File, bi *FileBasicInfo) error { | |||
if err := windows.SetFileInformationByHandle(windows.Handle(f.Fd()), windows.FileBasicInfo, (*byte)(unsafe.Pointer(bi)), uint32(unsafe.Sizeof(*bi))); err != nil { | |||
return &os.PathError{Op: "SetFileInformationByHandle", Path: f.Name(), Err: err} | |||
} | |||
runtime.KeepAlive(f) | |||
return nil | |||
} | |||
// FileStandardInfo contains extended information for the file. | |||
// FILE_STANDARD_INFO in WinBase.h | |||
// https://docs.microsoft.com/en-us/windows/win32/api/winbase/ns-winbase-file_standard_info | |||
type FileStandardInfo struct { | |||
AllocationSize, EndOfFile int64 | |||
NumberOfLinks uint32 | |||
DeletePending, Directory bool | |||
} | |||
// GetFileStandardInfo retrieves ended information for the file. | |||
func GetFileStandardInfo(f *os.File) (*FileStandardInfo, error) { | |||
si := &FileStandardInfo{} | |||
if err := windows.GetFileInformationByHandleEx(windows.Handle(f.Fd()), windows.FileStandardInfo, (*byte)(unsafe.Pointer(si)), uint32(unsafe.Sizeof(*si))); err != nil { | |||
return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err} | |||
} | |||
runtime.KeepAlive(f) | |||
return si, nil | |||
} | |||
// FileIDInfo contains the volume serial number and file ID for a file. This pair should be | |||
// unique on a system. | |||
type FileIDInfo struct { | |||
VolumeSerialNumber uint64 | |||
FileID [16]byte | |||
} | |||
// GetFileID retrieves the unique (volume, file ID) pair for a file. | |||
func GetFileID(f *os.File) (*FileIDInfo, error) { | |||
fileID := &FileIDInfo{} | |||
if err := windows.GetFileInformationByHandleEx(windows.Handle(f.Fd()), windows.FileIdInfo, (*byte)(unsafe.Pointer(fileID)), uint32(unsafe.Sizeof(*fileID))); err != nil { | |||
return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err} | |||
} | |||
runtime.KeepAlive(f) | |||
return fileID, nil | |||
} |
@@ -0,0 +1,316 @@ | |||
//go:build windows | |||
// +build windows | |||
package winio | |||
import ( | |||
"fmt" | |||
"io" | |||
"net" | |||
"os" | |||
"syscall" | |||
"time" | |||
"unsafe" | |||
"github.com/Microsoft/go-winio/pkg/guid" | |||
) | |||
//sys bind(s syscall.Handle, name unsafe.Pointer, namelen int32) (err error) [failretval==socketError] = ws2_32.bind | |||
const ( | |||
afHvSock = 34 // AF_HYPERV | |||
socketError = ^uintptr(0) | |||
) | |||
// An HvsockAddr is an address for a AF_HYPERV socket. | |||
type HvsockAddr struct { | |||
VMID guid.GUID | |||
ServiceID guid.GUID | |||
} | |||
type rawHvsockAddr struct { | |||
Family uint16 | |||
_ uint16 | |||
VMID guid.GUID | |||
ServiceID guid.GUID | |||
} | |||
// Network returns the address's network name, "hvsock". | |||
func (addr *HvsockAddr) Network() string { | |||
return "hvsock" | |||
} | |||
func (addr *HvsockAddr) String() string { | |||
return fmt.Sprintf("%s:%s", &addr.VMID, &addr.ServiceID) | |||
} | |||
// VsockServiceID returns an hvsock service ID corresponding to the specified AF_VSOCK port. | |||
func VsockServiceID(port uint32) guid.GUID { | |||
g, _ := guid.FromString("00000000-facb-11e6-bd58-64006a7986d3") | |||
g.Data1 = port | |||
return g | |||
} | |||
func (addr *HvsockAddr) raw() rawHvsockAddr { | |||
return rawHvsockAddr{ | |||
Family: afHvSock, | |||
VMID: addr.VMID, | |||
ServiceID: addr.ServiceID, | |||
} | |||
} | |||
func (addr *HvsockAddr) fromRaw(raw *rawHvsockAddr) { | |||
addr.VMID = raw.VMID | |||
addr.ServiceID = raw.ServiceID | |||
} | |||
// HvsockListener is a socket listener for the AF_HYPERV address family. | |||
type HvsockListener struct { | |||
sock *win32File | |||
addr HvsockAddr | |||
} | |||
// HvsockConn is a connected socket of the AF_HYPERV address family. | |||
type HvsockConn struct { | |||
sock *win32File | |||
local, remote HvsockAddr | |||
} | |||
func newHvSocket() (*win32File, error) { | |||
fd, err := syscall.Socket(afHvSock, syscall.SOCK_STREAM, 1) | |||
if err != nil { | |||
return nil, os.NewSyscallError("socket", err) | |||
} | |||
f, err := makeWin32File(fd) | |||
if err != nil { | |||
syscall.Close(fd) | |||
return nil, err | |||
} | |||
f.socket = true | |||
return f, nil | |||
} | |||
// ListenHvsock listens for connections on the specified hvsock address. | |||
func ListenHvsock(addr *HvsockAddr) (_ *HvsockListener, err error) { | |||
l := &HvsockListener{addr: *addr} | |||
sock, err := newHvSocket() | |||
if err != nil { | |||
return nil, l.opErr("listen", err) | |||
} | |||
sa := addr.raw() | |||
err = bind(sock.handle, unsafe.Pointer(&sa), int32(unsafe.Sizeof(sa))) | |||
if err != nil { | |||
return nil, l.opErr("listen", os.NewSyscallError("socket", err)) | |||
} | |||
err = syscall.Listen(sock.handle, 16) | |||
if err != nil { | |||
return nil, l.opErr("listen", os.NewSyscallError("listen", err)) | |||
} | |||
return &HvsockListener{sock: sock, addr: *addr}, nil | |||
} | |||
func (l *HvsockListener) opErr(op string, err error) error { | |||
return &net.OpError{Op: op, Net: "hvsock", Addr: &l.addr, Err: err} | |||
} | |||
// Addr returns the listener's network address. | |||
func (l *HvsockListener) Addr() net.Addr { | |||
return &l.addr | |||
} | |||
// Accept waits for the next connection and returns it. | |||
func (l *HvsockListener) Accept() (_ net.Conn, err error) { | |||
sock, err := newHvSocket() | |||
if err != nil { | |||
return nil, l.opErr("accept", err) | |||
} | |||
defer func() { | |||
if sock != nil { | |||
sock.Close() | |||
} | |||
}() | |||
c, err := l.sock.prepareIo() | |||
if err != nil { | |||
return nil, l.opErr("accept", err) | |||
} | |||
defer l.sock.wg.Done() | |||
// AcceptEx, per documentation, requires an extra 16 bytes per address. | |||
const addrlen = uint32(16 + unsafe.Sizeof(rawHvsockAddr{})) | |||
var addrbuf [addrlen * 2]byte | |||
var bytes uint32 | |||
err = syscall.AcceptEx(l.sock.handle, sock.handle, &addrbuf[0], 0, addrlen, addrlen, &bytes, &c.o) | |||
_, err = l.sock.asyncIo(c, nil, bytes, err) | |||
if err != nil { | |||
return nil, l.opErr("accept", os.NewSyscallError("acceptex", err)) | |||
} | |||
conn := &HvsockConn{ | |||
sock: sock, | |||
} | |||
conn.local.fromRaw((*rawHvsockAddr)(unsafe.Pointer(&addrbuf[0]))) | |||
conn.remote.fromRaw((*rawHvsockAddr)(unsafe.Pointer(&addrbuf[addrlen]))) | |||
sock = nil | |||
return conn, nil | |||
} | |||
// Close closes the listener, causing any pending Accept calls to fail. | |||
func (l *HvsockListener) Close() error { | |||
return l.sock.Close() | |||
} | |||
/* Need to finish ConnectEx handling | |||
func DialHvsock(ctx context.Context, addr *HvsockAddr) (*HvsockConn, error) { | |||
sock, err := newHvSocket() | |||
if err != nil { | |||
return nil, err | |||
} | |||
defer func() { | |||
if sock != nil { | |||
sock.Close() | |||
} | |||
}() | |||
c, err := sock.prepareIo() | |||
if err != nil { | |||
return nil, err | |||
} | |||
defer sock.wg.Done() | |||
var bytes uint32 | |||
err = windows.ConnectEx(windows.Handle(sock.handle), sa, nil, 0, &bytes, &c.o) | |||
_, err = sock.asyncIo(ctx, c, nil, bytes, err) | |||
if err != nil { | |||
return nil, err | |||
} | |||
conn := &HvsockConn{ | |||
sock: sock, | |||
remote: *addr, | |||
} | |||
sock = nil | |||
return conn, nil | |||
} | |||
*/ | |||
func (conn *HvsockConn) opErr(op string, err error) error { | |||
return &net.OpError{Op: op, Net: "hvsock", Source: &conn.local, Addr: &conn.remote, Err: err} | |||
} | |||
func (conn *HvsockConn) Read(b []byte) (int, error) { | |||
c, err := conn.sock.prepareIo() | |||
if err != nil { | |||
return 0, conn.opErr("read", err) | |||
} | |||
defer conn.sock.wg.Done() | |||
buf := syscall.WSABuf{Buf: &b[0], Len: uint32(len(b))} | |||
var flags, bytes uint32 | |||
err = syscall.WSARecv(conn.sock.handle, &buf, 1, &bytes, &flags, &c.o, nil) | |||
n, err := conn.sock.asyncIo(c, &conn.sock.readDeadline, bytes, err) | |||
if err != nil { | |||
if _, ok := err.(syscall.Errno); ok { | |||
err = os.NewSyscallError("wsarecv", err) | |||
} | |||
return 0, conn.opErr("read", err) | |||
} else if n == 0 { | |||
err = io.EOF | |||
} | |||
return n, err | |||
} | |||
func (conn *HvsockConn) Write(b []byte) (int, error) { | |||
t := 0 | |||
for len(b) != 0 { | |||
n, err := conn.write(b) | |||
if err != nil { | |||
return t + n, err | |||
} | |||
t += n | |||
b = b[n:] | |||
} | |||
return t, nil | |||
} | |||
func (conn *HvsockConn) write(b []byte) (int, error) { | |||
c, err := conn.sock.prepareIo() | |||
if err != nil { | |||
return 0, conn.opErr("write", err) | |||
} | |||
defer conn.sock.wg.Done() | |||
buf := syscall.WSABuf{Buf: &b[0], Len: uint32(len(b))} | |||
var bytes uint32 | |||
err = syscall.WSASend(conn.sock.handle, &buf, 1, &bytes, 0, &c.o, nil) | |||
n, err := conn.sock.asyncIo(c, &conn.sock.writeDeadline, bytes, err) | |||
if err != nil { | |||
if _, ok := err.(syscall.Errno); ok { | |||
err = os.NewSyscallError("wsasend", err) | |||
} | |||
return 0, conn.opErr("write", err) | |||
} | |||
return n, err | |||
} | |||
// Close closes the socket connection, failing any pending read or write calls. | |||
func (conn *HvsockConn) Close() error { | |||
return conn.sock.Close() | |||
} | |||
func (conn *HvsockConn) IsClosed() bool { | |||
return conn.sock.IsClosed() | |||
} | |||
func (conn *HvsockConn) shutdown(how int) error { | |||
if conn.IsClosed() { | |||
return ErrFileClosed | |||
} | |||
err := syscall.Shutdown(conn.sock.handle, how) | |||
if err != nil { | |||
return os.NewSyscallError("shutdown", err) | |||
} | |||
return nil | |||
} | |||
// CloseRead shuts down the read end of the socket, preventing future read operations. | |||
func (conn *HvsockConn) CloseRead() error { | |||
err := conn.shutdown(syscall.SHUT_RD) | |||
if err != nil { | |||
return conn.opErr("close", err) | |||
} | |||
return nil | |||
} | |||
// CloseWrite shuts down the write end of the socket, preventing future write operations and | |||
// notifying the other endpoint that no more data will be written. | |||
func (conn *HvsockConn) CloseWrite() error { | |||
err := conn.shutdown(syscall.SHUT_WR) | |||
if err != nil { | |||
return conn.opErr("close", err) | |||
} | |||
return nil | |||
} | |||
// LocalAddr returns the local address of the connection. | |||
func (conn *HvsockConn) LocalAddr() net.Addr { | |||
return &conn.local | |||
} | |||
// RemoteAddr returns the remote address of the connection. | |||
func (conn *HvsockConn) RemoteAddr() net.Addr { | |||
return &conn.remote | |||
} | |||
// SetDeadline implements the net.Conn SetDeadline method. | |||
func (conn *HvsockConn) SetDeadline(t time.Time) error { | |||
conn.SetReadDeadline(t) | |||
conn.SetWriteDeadline(t) | |||
return nil | |||
} | |||
// SetReadDeadline implements the net.Conn SetReadDeadline method. | |||
func (conn *HvsockConn) SetReadDeadline(t time.Time) error { | |||
return conn.sock.SetReadDeadline(t) | |||
} | |||
// SetWriteDeadline implements the net.Conn SetWriteDeadline method. | |||
func (conn *HvsockConn) SetWriteDeadline(t time.Time) error { | |||
return conn.sock.SetWriteDeadline(t) | |||
} |
@@ -0,0 +1,517 @@ | |||
// +build windows | |||
package winio | |||
import ( | |||
"context" | |||
"errors" | |||
"fmt" | |||
"io" | |||
"net" | |||
"os" | |||
"runtime" | |||
"syscall" | |||
"time" | |||
"unsafe" | |||
) | |||
//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 | |||
//sys ntCreateNamedPipeFile(pipe *syscall.Handle, access uint32, oa *objectAttributes, iosb *ioStatusBlock, share uint32, disposition uint32, options uint32, typ uint32, readMode uint32, completionMode uint32, maxInstances uint32, inboundQuota uint32, outputQuota uint32, timeout *int64) (status ntstatus) = ntdll.NtCreateNamedPipeFile | |||
//sys rtlNtStatusToDosError(status ntstatus) (winerr error) = ntdll.RtlNtStatusToDosErrorNoTeb | |||
//sys rtlDosPathNameToNtPathName(name *uint16, ntName *unicodeString, filePart uintptr, reserved uintptr) (status ntstatus) = ntdll.RtlDosPathNameToNtPathName_U | |||
//sys rtlDefaultNpAcl(dacl *uintptr) (status ntstatus) = ntdll.RtlDefaultNpAcl | |||
type ioStatusBlock struct { | |||
Status, Information uintptr | |||
} | |||
type objectAttributes struct { | |||
Length uintptr | |||
RootDirectory uintptr | |||
ObjectName *unicodeString | |||
Attributes uintptr | |||
SecurityDescriptor *securityDescriptor | |||
SecurityQoS uintptr | |||
} | |||
type unicodeString struct { | |||
Length uint16 | |||
MaximumLength uint16 | |||
Buffer uintptr | |||
} | |||
type securityDescriptor struct { | |||
Revision byte | |||
Sbz1 byte | |||
Control uint16 | |||
Owner uintptr | |||
Group uintptr | |||
Sacl uintptr | |||
Dacl uintptr | |||
} | |||
type ntstatus int32 | |||
func (status ntstatus) Err() error { | |||
if status >= 0 { | |||
return nil | |||
} | |||
return rtlNtStatusToDosError(status) | |||
} | |||
const ( | |||
cERROR_PIPE_BUSY = syscall.Errno(231) | |||
cERROR_NO_DATA = syscall.Errno(232) | |||
cERROR_PIPE_CONNECTED = syscall.Errno(535) | |||
cERROR_SEM_TIMEOUT = syscall.Errno(121) | |||
cSECURITY_SQOS_PRESENT = 0x100000 | |||
cSECURITY_ANONYMOUS = 0 | |||
cPIPE_TYPE_MESSAGE = 4 | |||
cPIPE_READMODE_MESSAGE = 2 | |||
cFILE_OPEN = 1 | |||
cFILE_CREATE = 2 | |||
cFILE_PIPE_MESSAGE_TYPE = 1 | |||
cFILE_PIPE_REJECT_REMOTE_CLIENTS = 2 | |||
cSE_DACL_PRESENT = 4 | |||
) | |||
var ( | |||
// ErrPipeListenerClosed is returned for pipe operations on listeners that have been closed. | |||
// This error should match net.errClosing since docker takes a dependency on its text. | |||
ErrPipeListenerClosed = errors.New("use of closed network connection") | |||
errPipeWriteClosed = errors.New("pipe has been closed for write") | |||
) | |||
type win32Pipe struct { | |||
*win32File | |||
path string | |||
} | |||
type win32MessageBytePipe struct { | |||
win32Pipe | |||
writeClosed bool | |||
readEOF bool | |||
} | |||
type pipeAddress string | |||
func (f *win32Pipe) LocalAddr() net.Addr { | |||
return pipeAddress(f.path) | |||
} | |||
func (f *win32Pipe) RemoteAddr() net.Addr { | |||
return pipeAddress(f.path) | |||
} | |||
func (f *win32Pipe) SetDeadline(t time.Time) error { | |||
f.SetReadDeadline(t) | |||
f.SetWriteDeadline(t) | |||
return nil | |||
} | |||
// CloseWrite closes the write side of a message pipe in byte mode. | |||
func (f *win32MessageBytePipe) CloseWrite() error { | |||
if f.writeClosed { | |||
return errPipeWriteClosed | |||
} | |||
err := f.win32File.Flush() | |||
if err != nil { | |||
return err | |||
} | |||
_, err = f.win32File.Write(nil) | |||
if err != nil { | |||
return err | |||
} | |||
f.writeClosed = true | |||
return nil | |||
} | |||
// Write writes bytes to a message pipe in byte mode. Zero-byte writes are ignored, since | |||
// they are used to implement CloseWrite(). | |||
func (f *win32MessageBytePipe) Write(b []byte) (int, error) { | |||
if f.writeClosed { | |||
return 0, errPipeWriteClosed | |||
} | |||
if len(b) == 0 { | |||
return 0, nil | |||
} | |||
return f.win32File.Write(b) | |||
} | |||
// Read reads bytes from a message pipe in byte mode. A read of a zero-byte message on a message | |||
// mode pipe will return io.EOF, as will all subsequent reads. | |||
func (f *win32MessageBytePipe) Read(b []byte) (int, error) { | |||
if f.readEOF { | |||
return 0, io.EOF | |||
} | |||
n, err := f.win32File.Read(b) | |||
if err == io.EOF { | |||
// If this was the result of a zero-byte read, then | |||
// it is possible that the read was due to a zero-size | |||
// message. Since we are simulating CloseWrite with a | |||
// zero-byte message, ensure that all future Read() calls | |||
// also return EOF. | |||
f.readEOF = true | |||
} else if err == syscall.ERROR_MORE_DATA { | |||
// ERROR_MORE_DATA indicates that the pipe's read mode is message mode | |||
// and the message still has more bytes. Treat this as a success, since | |||
// this package presents all named pipes as byte streams. | |||
err = nil | |||
} | |||
return n, err | |||
} | |||
func (s pipeAddress) Network() string { | |||
return "pipe" | |||
} | |||
func (s pipeAddress) String() string { | |||
return string(s) | |||
} | |||
// 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) { | |||
for { | |||
select { | |||
case <-ctx.Done(): | |||
return syscall.Handle(0), ctx.Err() | |||
default: | |||
h, err := createFile(*path, access, 0, nil, syscall.OPEN_EXISTING, syscall.FILE_FLAG_OVERLAPPED|cSECURITY_SQOS_PRESENT|cSECURITY_ANONYMOUS, 0) | |||
if err == nil { | |||
return h, nil | |||
} | |||
if err != cERROR_PIPE_BUSY { | |||
return h, &os.PathError{Err: err, Op: "open", Path: *path} | |||
} | |||
// Wait 10 msec and try again. This is a rather simplistic | |||
// view, as we always try each 10 milliseconds. | |||
time.Sleep(10 * time.Millisecond) | |||
} | |||
} | |||
} | |||
// DialPipe connects to a named pipe by path, timing out if the connection | |||
// takes longer than the specified duration. If timeout is nil, then we use | |||
// a default timeout of 2 seconds. (We do not use WaitNamedPipe.) | |||
func DialPipe(path string, timeout *time.Duration) (net.Conn, error) { | |||
var absTimeout time.Time | |||
if timeout != nil { | |||
absTimeout = time.Now().Add(*timeout) | |||
} else { | |||
absTimeout = time.Now().Add(2 * time.Second) | |||
} | |||
ctx, _ := context.WithDeadline(context.Background(), absTimeout) | |||
conn, err := DialPipeContext(ctx, path) | |||
if err == context.DeadlineExceeded { | |||
return nil, ErrTimeout | |||
} | |||
return conn, err | |||
} | |||
// DialPipeContext attempts to connect to a named pipe by `path` until `ctx` | |||
// cancellation or timeout. | |||
func DialPipeContext(ctx context.Context, path string) (net.Conn, error) { | |||
return DialPipeAccess(ctx, path, syscall.GENERIC_READ|syscall.GENERIC_WRITE) | |||
} | |||
// DialPipeAccess attempts to connect to a named pipe by `path` with `access` until `ctx` | |||
// cancellation or timeout. | |||
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) | |||
if err != nil { | |||
return nil, err | |||
} | |||
var flags uint32 | |||
err = getNamedPipeInfo(h, &flags, nil, nil, nil) | |||
if err != nil { | |||
return nil, err | |||
} | |||
f, err := makeWin32File(h) | |||
if err != nil { | |||
syscall.Close(h) | |||
return nil, err | |||
} | |||
// If the pipe is in message mode, return a message byte pipe, which | |||
// supports CloseWrite(). | |||
if flags&cPIPE_TYPE_MESSAGE != 0 { | |||
return &win32MessageBytePipe{ | |||
win32Pipe: win32Pipe{win32File: f, path: path}, | |||
}, nil | |||
} | |||
return &win32Pipe{win32File: f, path: path}, nil | |||
} | |||
type acceptResponse struct { | |||
f *win32File | |||
err error | |||
} | |||
type win32PipeListener struct { | |||
firstHandle syscall.Handle | |||
path string | |||
config PipeConfig | |||
acceptCh chan (chan acceptResponse) | |||
closeCh chan int | |||
doneCh chan int | |||
} | |||
func makeServerPipeHandle(path string, sd []byte, c *PipeConfig, first bool) (syscall.Handle, error) { | |||
path16, err := syscall.UTF16FromString(path) | |||
if err != nil { | |||
return 0, &os.PathError{Op: "open", Path: path, Err: err} | |||
} | |||
var oa objectAttributes | |||
oa.Length = unsafe.Sizeof(oa) | |||
var ntPath unicodeString | |||
if err := rtlDosPathNameToNtPathName(&path16[0], &ntPath, 0, 0).Err(); err != nil { | |||
return 0, &os.PathError{Op: "open", Path: path, Err: err} | |||
} | |||
defer localFree(ntPath.Buffer) | |||
oa.ObjectName = &ntPath | |||
// The security descriptor is only needed for the first pipe. | |||
if first { | |||
if sd != nil { | |||
len := uint32(len(sd)) | |||
sdb := localAlloc(0, len) | |||
defer localFree(sdb) | |||
copy((*[0xffff]byte)(unsafe.Pointer(sdb))[:], sd) | |||
oa.SecurityDescriptor = (*securityDescriptor)(unsafe.Pointer(sdb)) | |||
} else { | |||
// Construct the default named pipe security descriptor. | |||
var dacl uintptr | |||
if err := rtlDefaultNpAcl(&dacl).Err(); err != nil { | |||
return 0, fmt.Errorf("getting default named pipe ACL: %s", err) | |||
} | |||
defer localFree(dacl) | |||
sdb := &securityDescriptor{ | |||
Revision: 1, | |||
Control: cSE_DACL_PRESENT, | |||
Dacl: dacl, | |||
} | |||
oa.SecurityDescriptor = sdb | |||
} | |||
} | |||
typ := uint32(cFILE_PIPE_REJECT_REMOTE_CLIENTS) | |||
if c.MessageMode { | |||
typ |= cFILE_PIPE_MESSAGE_TYPE | |||
} | |||
disposition := uint32(cFILE_OPEN) | |||
access := uint32(syscall.GENERIC_READ | syscall.GENERIC_WRITE | syscall.SYNCHRONIZE) | |||
if first { | |||
disposition = cFILE_CREATE | |||
// By not asking for read or write access, the named pipe file system | |||
// will put this pipe into an initially disconnected state, blocking | |||
// client connections until the next call with first == false. | |||
access = syscall.SYNCHRONIZE | |||
} | |||
timeout := int64(-50 * 10000) // 50ms | |||
var ( | |||
h syscall.Handle | |||
iosb ioStatusBlock | |||
) | |||
err = ntCreateNamedPipeFile(&h, access, &oa, &iosb, syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE, disposition, 0, typ, 0, 0, 0xffffffff, uint32(c.InputBufferSize), uint32(c.OutputBufferSize), &timeout).Err() | |||
if err != nil { | |||
return 0, &os.PathError{Op: "open", Path: path, Err: err} | |||
} | |||
runtime.KeepAlive(ntPath) | |||
return h, nil | |||
} | |||
func (l *win32PipeListener) makeServerPipe() (*win32File, error) { | |||
h, err := makeServerPipeHandle(l.path, nil, &l.config, false) | |||
if err != nil { | |||
return nil, err | |||
} | |||
f, err := makeWin32File(h) | |||
if err != nil { | |||
syscall.Close(h) | |||
return nil, err | |||
} | |||
return f, nil | |||
} | |||
func (l *win32PipeListener) makeConnectedServerPipe() (*win32File, error) { | |||
p, err := l.makeServerPipe() | |||
if err != nil { | |||
return nil, err | |||
} | |||
// Wait for the client to connect. | |||
ch := make(chan error) | |||
go func(p *win32File) { | |||
ch <- connectPipe(p) | |||
}(p) | |||
select { | |||
case err = <-ch: | |||
if err != nil { | |||
p.Close() | |||
p = nil | |||
} | |||
case <-l.closeCh: | |||
// Abort the connect request by closing the handle. | |||
p.Close() | |||
p = nil | |||
err = <-ch | |||
if err == nil || err == ErrFileClosed { | |||
err = ErrPipeListenerClosed | |||
} | |||
} | |||
return p, err | |||
} | |||
func (l *win32PipeListener) listenerRoutine() { | |||
closed := false | |||
for !closed { | |||
select { | |||
case <-l.closeCh: | |||
closed = true | |||
case responseCh := <-l.acceptCh: | |||
var ( | |||
p *win32File | |||
err error | |||
) | |||
for { | |||
p, err = l.makeConnectedServerPipe() | |||
// If the connection was immediately closed by the client, try | |||
// again. | |||
if err != cERROR_NO_DATA { | |||
break | |||
} | |||
} | |||
responseCh <- acceptResponse{p, err} | |||
closed = err == ErrPipeListenerClosed | |||
} | |||
} | |||
syscall.Close(l.firstHandle) | |||
l.firstHandle = 0 | |||
// Notify Close() and Accept() callers that the handle has been closed. | |||
close(l.doneCh) | |||
} | |||
// PipeConfig contain configuration for the pipe listener. | |||
type PipeConfig struct { | |||
// SecurityDescriptor contains a Windows security descriptor in SDDL format. | |||
SecurityDescriptor string | |||
// MessageMode determines whether the pipe is in byte or message mode. In either | |||
// case the pipe is read in byte mode by default. The only practical difference in | |||
// this implementation is that CloseWrite() is only supported for message mode pipes; | |||
// CloseWrite() is implemented as a zero-byte write, but zero-byte writes are only | |||
// transferred to the reader (and returned as io.EOF in this implementation) | |||
// when the pipe is in message mode. | |||
MessageMode bool | |||
// InputBufferSize specifies the size of the input buffer, in bytes. | |||
InputBufferSize int32 | |||
// OutputBufferSize specifies the size of the output buffer, in bytes. | |||
OutputBufferSize int32 | |||
} | |||
// ListenPipe creates a listener on a Windows named pipe path, e.g. \\.\pipe\mypipe. | |||
// The pipe must not already exist. | |||
func ListenPipe(path string, c *PipeConfig) (net.Listener, error) { | |||
var ( | |||
sd []byte | |||
err error | |||
) | |||
if c == nil { | |||
c = &PipeConfig{} | |||
} | |||
if c.SecurityDescriptor != "" { | |||
sd, err = SddlToSecurityDescriptor(c.SecurityDescriptor) | |||
if err != nil { | |||
return nil, err | |||
} | |||
} | |||
h, err := makeServerPipeHandle(path, sd, c, true) | |||
if err != nil { | |||
return nil, err | |||
} | |||
l := &win32PipeListener{ | |||
firstHandle: h, | |||
path: path, | |||
config: *c, | |||
acceptCh: make(chan (chan acceptResponse)), | |||
closeCh: make(chan int), | |||
doneCh: make(chan int), | |||
} | |||
go l.listenerRoutine() | |||
return l, nil | |||
} | |||
func connectPipe(p *win32File) error { | |||
c, err := p.prepareIo() | |||
if err != nil { | |||
return err | |||
} | |||
defer p.wg.Done() | |||
err = connectNamedPipe(p.handle, &c.o) | |||
_, err = p.asyncIo(c, nil, 0, err) | |||
if err != nil && err != cERROR_PIPE_CONNECTED { | |||
return err | |||
} | |||
return nil | |||
} | |||
func (l *win32PipeListener) Accept() (net.Conn, error) { | |||
ch := make(chan acceptResponse) | |||
select { | |||
case l.acceptCh <- ch: | |||
response := <-ch | |||
err := response.err | |||
if err != nil { | |||
return nil, err | |||
} | |||
if l.config.MessageMode { | |||
return &win32MessageBytePipe{ | |||
win32Pipe: win32Pipe{win32File: response.f, path: l.path}, | |||
}, nil | |||
} | |||
return &win32Pipe{win32File: response.f, path: l.path}, nil | |||
case <-l.doneCh: | |||
return nil, ErrPipeListenerClosed | |||
} | |||
} | |||
func (l *win32PipeListener) Close() error { | |||
select { | |||
case l.closeCh <- 1: | |||
<-l.doneCh | |||
case <-l.doneCh: | |||
} | |||
return nil | |||
} | |||
func (l *win32PipeListener) Addr() net.Addr { | |||
return pipeAddress(l.path) | |||
} |
@@ -0,0 +1,228 @@ | |||
// +build windows | |||
// Package guid provides a GUID type. The backing structure for a GUID is | |||
// identical to that used by the golang.org/x/sys/windows GUID type. | |||
// There are two main binary encodings used for a GUID, the big-endian encoding, | |||
// and the Windows (mixed-endian) encoding. See here for details: | |||
// https://en.wikipedia.org/wiki/Universally_unique_identifier#Encoding | |||
package guid | |||
import ( | |||
"crypto/rand" | |||
"crypto/sha1" | |||
"encoding" | |||
"encoding/binary" | |||
"fmt" | |||
"strconv" | |||
) | |||
// Variant specifies which GUID variant (or "type") of the GUID. It determines | |||
// how the entirety of the rest of the GUID is interpreted. | |||
type Variant uint8 | |||
// The variants specified by RFC 4122. | |||
const ( | |||
// VariantUnknown specifies a GUID variant which does not conform to one of | |||
// the variant encodings specified in RFC 4122. | |||
VariantUnknown Variant = iota | |||
VariantNCS | |||
VariantRFC4122 | |||
VariantMicrosoft | |||
VariantFuture | |||
) | |||
// Version specifies how the bits in the GUID were generated. For instance, a | |||
// version 4 GUID is randomly generated, and a version 5 is generated from the | |||
// hash of an input string. | |||
type Version uint8 | |||
var _ = (encoding.TextMarshaler)(GUID{}) | |||
var _ = (encoding.TextUnmarshaler)(&GUID{}) | |||
// NewV4 returns a new version 4 (pseudorandom) GUID, as defined by RFC 4122. | |||
func NewV4() (GUID, error) { | |||
var b [16]byte | |||
if _, err := rand.Read(b[:]); err != nil { | |||
return GUID{}, err | |||
} | |||
g := FromArray(b) | |||
g.setVersion(4) // Version 4 means randomly generated. | |||
g.setVariant(VariantRFC4122) | |||
return g, nil | |||
} | |||
// NewV5 returns a new version 5 (generated from a string via SHA-1 hashing) | |||
// GUID, as defined by RFC 4122. The RFC is unclear on the encoding of the name, | |||
// and the sample code treats it as a series of bytes, so we do the same here. | |||
// | |||
// Some implementations, such as those found on Windows, treat the name as a | |||
// big-endian UTF16 stream of bytes. If that is desired, the string can be | |||
// encoded as such before being passed to this function. | |||
func NewV5(namespace GUID, name []byte) (GUID, error) { | |||
b := sha1.New() | |||
namespaceBytes := namespace.ToArray() | |||
b.Write(namespaceBytes[:]) | |||
b.Write(name) | |||
a := [16]byte{} | |||
copy(a[:], b.Sum(nil)) | |||
g := FromArray(a) | |||
g.setVersion(5) // Version 5 means generated from a string. | |||
g.setVariant(VariantRFC4122) | |||
return g, nil | |||
} | |||
func fromArray(b [16]byte, order binary.ByteOrder) GUID { | |||
var g GUID | |||
g.Data1 = order.Uint32(b[0:4]) | |||
g.Data2 = order.Uint16(b[4:6]) | |||
g.Data3 = order.Uint16(b[6:8]) | |||
copy(g.Data4[:], b[8:16]) | |||
return g | |||
} | |||
func (g GUID) toArray(order binary.ByteOrder) [16]byte { | |||
b := [16]byte{} | |||
order.PutUint32(b[0:4], g.Data1) | |||
order.PutUint16(b[4:6], g.Data2) | |||
order.PutUint16(b[6:8], g.Data3) | |||
copy(b[8:16], g.Data4[:]) | |||
return b | |||
} | |||
// FromArray constructs a GUID from a big-endian encoding array of 16 bytes. | |||
func FromArray(b [16]byte) GUID { | |||
return fromArray(b, binary.BigEndian) | |||
} | |||
// ToArray returns an array of 16 bytes representing the GUID in big-endian | |||
// encoding. | |||
func (g GUID) ToArray() [16]byte { | |||
return g.toArray(binary.BigEndian) | |||
} | |||
// FromWindowsArray constructs a GUID from a Windows encoding array of bytes. | |||
func FromWindowsArray(b [16]byte) GUID { | |||
return fromArray(b, binary.LittleEndian) | |||
} | |||
// ToWindowsArray returns an array of 16 bytes representing the GUID in Windows | |||
// encoding. | |||
func (g GUID) ToWindowsArray() [16]byte { | |||
return g.toArray(binary.LittleEndian) | |||
} | |||
func (g GUID) String() string { | |||
return fmt.Sprintf( | |||
"%08x-%04x-%04x-%04x-%012x", | |||
g.Data1, | |||
g.Data2, | |||
g.Data3, | |||
g.Data4[:2], | |||
g.Data4[2:]) | |||
} | |||
// FromString parses a string containing a GUID and returns the GUID. The only | |||
// format currently supported is the `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx` | |||
// format. | |||
func FromString(s string) (GUID, error) { | |||
if len(s) != 36 { | |||
return GUID{}, fmt.Errorf("invalid GUID %q", s) | |||
} | |||
if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' { | |||
return GUID{}, fmt.Errorf("invalid GUID %q", s) | |||
} | |||
var g GUID | |||
data1, err := strconv.ParseUint(s[0:8], 16, 32) | |||
if err != nil { | |||
return GUID{}, fmt.Errorf("invalid GUID %q", s) | |||
} | |||
g.Data1 = uint32(data1) | |||
data2, err := strconv.ParseUint(s[9:13], 16, 16) | |||
if err != nil { | |||
return GUID{}, fmt.Errorf("invalid GUID %q", s) | |||
} | |||
g.Data2 = uint16(data2) | |||
data3, err := strconv.ParseUint(s[14:18], 16, 16) | |||
if err != nil { | |||
return GUID{}, fmt.Errorf("invalid GUID %q", s) | |||
} | |||
g.Data3 = uint16(data3) | |||
for i, x := range []int{19, 21, 24, 26, 28, 30, 32, 34} { | |||
v, err := strconv.ParseUint(s[x:x+2], 16, 8) | |||
if err != nil { | |||
return GUID{}, fmt.Errorf("invalid GUID %q", s) | |||
} | |||
g.Data4[i] = uint8(v) | |||
} | |||
return g, nil | |||
} | |||
func (g *GUID) setVariant(v Variant) { | |||
d := g.Data4[0] | |||
switch v { | |||
case VariantNCS: | |||
d = (d & 0x7f) | |||
case VariantRFC4122: | |||
d = (d & 0x3f) | 0x80 | |||
case VariantMicrosoft: | |||
d = (d & 0x1f) | 0xc0 | |||
case VariantFuture: | |||
d = (d & 0x0f) | 0xe0 | |||
case VariantUnknown: | |||
fallthrough | |||
default: | |||
panic(fmt.Sprintf("invalid variant: %d", v)) | |||
} | |||
g.Data4[0] = d | |||
} | |||
// Variant returns the GUID variant, as defined in RFC 4122. | |||
func (g GUID) Variant() Variant { | |||
b := g.Data4[0] | |||
if b&0x80 == 0 { | |||
return VariantNCS | |||
} else if b&0xc0 == 0x80 { | |||
return VariantRFC4122 | |||
} else if b&0xe0 == 0xc0 { | |||
return VariantMicrosoft | |||
} else if b&0xe0 == 0xe0 { | |||
return VariantFuture | |||
} | |||
return VariantUnknown | |||
} | |||
func (g *GUID) setVersion(v Version) { | |||
g.Data3 = (g.Data3 & 0x0fff) | (uint16(v) << 12) | |||
} | |||
// Version returns the GUID version, as defined in RFC 4122. | |||
func (g GUID) Version() Version { | |||
return Version((g.Data3 & 0xF000) >> 12) | |||
} | |||
// MarshalText returns the textual representation of the GUID. | |||
func (g GUID) MarshalText() ([]byte, error) { | |||
return []byte(g.String()), nil | |||
} | |||
// UnmarshalText takes the textual representation of a GUID, and unmarhals it | |||
// into this GUID. | |||
func (g *GUID) UnmarshalText(text []byte) error { | |||
g2, err := FromString(string(text)) | |||
if err != nil { | |||
return err | |||
} | |||
*g = g2 | |||
return nil | |||
} |
@@ -0,0 +1,15 @@ | |||
// +build !windows | |||
package guid | |||
// GUID represents a GUID/UUID. It has the same structure as | |||
// golang.org/x/sys/windows.GUID so that it can be used with functions expecting | |||
// that type. It is defined as its own type as that is only available to builds | |||
// targeted at `windows`. The representation matches that used by native Windows | |||
// code. | |||
type GUID struct { | |||
Data1 uint32 | |||
Data2 uint16 | |||
Data3 uint16 | |||
Data4 [8]byte | |||
} |
@@ -0,0 +1,10 @@ | |||
package guid | |||
import "golang.org/x/sys/windows" | |||
// GUID represents a GUID/UUID. It has the same structure as | |||
// golang.org/x/sys/windows.GUID so that it can be used with functions expecting | |||
// that type. It is defined as its own type so that stringification and | |||
// marshaling can be supported. The representation matches that used by native | |||
// Windows code. | |||
type GUID windows.GUID |
@@ -0,0 +1,203 @@ | |||
// +build windows | |||
package winio | |||
import ( | |||
"bytes" | |||
"encoding/binary" | |||
"fmt" | |||
"runtime" | |||
"sync" | |||
"syscall" | |||
"unicode/utf16" | |||
"golang.org/x/sys/windows" | |||
) | |||
//sys adjustTokenPrivileges(token windows.Token, releaseAll bool, input *byte, outputSize uint32, output *byte, requiredSize *uint32) (success bool, err error) [true] = advapi32.AdjustTokenPrivileges | |||
//sys impersonateSelf(level uint32) (err error) = advapi32.ImpersonateSelf | |||
//sys revertToSelf() (err error) = advapi32.RevertToSelf | |||
//sys openThreadToken(thread syscall.Handle, accessMask uint32, openAsSelf bool, token *windows.Token) (err error) = advapi32.OpenThreadToken | |||
//sys getCurrentThread() (h syscall.Handle) = GetCurrentThread | |||
//sys lookupPrivilegeValue(systemName string, name string, luid *uint64) (err error) = advapi32.LookupPrivilegeValueW | |||
//sys lookupPrivilegeName(systemName string, luid *uint64, buffer *uint16, size *uint32) (err error) = advapi32.LookupPrivilegeNameW | |||
//sys lookupPrivilegeDisplayName(systemName string, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) = advapi32.LookupPrivilegeDisplayNameW | |||
const ( | |||
SE_PRIVILEGE_ENABLED = 2 | |||
ERROR_NOT_ALL_ASSIGNED syscall.Errno = 1300 | |||
SeBackupPrivilege = "SeBackupPrivilege" | |||
SeRestorePrivilege = "SeRestorePrivilege" | |||
SeSecurityPrivilege = "SeSecurityPrivilege" | |||
) | |||
const ( | |||
securityAnonymous = iota | |||
securityIdentification | |||
securityImpersonation | |||
securityDelegation | |||
) | |||
var ( | |||
privNames = make(map[string]uint64) | |||
privNameMutex sync.Mutex | |||
) | |||
// PrivilegeError represents an error enabling privileges. | |||
type PrivilegeError struct { | |||
privileges []uint64 | |||
} | |||
func (e *PrivilegeError) Error() string { | |||
s := "" | |||
if len(e.privileges) > 1 { | |||
s = "Could not enable privileges " | |||
} else { | |||
s = "Could not enable privilege " | |||
} | |||
for i, p := range e.privileges { | |||
if i != 0 { | |||
s += ", " | |||
} | |||
s += `"` | |||
s += getPrivilegeName(p) | |||
s += `"` | |||
} | |||
return s | |||
} | |||
// RunWithPrivilege enables a single privilege for a function call. | |||
func RunWithPrivilege(name string, fn func() error) error { | |||
return RunWithPrivileges([]string{name}, fn) | |||
} | |||
// RunWithPrivileges enables privileges for a function call. | |||
func RunWithPrivileges(names []string, fn func() error) error { | |||
privileges, err := mapPrivileges(names) | |||
if err != nil { | |||
return err | |||
} | |||
runtime.LockOSThread() | |||
defer runtime.UnlockOSThread() | |||
token, err := newThreadToken() | |||
if err != nil { | |||
return err | |||
} | |||
defer releaseThreadToken(token) | |||
err = adjustPrivileges(token, privileges, SE_PRIVILEGE_ENABLED) | |||
if err != nil { | |||
return err | |||
} | |||
return fn() | |||
} | |||
func mapPrivileges(names []string) ([]uint64, error) { | |||
var privileges []uint64 | |||
privNameMutex.Lock() | |||
defer privNameMutex.Unlock() | |||
for _, name := range names { | |||
p, ok := privNames[name] | |||
if !ok { | |||
err := lookupPrivilegeValue("", name, &p) | |||
if err != nil { | |||
return nil, err | |||
} | |||
privNames[name] = p | |||
} | |||
privileges = append(privileges, p) | |||
} | |||
return privileges, nil | |||
} | |||
// EnableProcessPrivileges enables privileges globally for the process. | |||
func EnableProcessPrivileges(names []string) error { | |||
return enableDisableProcessPrivilege(names, SE_PRIVILEGE_ENABLED) | |||
} | |||
// DisableProcessPrivileges disables privileges globally for the process. | |||
func DisableProcessPrivileges(names []string) error { | |||
return enableDisableProcessPrivilege(names, 0) | |||
} | |||
func enableDisableProcessPrivilege(names []string, action uint32) error { | |||
privileges, err := mapPrivileges(names) | |||
if err != nil { | |||
return err | |||
} | |||
p, _ := windows.GetCurrentProcess() | |||
var token windows.Token | |||
err = windows.OpenProcessToken(p, windows.TOKEN_ADJUST_PRIVILEGES|windows.TOKEN_QUERY, &token) | |||
if err != nil { | |||
return err | |||
} | |||
defer token.Close() | |||
return adjustPrivileges(token, privileges, action) | |||
} | |||
func adjustPrivileges(token windows.Token, privileges []uint64, action uint32) error { | |||
var b bytes.Buffer | |||
binary.Write(&b, binary.LittleEndian, uint32(len(privileges))) | |||
for _, p := range privileges { | |||
binary.Write(&b, binary.LittleEndian, p) | |||
binary.Write(&b, binary.LittleEndian, action) | |||
} | |||
prevState := make([]byte, b.Len()) | |||
reqSize := uint32(0) | |||
success, err := adjustTokenPrivileges(token, false, &b.Bytes()[0], uint32(len(prevState)), &prevState[0], &reqSize) | |||
if !success { | |||
return err | |||
} | |||
if err == ERROR_NOT_ALL_ASSIGNED { | |||
return &PrivilegeError{privileges} | |||
} | |||
return nil | |||
} | |||
func getPrivilegeName(luid uint64) string { | |||
var nameBuffer [256]uint16 | |||
bufSize := uint32(len(nameBuffer)) | |||
err := lookupPrivilegeName("", &luid, &nameBuffer[0], &bufSize) | |||
if err != nil { | |||
return fmt.Sprintf("<unknown privilege %d>", luid) | |||
} | |||
var displayNameBuffer [256]uint16 | |||
displayBufSize := uint32(len(displayNameBuffer)) | |||
var langID uint32 | |||
err = lookupPrivilegeDisplayName("", &nameBuffer[0], &displayNameBuffer[0], &displayBufSize, &langID) | |||
if err != nil { | |||
return fmt.Sprintf("<unknown privilege %s>", string(utf16.Decode(nameBuffer[:bufSize]))) | |||
} | |||
return string(utf16.Decode(displayNameBuffer[:displayBufSize])) | |||
} | |||
func newThreadToken() (windows.Token, error) { | |||
err := impersonateSelf(securityImpersonation) | |||
if err != nil { | |||
return 0, err | |||
} | |||
var token windows.Token | |||
err = openThreadToken(getCurrentThread(), syscall.TOKEN_ADJUST_PRIVILEGES|syscall.TOKEN_QUERY, false, &token) | |||
if err != nil { | |||
rerr := revertToSelf() | |||
if rerr != nil { | |||
panic(rerr) | |||
} | |||
return 0, err | |||
} | |||
return token, nil | |||
} | |||
func releaseThreadToken(h windows.Token) { | |||
err := revertToSelf() | |||
if err != nil { | |||
panic(err) | |||
} | |||
h.Close() | |||
} |
@@ -0,0 +1,128 @@ | |||
package winio | |||
import ( | |||
"bytes" | |||
"encoding/binary" | |||
"fmt" | |||
"strings" | |||
"unicode/utf16" | |||
"unsafe" | |||
) | |||
const ( | |||
reparseTagMountPoint = 0xA0000003 | |||
reparseTagSymlink = 0xA000000C | |||
) | |||
type reparseDataBuffer struct { | |||
ReparseTag uint32 | |||
ReparseDataLength uint16 | |||
Reserved uint16 | |||
SubstituteNameOffset uint16 | |||
SubstituteNameLength uint16 | |||
PrintNameOffset uint16 | |||
PrintNameLength uint16 | |||
} | |||
// ReparsePoint describes a Win32 symlink or mount point. | |||
type ReparsePoint struct { | |||
Target string | |||
IsMountPoint bool | |||
} | |||
// UnsupportedReparsePointError is returned when trying to decode a non-symlink or | |||
// mount point reparse point. | |||
type UnsupportedReparsePointError struct { | |||
Tag uint32 | |||
} | |||
func (e *UnsupportedReparsePointError) Error() string { | |||
return fmt.Sprintf("unsupported reparse point %x", e.Tag) | |||
} | |||
// DecodeReparsePoint decodes a Win32 REPARSE_DATA_BUFFER structure containing either a symlink | |||
// or a mount point. | |||
func DecodeReparsePoint(b []byte) (*ReparsePoint, error) { | |||
tag := binary.LittleEndian.Uint32(b[0:4]) | |||
return DecodeReparsePointData(tag, b[8:]) | |||
} | |||
func DecodeReparsePointData(tag uint32, b []byte) (*ReparsePoint, error) { | |||
isMountPoint := false | |||
switch tag { | |||
case reparseTagMountPoint: | |||
isMountPoint = true | |||
case reparseTagSymlink: | |||
default: | |||
return nil, &UnsupportedReparsePointError{tag} | |||
} | |||
nameOffset := 8 + binary.LittleEndian.Uint16(b[4:6]) | |||
if !isMountPoint { | |||
nameOffset += 4 | |||
} | |||
nameLength := binary.LittleEndian.Uint16(b[6:8]) | |||
name := make([]uint16, nameLength/2) | |||
err := binary.Read(bytes.NewReader(b[nameOffset:nameOffset+nameLength]), binary.LittleEndian, &name) | |||
if err != nil { | |||
return nil, err | |||
} | |||
return &ReparsePoint{string(utf16.Decode(name)), isMountPoint}, nil | |||
} | |||
func isDriveLetter(c byte) bool { | |||
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') | |||
} | |||
// EncodeReparsePoint encodes a Win32 REPARSE_DATA_BUFFER structure describing a symlink or | |||
// mount point. | |||
func EncodeReparsePoint(rp *ReparsePoint) []byte { | |||
// Generate an NT path and determine if this is a relative path. | |||
var ntTarget string | |||
relative := false | |||
if strings.HasPrefix(rp.Target, `\\?\`) { | |||
ntTarget = `\??\` + rp.Target[4:] | |||
} else if strings.HasPrefix(rp.Target, `\\`) { | |||
ntTarget = `\??\UNC\` + rp.Target[2:] | |||
} else if len(rp.Target) >= 2 && isDriveLetter(rp.Target[0]) && rp.Target[1] == ':' { | |||
ntTarget = `\??\` + rp.Target | |||
} else { | |||
ntTarget = rp.Target | |||
relative = true | |||
} | |||
// The paths must be NUL-terminated even though they are counted strings. | |||
target16 := utf16.Encode([]rune(rp.Target + "\x00")) | |||
ntTarget16 := utf16.Encode([]rune(ntTarget + "\x00")) | |||
size := int(unsafe.Sizeof(reparseDataBuffer{})) - 8 | |||
size += len(ntTarget16)*2 + len(target16)*2 | |||
tag := uint32(reparseTagMountPoint) | |||
if !rp.IsMountPoint { | |||
tag = reparseTagSymlink | |||
size += 4 // Add room for symlink flags | |||
} | |||
data := reparseDataBuffer{ | |||
ReparseTag: tag, | |||
ReparseDataLength: uint16(size), | |||
SubstituteNameOffset: 0, | |||
SubstituteNameLength: uint16((len(ntTarget16) - 1) * 2), | |||
PrintNameOffset: uint16(len(ntTarget16) * 2), | |||
PrintNameLength: uint16((len(target16) - 1) * 2), | |||
} | |||
var b bytes.Buffer | |||
binary.Write(&b, binary.LittleEndian, &data) | |||
if !rp.IsMountPoint { | |||
flags := uint32(0) | |||
if relative { | |||
flags |= 1 | |||
} | |||
binary.Write(&b, binary.LittleEndian, flags) | |||
} | |||
binary.Write(&b, binary.LittleEndian, ntTarget16) | |||
binary.Write(&b, binary.LittleEndian, target16) | |||
return b.Bytes() | |||
} |
@@ -0,0 +1,98 @@ | |||
// +build windows | |||
package winio | |||
import ( | |||
"syscall" | |||
"unsafe" | |||
) | |||
//sys lookupAccountName(systemName *uint16, accountName string, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) = advapi32.LookupAccountNameW | |||
//sys convertSidToStringSid(sid *byte, str **uint16) (err error) = advapi32.ConvertSidToStringSidW | |||
//sys convertStringSecurityDescriptorToSecurityDescriptor(str string, revision uint32, sd *uintptr, size *uint32) (err error) = advapi32.ConvertStringSecurityDescriptorToSecurityDescriptorW | |||
//sys convertSecurityDescriptorToStringSecurityDescriptor(sd *byte, revision uint32, secInfo uint32, sddl **uint16, sddlSize *uint32) (err error) = advapi32.ConvertSecurityDescriptorToStringSecurityDescriptorW | |||
//sys localFree(mem uintptr) = LocalFree | |||
//sys getSecurityDescriptorLength(sd uintptr) (len uint32) = advapi32.GetSecurityDescriptorLength | |||
const ( | |||
cERROR_NONE_MAPPED = syscall.Errno(1332) | |||
) | |||
type AccountLookupError struct { | |||
Name string | |||
Err error | |||
} | |||
func (e *AccountLookupError) Error() string { | |||
if e.Name == "" { | |||
return "lookup account: empty account name specified" | |||
} | |||
var s string | |||
switch e.Err { | |||
case cERROR_NONE_MAPPED: | |||
s = "not found" | |||
default: | |||
s = e.Err.Error() | |||
} | |||
return "lookup account " + e.Name + ": " + s | |||
} | |||
type SddlConversionError struct { | |||
Sddl string | |||
Err error | |||
} | |||
func (e *SddlConversionError) Error() string { | |||
return "convert " + e.Sddl + ": " + e.Err.Error() | |||
} | |||
// LookupSidByName looks up the SID of an account by name | |||
func LookupSidByName(name string) (sid string, err error) { | |||
if name == "" { | |||
return "", &AccountLookupError{name, cERROR_NONE_MAPPED} | |||
} | |||
var sidSize, sidNameUse, refDomainSize uint32 | |||
err = lookupAccountName(nil, name, nil, &sidSize, nil, &refDomainSize, &sidNameUse) | |||
if err != nil && err != syscall.ERROR_INSUFFICIENT_BUFFER { | |||
return "", &AccountLookupError{name, err} | |||
} | |||
sidBuffer := make([]byte, sidSize) | |||
refDomainBuffer := make([]uint16, refDomainSize) | |||
err = lookupAccountName(nil, name, &sidBuffer[0], &sidSize, &refDomainBuffer[0], &refDomainSize, &sidNameUse) | |||
if err != nil { | |||
return "", &AccountLookupError{name, err} | |||
} | |||
var strBuffer *uint16 | |||
err = convertSidToStringSid(&sidBuffer[0], &strBuffer) | |||
if err != nil { | |||
return "", &AccountLookupError{name, err} | |||
} | |||
sid = syscall.UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(strBuffer))[:]) | |||
localFree(uintptr(unsafe.Pointer(strBuffer))) | |||
return sid, nil | |||
} | |||
func SddlToSecurityDescriptor(sddl string) ([]byte, error) { | |||
var sdBuffer uintptr | |||
err := convertStringSecurityDescriptorToSecurityDescriptor(sddl, 1, &sdBuffer, nil) | |||
if err != nil { | |||
return nil, &SddlConversionError{sddl, err} | |||
} | |||
defer localFree(sdBuffer) | |||
sd := make([]byte, getSecurityDescriptorLength(sdBuffer)) | |||
copy(sd, (*[0xffff]byte)(unsafe.Pointer(sdBuffer))[:len(sd)]) | |||
return sd, nil | |||
} | |||
func SecurityDescriptorToSddl(sd []byte) (string, error) { | |||
var sddl *uint16 | |||
// The returned string length seems to including an aribtrary number of terminating NULs. | |||
// Don't use it. | |||
err := convertSecurityDescriptorToStringSecurityDescriptor(&sd[0], 1, 0xff, &sddl, nil) | |||
if err != nil { | |||
return "", err | |||
} | |||
defer localFree(uintptr(unsafe.Pointer(sddl))) | |||
return syscall.UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(sddl))[:]), nil | |||
} |
@@ -0,0 +1,3 @@ | |||
package winio | |||
//go:generate go run golang.org/x/sys/windows/mkwinsyscall -output zsyscall_windows.go file.go pipe.go sd.go fileinfo.go privilege.go backup.go hvsock.go |
@@ -0,0 +1,427 @@ | |||
// Code generated by 'go generate'; DO NOT EDIT. | |||
package winio | |||
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 ( | |||
modadvapi32 = windows.NewLazySystemDLL("advapi32.dll") | |||
modkernel32 = windows.NewLazySystemDLL("kernel32.dll") | |||
modntdll = windows.NewLazySystemDLL("ntdll.dll") | |||
modws2_32 = windows.NewLazySystemDLL("ws2_32.dll") | |||
procAdjustTokenPrivileges = modadvapi32.NewProc("AdjustTokenPrivileges") | |||
procConvertSecurityDescriptorToStringSecurityDescriptorW = modadvapi32.NewProc("ConvertSecurityDescriptorToStringSecurityDescriptorW") | |||
procConvertSidToStringSidW = modadvapi32.NewProc("ConvertSidToStringSidW") | |||
procConvertStringSecurityDescriptorToSecurityDescriptorW = modadvapi32.NewProc("ConvertStringSecurityDescriptorToSecurityDescriptorW") | |||
procGetSecurityDescriptorLength = modadvapi32.NewProc("GetSecurityDescriptorLength") | |||
procImpersonateSelf = modadvapi32.NewProc("ImpersonateSelf") | |||
procLookupAccountNameW = modadvapi32.NewProc("LookupAccountNameW") | |||
procLookupPrivilegeDisplayNameW = modadvapi32.NewProc("LookupPrivilegeDisplayNameW") | |||
procLookupPrivilegeNameW = modadvapi32.NewProc("LookupPrivilegeNameW") | |||
procLookupPrivilegeValueW = modadvapi32.NewProc("LookupPrivilegeValueW") | |||
procOpenThreadToken = modadvapi32.NewProc("OpenThreadToken") | |||
procRevertToSelf = modadvapi32.NewProc("RevertToSelf") | |||
procBackupRead = modkernel32.NewProc("BackupRead") | |||
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") | |||
procGetNamedPipeHandleStateW = modkernel32.NewProc("GetNamedPipeHandleStateW") | |||
procGetNamedPipeInfo = modkernel32.NewProc("GetNamedPipeInfo") | |||
procGetQueuedCompletionStatus = modkernel32.NewProc("GetQueuedCompletionStatus") | |||
procLocalAlloc = modkernel32.NewProc("LocalAlloc") | |||
procLocalFree = modkernel32.NewProc("LocalFree") | |||
procSetFileCompletionNotificationModes = modkernel32.NewProc("SetFileCompletionNotificationModes") | |||
procNtCreateNamedPipeFile = modntdll.NewProc("NtCreateNamedPipeFile") | |||
procRtlDefaultNpAcl = modntdll.NewProc("RtlDefaultNpAcl") | |||
procRtlDosPathNameToNtPathName_U = modntdll.NewProc("RtlDosPathNameToNtPathName_U") | |||
procRtlNtStatusToDosErrorNoTeb = modntdll.NewProc("RtlNtStatusToDosErrorNoTeb") | |||
procWSAGetOverlappedResult = modws2_32.NewProc("WSAGetOverlappedResult") | |||
procbind = modws2_32.NewProc("bind") | |||
) | |||
func adjustTokenPrivileges(token windows.Token, releaseAll bool, input *byte, outputSize uint32, output *byte, requiredSize *uint32) (success bool, err error) { | |||
var _p0 uint32 | |||
if releaseAll { | |||
_p0 = 1 | |||
} | |||
r0, _, e1 := syscall.Syscall6(procAdjustTokenPrivileges.Addr(), 6, uintptr(token), uintptr(_p0), uintptr(unsafe.Pointer(input)), uintptr(outputSize), uintptr(unsafe.Pointer(output)), uintptr(unsafe.Pointer(requiredSize))) | |||
success = r0 != 0 | |||
if true { | |||
err = errnoErr(e1) | |||
} | |||
return | |||
} | |||
func convertSecurityDescriptorToStringSecurityDescriptor(sd *byte, revision uint32, secInfo uint32, sddl **uint16, sddlSize *uint32) (err error) { | |||
r1, _, e1 := syscall.Syscall6(procConvertSecurityDescriptorToStringSecurityDescriptorW.Addr(), 5, uintptr(unsafe.Pointer(sd)), uintptr(revision), uintptr(secInfo), uintptr(unsafe.Pointer(sddl)), uintptr(unsafe.Pointer(sddlSize)), 0) | |||
if r1 == 0 { | |||
err = errnoErr(e1) | |||
} | |||
return | |||
} | |||
func convertSidToStringSid(sid *byte, str **uint16) (err error) { | |||
r1, _, e1 := syscall.Syscall(procConvertSidToStringSidW.Addr(), 2, uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(str)), 0) | |||
if r1 == 0 { | |||
err = errnoErr(e1) | |||
} | |||
return | |||
} | |||
func convertStringSecurityDescriptorToSecurityDescriptor(str string, revision uint32, sd *uintptr, size *uint32) (err error) { | |||
var _p0 *uint16 | |||
_p0, err = syscall.UTF16PtrFromString(str) | |||
if err != nil { | |||
return | |||
} | |||
return _convertStringSecurityDescriptorToSecurityDescriptor(_p0, revision, sd, size) | |||
} | |||
func _convertStringSecurityDescriptorToSecurityDescriptor(str *uint16, revision uint32, sd *uintptr, size *uint32) (err error) { | |||
r1, _, e1 := syscall.Syscall6(procConvertStringSecurityDescriptorToSecurityDescriptorW.Addr(), 4, uintptr(unsafe.Pointer(str)), uintptr(revision), uintptr(unsafe.Pointer(sd)), uintptr(unsafe.Pointer(size)), 0, 0) | |||
if r1 == 0 { | |||
err = errnoErr(e1) | |||
} | |||
return | |||
} | |||
func getSecurityDescriptorLength(sd uintptr) (len uint32) { | |||
r0, _, _ := syscall.Syscall(procGetSecurityDescriptorLength.Addr(), 1, uintptr(sd), 0, 0) | |||
len = uint32(r0) | |||
return | |||
} | |||
func impersonateSelf(level uint32) (err error) { | |||
r1, _, e1 := syscall.Syscall(procImpersonateSelf.Addr(), 1, uintptr(level), 0, 0) | |||
if r1 == 0 { | |||
err = errnoErr(e1) | |||
} | |||
return | |||
} | |||
func lookupAccountName(systemName *uint16, accountName string, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) { | |||
var _p0 *uint16 | |||
_p0, err = syscall.UTF16PtrFromString(accountName) | |||
if err != nil { | |||
return | |||
} | |||
return _lookupAccountName(systemName, _p0, sid, sidSize, refDomain, refDomainSize, sidNameUse) | |||
} | |||
func _lookupAccountName(systemName *uint16, accountName *uint16, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) { | |||
r1, _, e1 := syscall.Syscall9(procLookupAccountNameW.Addr(), 7, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(accountName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(sidSize)), uintptr(unsafe.Pointer(refDomain)), uintptr(unsafe.Pointer(refDomainSize)), uintptr(unsafe.Pointer(sidNameUse)), 0, 0) | |||
if r1 == 0 { | |||
err = errnoErr(e1) | |||
} | |||
return | |||
} | |||
func lookupPrivilegeDisplayName(systemName string, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) { | |||
var _p0 *uint16 | |||
_p0, err = syscall.UTF16PtrFromString(systemName) | |||
if err != nil { | |||
return | |||
} | |||
return _lookupPrivilegeDisplayName(_p0, name, buffer, size, languageId) | |||
} | |||
func _lookupPrivilegeDisplayName(systemName *uint16, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) { | |||
r1, _, e1 := syscall.Syscall6(procLookupPrivilegeDisplayNameW.Addr(), 5, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(buffer)), uintptr(unsafe.Pointer(size)), uintptr(unsafe.Pointer(languageId)), 0) | |||
if r1 == 0 { | |||
err = errnoErr(e1) | |||
} | |||
return | |||
} | |||
func lookupPrivilegeName(systemName string, luid *uint64, buffer *uint16, size *uint32) (err error) { | |||
var _p0 *uint16 | |||
_p0, err = syscall.UTF16PtrFromString(systemName) | |||
if err != nil { | |||
return | |||
} | |||
return _lookupPrivilegeName(_p0, luid, buffer, size) | |||
} | |||
func _lookupPrivilegeName(systemName *uint16, luid *uint64, buffer *uint16, size *uint32) (err error) { | |||
r1, _, e1 := syscall.Syscall6(procLookupPrivilegeNameW.Addr(), 4, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(luid)), uintptr(unsafe.Pointer(buffer)), uintptr(unsafe.Pointer(size)), 0, 0) | |||
if r1 == 0 { | |||
err = errnoErr(e1) | |||
} | |||
return | |||
} | |||
func lookupPrivilegeValue(systemName string, name string, luid *uint64) (err error) { | |||
var _p0 *uint16 | |||
_p0, err = syscall.UTF16PtrFromString(systemName) | |||
if err != nil { | |||
return | |||
} | |||
var _p1 *uint16 | |||
_p1, err = syscall.UTF16PtrFromString(name) | |||
if err != nil { | |||
return | |||
} | |||
return _lookupPrivilegeValue(_p0, _p1, luid) | |||
} | |||
func _lookupPrivilegeValue(systemName *uint16, name *uint16, luid *uint64) (err error) { | |||
r1, _, e1 := syscall.Syscall(procLookupPrivilegeValueW.Addr(), 3, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(luid))) | |||
if r1 == 0 { | |||
err = errnoErr(e1) | |||
} | |||
return | |||
} | |||
func openThreadToken(thread syscall.Handle, accessMask uint32, openAsSelf bool, token *windows.Token) (err error) { | |||
var _p0 uint32 | |||
if openAsSelf { | |||
_p0 = 1 | |||
} | |||
r1, _, e1 := syscall.Syscall6(procOpenThreadToken.Addr(), 4, uintptr(thread), uintptr(accessMask), uintptr(_p0), uintptr(unsafe.Pointer(token)), 0, 0) | |||
if r1 == 0 { | |||
err = errnoErr(e1) | |||
} | |||
return | |||
} | |||
func revertToSelf() (err error) { | |||
r1, _, e1 := syscall.Syscall(procRevertToSelf.Addr(), 0, 0, 0, 0) | |||
if r1 == 0 { | |||
err = errnoErr(e1) | |||
} | |||
return | |||
} | |||
func backupRead(h syscall.Handle, b []byte, bytesRead *uint32, abort bool, processSecurity bool, context *uintptr) (err error) { | |||
var _p0 *byte | |||
if len(b) > 0 { | |||
_p0 = &b[0] | |||
} | |||
var _p1 uint32 | |||
if abort { | |||
_p1 = 1 | |||
} | |||
var _p2 uint32 | |||
if processSecurity { | |||
_p2 = 1 | |||
} | |||
r1, _, e1 := syscall.Syscall9(procBackupRead.Addr(), 7, uintptr(h), uintptr(unsafe.Pointer(_p0)), uintptr(len(b)), uintptr(unsafe.Pointer(bytesRead)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(context)), 0, 0) | |||
if r1 == 0 { | |||
err = errnoErr(e1) | |||
} | |||
return | |||
} | |||
func backupWrite(h syscall.Handle, b []byte, bytesWritten *uint32, abort bool, processSecurity bool, context *uintptr) (err error) { | |||
var _p0 *byte | |||
if len(b) > 0 { | |||
_p0 = &b[0] | |||
} | |||
var _p1 uint32 | |||
if abort { | |||
_p1 = 1 | |||
} | |||
var _p2 uint32 | |||
if processSecurity { | |||
_p2 = 1 | |||
} | |||
r1, _, e1 := syscall.Syscall9(procBackupWrite.Addr(), 7, uintptr(h), uintptr(unsafe.Pointer(_p0)), uintptr(len(b)), uintptr(unsafe.Pointer(bytesWritten)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(context)), 0, 0) | |||
if r1 == 0 { | |||
err = errnoErr(e1) | |||
} | |||
return | |||
} | |||
func cancelIoEx(file syscall.Handle, o *syscall.Overlapped) (err error) { | |||
r1, _, e1 := syscall.Syscall(procCancelIoEx.Addr(), 2, uintptr(file), uintptr(unsafe.Pointer(o)), 0) | |||
if r1 == 0 { | |||
err = errnoErr(e1) | |||
} | |||
return | |||
} | |||
func connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) { | |||
r1, _, e1 := syscall.Syscall(procConnectNamedPipe.Addr(), 2, uintptr(pipe), uintptr(unsafe.Pointer(o)), 0) | |||
if r1 == 0 { | |||
err = errnoErr(e1) | |||
} | |||
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) | |||
if newport == 0 { | |||
err = errnoErr(e1) | |||
} | |||
return | |||
} | |||
func createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *syscall.SecurityAttributes) (handle syscall.Handle, err error) { | |||
var _p0 *uint16 | |||
_p0, err = syscall.UTF16PtrFromString(name) | |||
if err != nil { | |||
return | |||
} | |||
return _createNamedPipe(_p0, flags, pipeMode, maxInstances, outSize, inSize, defaultTimeout, sa) | |||
} | |||
func _createNamedPipe(name *uint16, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *syscall.SecurityAttributes) (handle syscall.Handle, err error) { | |||
r0, _, e1 := syscall.Syscall9(procCreateNamedPipeW.Addr(), 8, uintptr(unsafe.Pointer(name)), uintptr(flags), uintptr(pipeMode), uintptr(maxInstances), uintptr(outSize), uintptr(inSize), uintptr(defaultTimeout), uintptr(unsafe.Pointer(sa)), 0) | |||
handle = syscall.Handle(r0) | |||
if handle == syscall.InvalidHandle { | |||
err = errnoErr(e1) | |||
} | |||
return | |||
} | |||
func getCurrentThread() (h syscall.Handle) { | |||
r0, _, _ := syscall.Syscall(procGetCurrentThread.Addr(), 0, 0, 0, 0) | |||
h = syscall.Handle(r0) | |||
return | |||
} | |||
func getNamedPipeHandleState(pipe syscall.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) { | |||
r1, _, e1 := syscall.Syscall9(procGetNamedPipeHandleStateW.Addr(), 7, uintptr(pipe), uintptr(unsafe.Pointer(state)), uintptr(unsafe.Pointer(curInstances)), uintptr(unsafe.Pointer(maxCollectionCount)), uintptr(unsafe.Pointer(collectDataTimeout)), uintptr(unsafe.Pointer(userName)), uintptr(maxUserNameSize), 0, 0) | |||
if r1 == 0 { | |||
err = errnoErr(e1) | |||
} | |||
return | |||
} | |||
func getNamedPipeInfo(pipe syscall.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) { | |||
r1, _, e1 := syscall.Syscall6(procGetNamedPipeInfo.Addr(), 5, uintptr(pipe), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(outSize)), uintptr(unsafe.Pointer(inSize)), uintptr(unsafe.Pointer(maxInstances)), 0) | |||
if r1 == 0 { | |||
err = errnoErr(e1) | |||
} | |||
return | |||
} | |||
func getQueuedCompletionStatus(port syscall.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) { | |||
r1, _, e1 := syscall.Syscall6(procGetQueuedCompletionStatus.Addr(), 5, uintptr(port), uintptr(unsafe.Pointer(bytes)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(o)), uintptr(timeout), 0) | |||
if r1 == 0 { | |||
err = errnoErr(e1) | |||
} | |||
return | |||
} | |||
func localAlloc(uFlags uint32, length uint32) (ptr uintptr) { | |||
r0, _, _ := syscall.Syscall(procLocalAlloc.Addr(), 2, uintptr(uFlags), uintptr(length), 0) | |||
ptr = uintptr(r0) | |||
return | |||
} | |||
func localFree(mem uintptr) { | |||
syscall.Syscall(procLocalFree.Addr(), 1, uintptr(mem), 0, 0) | |||
return | |||
} | |||
func setFileCompletionNotificationModes(h syscall.Handle, flags uint8) (err error) { | |||
r1, _, e1 := syscall.Syscall(procSetFileCompletionNotificationModes.Addr(), 2, uintptr(h), uintptr(flags), 0) | |||
if r1 == 0 { | |||
err = errnoErr(e1) | |||
} | |||
return | |||
} | |||
func ntCreateNamedPipeFile(pipe *syscall.Handle, access uint32, oa *objectAttributes, iosb *ioStatusBlock, share uint32, disposition uint32, options uint32, typ uint32, readMode uint32, completionMode uint32, maxInstances uint32, inboundQuota uint32, outputQuota uint32, timeout *int64) (status ntstatus) { | |||
r0, _, _ := syscall.Syscall15(procNtCreateNamedPipeFile.Addr(), 14, uintptr(unsafe.Pointer(pipe)), uintptr(access), uintptr(unsafe.Pointer(oa)), uintptr(unsafe.Pointer(iosb)), uintptr(share), uintptr(disposition), uintptr(options), uintptr(typ), uintptr(readMode), uintptr(completionMode), uintptr(maxInstances), uintptr(inboundQuota), uintptr(outputQuota), uintptr(unsafe.Pointer(timeout)), 0) | |||
status = ntstatus(r0) | |||
return | |||
} | |||
func rtlDefaultNpAcl(dacl *uintptr) (status ntstatus) { | |||
r0, _, _ := syscall.Syscall(procRtlDefaultNpAcl.Addr(), 1, uintptr(unsafe.Pointer(dacl)), 0, 0) | |||
status = ntstatus(r0) | |||
return | |||
} | |||
func rtlDosPathNameToNtPathName(name *uint16, ntName *unicodeString, filePart uintptr, reserved uintptr) (status ntstatus) { | |||
r0, _, _ := syscall.Syscall6(procRtlDosPathNameToNtPathName_U.Addr(), 4, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(ntName)), uintptr(filePart), uintptr(reserved), 0, 0) | |||
status = ntstatus(r0) | |||
return | |||
} | |||
func rtlNtStatusToDosError(status ntstatus) (winerr error) { | |||
r0, _, _ := syscall.Syscall(procRtlNtStatusToDosErrorNoTeb.Addr(), 1, uintptr(status), 0, 0) | |||
if r0 != 0 { | |||
winerr = syscall.Errno(r0) | |||
} | |||
return | |||
} | |||
func wsaGetOverlappedResult(h syscall.Handle, o *syscall.Overlapped, bytes *uint32, wait bool, flags *uint32) (err error) { | |||
var _p0 uint32 | |||
if wait { | |||
_p0 = 1 | |||
} | |||
r1, _, e1 := syscall.Syscall6(procWSAGetOverlappedResult.Addr(), 5, uintptr(h), uintptr(unsafe.Pointer(o)), uintptr(unsafe.Pointer(bytes)), uintptr(_p0), uintptr(unsafe.Pointer(flags)), 0) | |||
if r1 == 0 { | |||
err = errnoErr(e1) | |||
} | |||
return | |||
} | |||
func bind(s syscall.Handle, name unsafe.Pointer, namelen int32) (err error) { | |||
r1, _, e1 := syscall.Syscall(procbind.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen)) | |||
if r1 == socketError { | |||
err = errnoErr(e1) | |||
} | |||
return | |||
} |
@@ -1,4 +1,4 @@ | |||
Copyright (c) 2019 The Go Authors. All rights reserved. | |||
Copyright (c) 2009 The Go Authors. All rights reserved. | |||
Redistribution and use in source and binary forms, with or without | |||
modification, are permitted provided that the following conditions are |
@@ -0,0 +1,381 @@ | |||
package bitcurves | |||
// Copyright 2010 The Go Authors. All rights reserved. | |||
// Copyright 2011 ThePiachu. All rights reserved. | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
// Package bitelliptic implements several Koblitz elliptic curves over prime | |||
// fields. | |||
// This package operates, internally, on Jacobian coordinates. For a given | |||
// (x, y) position on the curve, the Jacobian coordinates are (x1, y1, z1) | |||
// where x = x1/z1² and y = y1/z1³. The greatest speedups come when the whole | |||
// calculation can be performed within the transform (as in ScalarMult and | |||
// ScalarBaseMult). But even for Add and Double, it's faster to apply and | |||
// reverse the transform than to operate in affine coordinates. | |||
import ( | |||
"crypto/elliptic" | |||
"io" | |||
"math/big" | |||
"sync" | |||
) | |||
// A BitCurve represents a Koblitz Curve with a=0. | |||
// See http://www.hyperelliptic.org/EFD/g1p/auto-shortw.html | |||
type BitCurve struct { | |||
Name string | |||
P *big.Int // the order of the underlying field | |||
N *big.Int // the order of the base point | |||
B *big.Int // the constant of the BitCurve equation | |||
Gx, Gy *big.Int // (x,y) of the base point | |||
BitSize int // the size of the underlying field | |||
} | |||
// Params returns the parameters of the given BitCurve (see BitCurve struct) | |||
func (bitCurve *BitCurve) Params() (cp *elliptic.CurveParams) { | |||
cp = new(elliptic.CurveParams) | |||
cp.Name = bitCurve.Name | |||
cp.P = bitCurve.P | |||
cp.N = bitCurve.N | |||
cp.Gx = bitCurve.Gx | |||
cp.Gy = bitCurve.Gy | |||
cp.BitSize = bitCurve.BitSize | |||
return cp | |||
} | |||
// IsOnCurve returns true if the given (x,y) lies on the BitCurve. | |||
func (bitCurve *BitCurve) IsOnCurve(x, y *big.Int) bool { | |||
// y² = x³ + b | |||
y2 := new(big.Int).Mul(y, y) //y² | |||
y2.Mod(y2, bitCurve.P) //y²%P | |||
x3 := new(big.Int).Mul(x, x) //x² | |||
x3.Mul(x3, x) //x³ | |||
x3.Add(x3, bitCurve.B) //x³+B | |||
x3.Mod(x3, bitCurve.P) //(x³+B)%P | |||
return x3.Cmp(y2) == 0 | |||
} | |||
// affineFromJacobian reverses the Jacobian transform. See the comment at the | |||
// top of the file. | |||
func (bitCurve *BitCurve) affineFromJacobian(x, y, z *big.Int) (xOut, yOut *big.Int) { | |||
if z.Cmp(big.NewInt(0)) == 0 { | |||
panic("bitcurve: Can't convert to affine with Jacobian Z = 0") | |||
} | |||
// x = YZ^2 mod P | |||
zinv := new(big.Int).ModInverse(z, bitCurve.P) | |||
zinvsq := new(big.Int).Mul(zinv, zinv) | |||
xOut = new(big.Int).Mul(x, zinvsq) | |||
xOut.Mod(xOut, bitCurve.P) | |||
// y = YZ^3 mod P | |||
zinvsq.Mul(zinvsq, zinv) | |||
yOut = new(big.Int).Mul(y, zinvsq) | |||
yOut.Mod(yOut, bitCurve.P) | |||
return xOut, yOut | |||
} | |||
// Add returns the sum of (x1,y1) and (x2,y2) | |||
func (bitCurve *BitCurve) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) { | |||
z := new(big.Int).SetInt64(1) | |||
x, y, z := bitCurve.addJacobian(x1, y1, z, x2, y2, z) | |||
return bitCurve.affineFromJacobian(x, y, z) | |||
} | |||
// addJacobian takes two points in Jacobian coordinates, (x1, y1, z1) and | |||
// (x2, y2, z2) and returns their sum, also in Jacobian form. | |||
func (bitCurve *BitCurve) addJacobian(x1, y1, z1, x2, y2, z2 *big.Int) (*big.Int, *big.Int, *big.Int) { | |||
// See http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl | |||
z1z1 := new(big.Int).Mul(z1, z1) | |||
z1z1.Mod(z1z1, bitCurve.P) | |||
z2z2 := new(big.Int).Mul(z2, z2) | |||
z2z2.Mod(z2z2, bitCurve.P) | |||
u1 := new(big.Int).Mul(x1, z2z2) | |||
u1.Mod(u1, bitCurve.P) | |||
u2 := new(big.Int).Mul(x2, z1z1) | |||
u2.Mod(u2, bitCurve.P) | |||
h := new(big.Int).Sub(u2, u1) | |||
if h.Sign() == -1 { | |||
h.Add(h, bitCurve.P) | |||
} | |||
i := new(big.Int).Lsh(h, 1) | |||
i.Mul(i, i) | |||
j := new(big.Int).Mul(h, i) | |||
s1 := new(big.Int).Mul(y1, z2) | |||
s1.Mul(s1, z2z2) | |||
s1.Mod(s1, bitCurve.P) | |||
s2 := new(big.Int).Mul(y2, z1) | |||
s2.Mul(s2, z1z1) | |||
s2.Mod(s2, bitCurve.P) | |||
r := new(big.Int).Sub(s2, s1) | |||
if r.Sign() == -1 { | |||
r.Add(r, bitCurve.P) | |||
} | |||
r.Lsh(r, 1) | |||
v := new(big.Int).Mul(u1, i) | |||
x3 := new(big.Int).Set(r) | |||
x3.Mul(x3, x3) | |||
x3.Sub(x3, j) | |||
x3.Sub(x3, v) | |||
x3.Sub(x3, v) | |||
x3.Mod(x3, bitCurve.P) | |||
y3 := new(big.Int).Set(r) | |||
v.Sub(v, x3) | |||
y3.Mul(y3, v) | |||
s1.Mul(s1, j) | |||
s1.Lsh(s1, 1) | |||
y3.Sub(y3, s1) | |||
y3.Mod(y3, bitCurve.P) | |||
z3 := new(big.Int).Add(z1, z2) | |||
z3.Mul(z3, z3) | |||
z3.Sub(z3, z1z1) | |||
if z3.Sign() == -1 { | |||
z3.Add(z3, bitCurve.P) | |||
} | |||
z3.Sub(z3, z2z2) | |||
if z3.Sign() == -1 { | |||
z3.Add(z3, bitCurve.P) | |||
} | |||
z3.Mul(z3, h) | |||
z3.Mod(z3, bitCurve.P) | |||
return x3, y3, z3 | |||
} | |||
// Double returns 2*(x,y) | |||
func (bitCurve *BitCurve) Double(x1, y1 *big.Int) (*big.Int, *big.Int) { | |||
z1 := new(big.Int).SetInt64(1) | |||
return bitCurve.affineFromJacobian(bitCurve.doubleJacobian(x1, y1, z1)) | |||
} | |||
// doubleJacobian takes a point in Jacobian coordinates, (x, y, z), and | |||
// returns its double, also in Jacobian form. | |||
func (bitCurve *BitCurve) doubleJacobian(x, y, z *big.Int) (*big.Int, *big.Int, *big.Int) { | |||
// See http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l | |||
a := new(big.Int).Mul(x, x) //X1² | |||
b := new(big.Int).Mul(y, y) //Y1² | |||
c := new(big.Int).Mul(b, b) //B² | |||
d := new(big.Int).Add(x, b) //X1+B | |||
d.Mul(d, d) //(X1+B)² | |||
d.Sub(d, a) //(X1+B)²-A | |||
d.Sub(d, c) //(X1+B)²-A-C | |||
d.Mul(d, big.NewInt(2)) //2*((X1+B)²-A-C) | |||
e := new(big.Int).Mul(big.NewInt(3), a) //3*A | |||
f := new(big.Int).Mul(e, e) //E² | |||
x3 := new(big.Int).Mul(big.NewInt(2), d) //2*D | |||
x3.Sub(f, x3) //F-2*D | |||
x3.Mod(x3, bitCurve.P) | |||
y3 := new(big.Int).Sub(d, x3) //D-X3 | |||
y3.Mul(e, y3) //E*(D-X3) | |||
y3.Sub(y3, new(big.Int).Mul(big.NewInt(8), c)) //E*(D-X3)-8*C | |||
y3.Mod(y3, bitCurve.P) | |||
z3 := new(big.Int).Mul(y, z) //Y1*Z1 | |||
z3.Mul(big.NewInt(2), z3) //3*Y1*Z1 | |||
z3.Mod(z3, bitCurve.P) | |||
return x3, y3, z3 | |||
} | |||
// 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 | |||
// point at infinity) cannot be represented in (x, y) form on a finite | |||
// machine. Thus the standard add/double algorithm has to be tweaked | |||
// slightly: our initial state is not the identity, but x, and we | |||
// ignore the first true bit in |k|. If we don't find any true bits in | |||
// |k|, then we return nil, nil, because we cannot return the identity | |||
// element. | |||
Bz := new(big.Int).SetInt64(1) | |||
x := Bx | |||
y := By | |||
z := Bz | |||
seenFirstTrue := false | |||
for _, byte := range k { | |||
for bitNum := 0; bitNum < 8; bitNum++ { | |||
if seenFirstTrue { | |||
x, y, z = bitCurve.doubleJacobian(x, y, z) | |||
} | |||
if byte&0x80 == 0x80 { | |||
if !seenFirstTrue { | |||
seenFirstTrue = true | |||
} else { | |||
x, y, z = bitCurve.addJacobian(Bx, By, Bz, x, y, z) | |||
} | |||
} | |||
byte <<= 1 | |||
} | |||
} | |||
if !seenFirstTrue { | |||
return nil, nil | |||
} | |||
return bitCurve.affineFromJacobian(x, y, z) | |||
} | |||
// ScalarBaseMult returns k*G, where G is the base point of the group and k is | |||
// an integer in big-endian form. | |||
func (bitCurve *BitCurve) ScalarBaseMult(k []byte) (*big.Int, *big.Int) { | |||
return bitCurve.ScalarMult(bitCurve.Gx, bitCurve.Gy, k) | |||
} | |||
var mask = []byte{0xff, 0x1, 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f} | |||
// 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) { | |||
byteLen := (bitCurve.BitSize + 7) >> 3 | |||
priv = make([]byte, byteLen) | |||
for x == nil { | |||
_, err = io.ReadFull(rand, priv) | |||
if err != nil { | |||
return | |||
} | |||
// We have to mask off any excess bits in the case that the size of the | |||
// underlying field is not a whole number of bytes. | |||
priv[0] &= mask[bitCurve.BitSize%8] | |||
// This is because, in tests, rand will return all zeros and we don't | |||
// want to get the point at infinity and loop forever. | |||
priv[1] ^= 0x42 | |||
x, y = bitCurve.ScalarBaseMult(priv) | |||
} | |||
return | |||
} | |||
// Marshal converts a point into the form specified in section 4.3.6 of ANSI | |||
// X9.62. | |||
func (bitCurve *BitCurve) Marshal(x, y *big.Int) []byte { | |||
byteLen := (bitCurve.BitSize + 7) >> 3 | |||
ret := make([]byte, 1+2*byteLen) | |||
ret[0] = 4 // uncompressed point | |||
xBytes := x.Bytes() | |||
copy(ret[1+byteLen-len(xBytes):], xBytes) | |||
yBytes := y.Bytes() | |||
copy(ret[1+2*byteLen-len(yBytes):], yBytes) | |||
return ret | |||
} | |||
// Unmarshal converts a point, serialised by Marshal, into an x, y pair. On | |||
// error, x = nil. | |||
func (bitCurve *BitCurve) Unmarshal(data []byte) (x, y *big.Int) { | |||
byteLen := (bitCurve.BitSize + 7) >> 3 | |||
if len(data) != 1+2*byteLen { | |||
return | |||
} | |||
if data[0] != 4 { // uncompressed form | |||
return | |||
} | |||
x = new(big.Int).SetBytes(data[1 : 1+byteLen]) | |||
y = new(big.Int).SetBytes(data[1+byteLen:]) | |||
return | |||
} | |||
//curve parameters taken from: | |||
//http://www.secg.org/collateral/sec2_final.pdf | |||
var initonce sync.Once | |||
var secp160k1 *BitCurve | |||
var secp192k1 *BitCurve | |||
var secp224k1 *BitCurve | |||
var secp256k1 *BitCurve | |||
func initAll() { | |||
initS160() | |||
initS192() | |||
initS224() | |||
initS256() | |||
} | |||
func initS160() { | |||
// See SEC 2 section 2.4.1 | |||
secp160k1 = new(BitCurve) | |||
secp160k1.Name = "secp160k1" | |||
secp160k1.P, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73", 16) | |||
secp160k1.N, _ = new(big.Int).SetString("0100000000000000000001B8FA16DFAB9ACA16B6B3", 16) | |||
secp160k1.B, _ = new(big.Int).SetString("0000000000000000000000000000000000000007", 16) | |||
secp160k1.Gx, _ = new(big.Int).SetString("3B4C382CE37AA192A4019E763036F4F5DD4D7EBB", 16) | |||
secp160k1.Gy, _ = new(big.Int).SetString("938CF935318FDCED6BC28286531733C3F03C4FEE", 16) | |||
secp160k1.BitSize = 160 | |||
} | |||
func initS192() { | |||
// See SEC 2 section 2.5.1 | |||
secp192k1 = new(BitCurve) | |||
secp192k1.Name = "secp192k1" | |||
secp192k1.P, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFEE37", 16) | |||
secp192k1.N, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D", 16) | |||
secp192k1.B, _ = new(big.Int).SetString("000000000000000000000000000000000000000000000003", 16) | |||
secp192k1.Gx, _ = new(big.Int).SetString("DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D", 16) | |||
secp192k1.Gy, _ = new(big.Int).SetString("9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D", 16) | |||
secp192k1.BitSize = 192 | |||
} | |||
func initS224() { | |||
// See SEC 2 section 2.6.1 | |||
secp224k1 = new(BitCurve) | |||
secp224k1.Name = "secp224k1" | |||
secp224k1.P, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFE56D", 16) | |||
secp224k1.N, _ = new(big.Int).SetString("010000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7", 16) | |||
secp224k1.B, _ = new(big.Int).SetString("00000000000000000000000000000000000000000000000000000005", 16) | |||
secp224k1.Gx, _ = new(big.Int).SetString("A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C", 16) | |||
secp224k1.Gy, _ = new(big.Int).SetString("7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5", 16) | |||
secp224k1.BitSize = 224 | |||
} | |||
func initS256() { | |||
// See SEC 2 section 2.7.1 | |||
secp256k1 = new(BitCurve) | |||
secp256k1.Name = "secp256k1" | |||
secp256k1.P, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", 16) | |||
secp256k1.N, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 16) | |||
secp256k1.B, _ = new(big.Int).SetString("0000000000000000000000000000000000000000000000000000000000000007", 16) | |||
secp256k1.Gx, _ = new(big.Int).SetString("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", 16) | |||
secp256k1.Gy, _ = new(big.Int).SetString("483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8", 16) | |||
secp256k1.BitSize = 256 | |||
} | |||
// S160 returns a BitCurve which implements secp160k1 (see SEC 2 section 2.4.1) | |||
func S160() *BitCurve { | |||
initonce.Do(initAll) | |||
return secp160k1 | |||
} | |||
// S192 returns a BitCurve which implements secp192k1 (see SEC 2 section 2.5.1) | |||
func S192() *BitCurve { | |||
initonce.Do(initAll) | |||
return secp192k1 | |||
} | |||
// S224 returns a BitCurve which implements secp224k1 (see SEC 2 section 2.6.1) | |||
func S224() *BitCurve { | |||
initonce.Do(initAll) | |||
return secp224k1 | |||
} | |||
// S256 returns a BitCurve which implements bitcurves (see SEC 2 section 2.7.1) | |||
func S256() *BitCurve { | |||
initonce.Do(initAll) | |||
return secp256k1 | |||
} |
@@ -0,0 +1,134 @@ | |||
// Package brainpool implements Brainpool elliptic curves. | |||
// Implementation of rcurves is from github.com/ebfe/brainpool | |||
// Note that these curves are implemented with naive, non-constant time operations | |||
// and are likely not suitable for environments where timing attacks are a concern. | |||
package brainpool | |||
import ( | |||
"crypto/elliptic" | |||
"math/big" | |||
"sync" | |||
) | |||
var ( | |||
once sync.Once | |||
p256t1, p384t1, p512t1 *elliptic.CurveParams | |||
p256r1, p384r1, p512r1 *rcurve | |||
) | |||
func initAll() { | |||
initP256t1() | |||
initP384t1() | |||
initP512t1() | |||
initP256r1() | |||
initP384r1() | |||
initP512r1() | |||
} | |||
func initP256t1() { | |||
p256t1 = &elliptic.CurveParams{Name: "brainpoolP256t1"} | |||
p256t1.P, _ = new(big.Int).SetString("A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377", 16) | |||
p256t1.N, _ = new(big.Int).SetString("A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7", 16) | |||
p256t1.B, _ = new(big.Int).SetString("662C61C430D84EA4FE66A7733D0B76B7BF93EBC4AF2F49256AE58101FEE92B04", 16) | |||
p256t1.Gx, _ = new(big.Int).SetString("A3E8EB3CC1CFE7B7732213B23A656149AFA142C47AAFBC2B79A191562E1305F4", 16) | |||
p256t1.Gy, _ = new(big.Int).SetString("2D996C823439C56D7F7B22E14644417E69BCB6DE39D027001DABE8F35B25C9BE", 16) | |||
p256t1.BitSize = 256 | |||
} | |||
func initP256r1() { | |||
twisted := p256t1 | |||
params := &elliptic.CurveParams{ | |||
Name: "brainpoolP256r1", | |||
P: twisted.P, | |||
N: twisted.N, | |||
BitSize: twisted.BitSize, | |||
} | |||
params.Gx, _ = new(big.Int).SetString("8BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262", 16) | |||
params.Gy, _ = new(big.Int).SetString("547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997", 16) | |||
z, _ := new(big.Int).SetString("3E2D4BD9597B58639AE7AA669CAB9837CF5CF20A2C852D10F655668DFC150EF0", 16) | |||
p256r1 = newrcurve(twisted, params, z) | |||
} | |||
func initP384t1() { | |||
p384t1 = &elliptic.CurveParams{Name: "brainpoolP384t1"} | |||
p384t1.P, _ = new(big.Int).SetString("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC53", 16) | |||
p384t1.N, _ = new(big.Int).SetString("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC3103B883202E9046565", 16) | |||
p384t1.B, _ = new(big.Int).SetString("7F519EADA7BDA81BD826DBA647910F8C4B9346ED8CCDC64E4B1ABD11756DCE1D2074AA263B88805CED70355A33B471EE", 16) | |||
p384t1.Gx, _ = new(big.Int).SetString("18DE98B02DB9A306F2AFCD7235F72A819B80AB12EBD653172476FECD462AABFFC4FF191B946A5F54D8D0AA2F418808CC", 16) | |||
p384t1.Gy, _ = new(big.Int).SetString("25AB056962D30651A114AFD2755AD336747F93475B7A1FCA3B88F2B6A208CCFE469408584DC2B2912675BF5B9E582928", 16) | |||
p384t1.BitSize = 384 | |||
} | |||
func initP384r1() { | |||
twisted := p384t1 | |||
params := &elliptic.CurveParams{ | |||
Name: "brainpoolP384r1", | |||
P: twisted.P, | |||
N: twisted.N, | |||
BitSize: twisted.BitSize, | |||
} | |||
params.Gx, _ = new(big.Int).SetString("1D1C64F068CF45FFA2A63A81B7C13F6B8847A3E77EF14FE3DB7FCAFE0CBD10E8E826E03436D646AAEF87B2E247D4AF1E", 16) | |||
params.Gy, _ = new(big.Int).SetString("8ABE1D7520F9C2A45CB1EB8E95CFD55262B70B29FEEC5864E19C054FF99129280E4646217791811142820341263C5315", 16) | |||
z, _ := new(big.Int).SetString("41DFE8DD399331F7166A66076734A89CD0D2BCDB7D068E44E1F378F41ECBAE97D2D63DBC87BCCDDCCC5DA39E8589291C", 16) | |||
p384r1 = newrcurve(twisted, params, z) | |||
} | |||
func initP512t1() { | |||
p512t1 = &elliptic.CurveParams{Name: "brainpoolP512t1"} | |||
p512t1.P, _ = new(big.Int).SetString("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3", 16) | |||
p512t1.N, _ = new(big.Int).SetString("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069", 16) | |||
p512t1.B, _ = new(big.Int).SetString("7CBBBCF9441CFAB76E1890E46884EAE321F70C0BCB4981527897504BEC3E36A62BCDFA2304976540F6450085F2DAE145C22553B465763689180EA2571867423E", 16) | |||
p512t1.Gx, _ = new(big.Int).SetString("640ECE5C12788717B9C1BA06CBC2A6FEBA85842458C56DDE9DB1758D39C0313D82BA51735CDB3EA499AA77A7D6943A64F7A3F25FE26F06B51BAA2696FA9035DA", 16) | |||
p512t1.Gy, _ = new(big.Int).SetString("5B534BD595F5AF0FA2C892376C84ACE1BB4E3019B71634C01131159CAE03CEE9D9932184BEEF216BD71DF2DADF86A627306ECFF96DBB8BACE198B61E00F8B332", 16) | |||
p512t1.BitSize = 512 | |||
} | |||
func initP512r1() { | |||
twisted := p512t1 | |||
params := &elliptic.CurveParams{ | |||
Name: "brainpoolP512r1", | |||
P: twisted.P, | |||
N: twisted.N, | |||
BitSize: twisted.BitSize, | |||
} | |||
params.Gx, _ = new(big.Int).SetString("81AEE4BDD82ED9645A21322E9C4C6A9385ED9F70B5D916C1B43B62EEF4D0098EFF3B1F78E2D0D48D50D1687B93B97D5F7C6D5047406A5E688B352209BCB9F822", 16) | |||
params.Gy, _ = new(big.Int).SetString("7DDE385D566332ECC0EABFA9CF7822FDF209F70024A57B1AA000C55B881F8111B2DCDE494A5F485E5BCA4BD88A2763AED1CA2B2FA8F0540678CD1E0F3AD80892", 16) | |||
z, _ := new(big.Int).SetString("12EE58E6764838B69782136F0F2D3BA06E27695716054092E60A80BEDB212B64E585D90BCE13761F85C3F1D2A64E3BE8FEA2220F01EBA5EEB0F35DBD29D922AB", 16) | |||
p512r1 = newrcurve(twisted, params, z) | |||
} | |||
// P256t1 returns a Curve which implements Brainpool P256t1 (see RFC 5639, section 3.4) | |||
func P256t1() elliptic.Curve { | |||
once.Do(initAll) | |||
return p256t1 | |||
} | |||
// P256r1 returns a Curve which implements Brainpool P256r1 (see RFC 5639, section 3.4) | |||
func P256r1() elliptic.Curve { | |||
once.Do(initAll) | |||
return p256r1 | |||
} | |||
// P384t1 returns a Curve which implements Brainpool P384t1 (see RFC 5639, section 3.6) | |||
func P384t1() elliptic.Curve { | |||
once.Do(initAll) | |||
return p384t1 | |||
} | |||
// P384r1 returns a Curve which implements Brainpool P384r1 (see RFC 5639, section 3.6) | |||
func P384r1() elliptic.Curve { | |||
once.Do(initAll) | |||
return p384r1 | |||
} | |||
// P512t1 returns a Curve which implements Brainpool P512t1 (see RFC 5639, section 3.7) | |||
func P512t1() elliptic.Curve { | |||
once.Do(initAll) | |||
return p512t1 | |||
} | |||
// P512r1 returns a Curve which implements Brainpool P512r1 (see RFC 5639, section 3.7) | |||
func P512r1() elliptic.Curve { | |||
once.Do(initAll) | |||
return p512r1 | |||
} |
@@ -0,0 +1,83 @@ | |||
package brainpool | |||
import ( | |||
"crypto/elliptic" | |||
"math/big" | |||
) | |||
var _ elliptic.Curve = (*rcurve)(nil) | |||
type rcurve struct { | |||
twisted elliptic.Curve | |||
params *elliptic.CurveParams | |||
z *big.Int | |||
zinv *big.Int | |||
z2 *big.Int | |||
z3 *big.Int | |||
zinv2 *big.Int | |||
zinv3 *big.Int | |||
} | |||
var ( | |||
two = big.NewInt(2) | |||
three = big.NewInt(3) | |||
) | |||
func newrcurve(twisted elliptic.Curve, params *elliptic.CurveParams, z *big.Int) *rcurve { | |||
zinv := new(big.Int).ModInverse(z, params.P) | |||
return &rcurve{ | |||
twisted: twisted, | |||
params: params, | |||
z: z, | |||
zinv: zinv, | |||
z2: new(big.Int).Exp(z, two, params.P), | |||
z3: new(big.Int).Exp(z, three, params.P), | |||
zinv2: new(big.Int).Exp(zinv, two, params.P), | |||
zinv3: new(big.Int).Exp(zinv, three, params.P), | |||
} | |||
} | |||
func (curve *rcurve) toTwisted(x, y *big.Int) (*big.Int, *big.Int) { | |||
var tx, ty big.Int | |||
tx.Mul(x, curve.z2) | |||
tx.Mod(&tx, curve.params.P) | |||
ty.Mul(y, curve.z3) | |||
ty.Mod(&ty, curve.params.P) | |||
return &tx, &ty | |||
} | |||
func (curve *rcurve) fromTwisted(tx, ty *big.Int) (*big.Int, *big.Int) { | |||
var x, y big.Int | |||
x.Mul(tx, curve.zinv2) | |||
x.Mod(&x, curve.params.P) | |||
y.Mul(ty, curve.zinv3) | |||
y.Mod(&y, curve.params.P) | |||
return &x, &y | |||
} | |||
func (curve *rcurve) Params() *elliptic.CurveParams { | |||
return curve.params | |||
} | |||
func (curve *rcurve) IsOnCurve(x, y *big.Int) bool { | |||
return curve.twisted.IsOnCurve(curve.toTwisted(x, y)) | |||
} | |||
func (curve *rcurve) Add(x1, y1, x2, y2 *big.Int) (x, y *big.Int) { | |||
tx1, ty1 := curve.toTwisted(x1, y1) | |||
tx2, ty2 := curve.toTwisted(x2, y2) | |||
return curve.fromTwisted(curve.twisted.Add(tx1, ty1, tx2, ty2)) | |||
} | |||
func (curve *rcurve) Double(x1, y1 *big.Int) (x, y *big.Int) { | |||
return curve.fromTwisted(curve.twisted.Double(curve.toTwisted(x1, y1))) | |||
} | |||
func (curve *rcurve) ScalarMult(x1, y1 *big.Int, scalar []byte) (x, y *big.Int) { | |||
tx1, ty1 := curve.toTwisted(x1, y1) | |||
return curve.fromTwisted(curve.twisted.ScalarMult(tx1, ty1, scalar)) | |||
} | |||
func (curve *rcurve) ScalarBaseMult(scalar []byte) (x, y *big.Int) { | |||
return curve.fromTwisted(curve.twisted.ScalarBaseMult(scalar)) | |||
} |
@@ -0,0 +1,162 @@ | |||
// Copyright (C) 2019 ProtonTech AG | |||
// Package eax provides an implementation of the EAX | |||
// (encrypt-authenticate-translate) mode of operation, as described in | |||
// Bellare, Rogaway, and Wagner "THE EAX MODE OF OPERATION: A TWO-PASS | |||
// AUTHENTICATED-ENCRYPTION SCHEME OPTIMIZED FOR SIMPLICITY AND EFFICIENCY." | |||
// In FSE'04, volume 3017 of LNCS, 2004 | |||
package eax | |||
import ( | |||
"crypto/cipher" | |||
"crypto/subtle" | |||
"errors" | |||
"github.com/ProtonMail/go-crypto/internal/byteutil" | |||
) | |||
const ( | |||
defaultTagSize = 16 | |||
defaultNonceSize = 16 | |||
) | |||
type eax struct { | |||
block cipher.Block // Only AES-{128, 192, 256} supported | |||
tagSize int // At least 12 bytes recommended | |||
nonceSize int | |||
} | |||
func (e *eax) NonceSize() int { | |||
return e.nonceSize | |||
} | |||
func (e *eax) Overhead() int { | |||
return e.tagSize | |||
} | |||
// NewEAX returns an EAX instance with AES-{KEYLENGTH} and default nonce and | |||
// tag lengths. Supports {128, 192, 256}- bit key length. | |||
func NewEAX(block cipher.Block) (cipher.AEAD, error) { | |||
return NewEAXWithNonceAndTagSize(block, defaultNonceSize, defaultTagSize) | |||
} | |||
// NewEAXWithNonceAndTagSize returns an EAX instance with AES-{keyLength} and | |||
// given nonce and tag lengths in bytes. Panics on zero nonceSize and | |||
// exceedingly long tags. | |||
// | |||
// It is recommended to use at least 12 bytes as tag length (see, for instance, | |||
// NIST SP 800-38D). | |||
// | |||
// Only to be used for compatibility with existing cryptosystems with | |||
// non-standard parameters. For all other cases, prefer NewEAX. | |||
func NewEAXWithNonceAndTagSize( | |||
block cipher.Block, nonceSize, tagSize int) (cipher.AEAD, error) { | |||
if nonceSize < 1 { | |||
return nil, eaxError("Cannot initialize EAX with nonceSize = 0") | |||
} | |||
if tagSize > block.BlockSize() { | |||
return nil, eaxError("Custom tag length exceeds blocksize") | |||
} | |||
return &eax{ | |||
block: block, | |||
tagSize: tagSize, | |||
nonceSize: nonceSize, | |||
}, nil | |||
} | |||
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) | |||
omacNonce := e.omacT(0, nonce) | |||
omacAdata := e.omacT(1, adata) | |||
// Encrypt message using CTR mode and omacNonce as IV | |||
ctr := cipher.NewCTR(e.block, omacNonce) | |||
ciphertextData := out[:len(plaintext)] | |||
ctr.XORKeyStream(ciphertextData, plaintext) | |||
omacCiphertext := e.omacT(2, ciphertextData) | |||
tag := out[len(plaintext):] | |||
for i := 0; i < e.tagSize; i++ { | |||
tag[i] = omacCiphertext[i] ^ omacNonce[i] ^ omacAdata[i] | |||
} | |||
return ret | |||
} | |||
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") | |||
} | |||
if len(ciphertext) < e.tagSize { | |||
return nil, eaxError("Ciphertext shorter than tag length") | |||
} | |||
sep := len(ciphertext) - e.tagSize | |||
// Compute tag | |||
omacNonce := e.omacT(0, nonce) | |||
omacAdata := e.omacT(1, adata) | |||
omacCiphertext := e.omacT(2, ciphertext[:sep]) | |||
tag := make([]byte, e.tagSize) | |||
for i := 0; i < e.tagSize; i++ { | |||
tag[i] = omacCiphertext[i] ^ omacNonce[i] ^ omacAdata[i] | |||
} | |||
// Compare tags | |||
if subtle.ConstantTimeCompare(ciphertext[sep:], tag) != 1 { | |||
return nil, eaxError("Tag authentication failed") | |||
} | |||
// Decrypt ciphertext | |||
ret, out := byteutil.SliceForAppend(dst, len(ciphertext)) | |||
ctr := cipher.NewCTR(e.block, omacNonce) | |||
ctr.XORKeyStream(out, ciphertext[:sep]) | |||
return ret[:sep], nil | |||
} | |||
// Tweakable OMAC - Calls OMAC_K([t]_n || plaintext) | |||
func (e *eax) omacT(t byte, plaintext []byte) []byte { | |||
blockSize := e.block.BlockSize() | |||
byteT := make([]byte, blockSize) | |||
byteT[blockSize-1] = t | |||
concat := append(byteT, plaintext...) | |||
return e.omac(concat) | |||
} | |||
func (e *eax) omac(plaintext []byte) []byte { | |||
blockSize := e.block.BlockSize() | |||
// L ← E_K(0^n); B ← 2L; P ← 4L | |||
L := make([]byte, blockSize) | |||
e.block.Encrypt(L, L) | |||
B := byteutil.GfnDouble(L) | |||
P := byteutil.GfnDouble(B) | |||
// CBC with IV = 0 | |||
cbc := cipher.NewCBCEncrypter(e.block, make([]byte, blockSize)) | |||
padded := e.pad(plaintext, B, P) | |||
cbcCiphertext := make([]byte, len(padded)) | |||
cbc.CryptBlocks(cbcCiphertext, padded) | |||
return cbcCiphertext[len(cbcCiphertext)-blockSize:] | |||
} | |||
func (e *eax) pad(plaintext, B, P []byte) []byte { | |||
// if |M| in {n, 2n, 3n, ...} | |||
blockSize := e.block.BlockSize() | |||
if len(plaintext) != 0 && len(plaintext)%blockSize == 0 { | |||
return byteutil.RightXor(plaintext, B) | |||
} | |||
// else return (M || 1 || 0^(n−1−(|M| % n))) xor→ P | |||
ending := make([]byte, blockSize-len(plaintext)%blockSize) | |||
ending[0] = 0x80 | |||
padded := append(plaintext, ending...) | |||
return byteutil.RightXor(padded, P) | |||
} | |||
func eaxError(err string) error { | |||
return errors.New("crypto/eax: " + err) | |||
} |
@@ -0,0 +1,58 @@ | |||
package eax | |||
// Test vectors from | |||
// https://web.cs.ucdavis.edu/~rogaway/papers/eax.pdf | |||
var testVectors = []struct { | |||
msg, key, nonce, header, ciphertext string | |||
}{ | |||
{"", | |||
"233952DEE4D5ED5F9B9C6D6FF80FF478", | |||
"62EC67F9C3A4A407FCB2A8C49031A8B3", | |||
"6BFB914FD07EAE6B", | |||
"E037830E8389F27B025A2D6527E79D01"}, | |||
{"F7FB", | |||
"91945D3F4DCBEE0BF45EF52255F095A4", | |||
"BECAF043B0A23D843194BA972C66DEBD", | |||
"FA3BFD4806EB53FA", | |||
"19DD5C4C9331049D0BDAB0277408F67967E5"}, | |||
{"1A47CB4933", | |||
"01F74AD64077F2E704C0F60ADA3DD523", | |||
"70C3DB4F0D26368400A10ED05D2BFF5E", | |||
"234A3463C1264AC6", | |||
"D851D5BAE03A59F238A23E39199DC9266626C40F80"}, | |||
{"481C9E39B1", | |||
"D07CF6CBB7F313BDDE66B727AFD3C5E8", | |||
"8408DFFF3C1A2B1292DC199E46B7D617", | |||
"33CCE2EABFF5A79D", | |||
"632A9D131AD4C168A4225D8E1FF755939974A7BEDE"}, | |||
{"40D0C07DA5E4", | |||
"35B6D0580005BBC12B0587124557D2C2", | |||
"FDB6B06676EEDC5C61D74276E1F8E816", | |||
"AEB96EAEBE2970E9", | |||
"071DFE16C675CB0677E536F73AFE6A14B74EE49844DD"}, | |||
{"4DE3B35C3FC039245BD1FB7D", | |||
"BD8E6E11475E60B268784C38C62FEB22", | |||
"6EAC5C93072D8E8513F750935E46DA1B", | |||
"D4482D1CA78DCE0F", | |||
"835BB4F15D743E350E728414ABB8644FD6CCB86947C5E10590210A4F"}, | |||
{"8B0A79306C9CE7ED99DAE4F87F8DD61636", | |||
"7C77D6E813BED5AC98BAA417477A2E7D", | |||
"1A8C98DCD73D38393B2BF1569DEEFC19", | |||
"65D2017990D62528", | |||
"02083E3979DA014812F59F11D52630DA30137327D10649B0AA6E1C181DB617D7F2"}, | |||
{"1BDA122BCE8A8DBAF1877D962B8592DD2D56", | |||
"5FFF20CAFAB119CA2FC73549E20F5B0D", | |||
"DDE59B97D722156D4D9AFF2BC7559826", | |||
"54B9F04E6A09189A", | |||
"2EC47B2C4954A489AFC7BA4897EDCDAE8CC33B60450599BD02C96382902AEF7F832A"}, | |||
{"6CF36720872B8513F6EAB1A8A44438D5EF11", | |||
"A4A4782BCFFD3EC5E7EF6D8C34A56123", | |||
"B781FCF2F75FA5A8DE97A9CA48E522EC", | |||
"899A175897561D7E", | |||
"0DE18FD0FDD91E7AF19F1D8EE8733938B1E8E7F6D2231618102FDB7FE55FF1991700"}, | |||
{"CA40D7446E545FFAED3BD12A740A659FFBBB3CEAB7", | |||
"8395FCF1E95BEBD697BD010BC766AAC3", | |||
"22E7ADD93CFC6393C57EC0B3C17D6B44", | |||
"126735FCC320D25A", | |||
"CB8920F87A6C75CFF39627B56E3ED197C552D295A7CFC46AFC253B4652B1AF3795B124AB6E"}, | |||
} |
@@ -0,0 +1,131 @@ | |||
// These vectors include key length in {128, 192, 256}, tag size 128, and | |||
// random nonce, header, and plaintext lengths. | |||
// This file was automatically generated. | |||
package eax | |||
var randomVectors = []struct { | |||
key, nonce, header, plaintext, ciphertext string | |||
}{ | |||
{"DFDE093F36B0356E5A81F609786982E3", | |||
"1D8AC604419001816905BA72B14CED7E", | |||
"152A1517A998D7A24163FCDD146DE81AC347C8B97088F502093C1ABB8F6E33D9A219C34D7603A18B1F5ABE02E56661B7D7F67E81EC08C1302EF38D80A859486D450E94A4F26AD9E68EEBBC0C857A0FC5CF9E641D63D565A7E361BC8908F5A8DC8FD6", | |||
"1C8EAAB71077FE18B39730A3156ADE29C5EE824C7EE86ED2A253B775603FB237116E654F6FEC588DD27F523A0E01246FE73FE348491F2A8E9ABC6CA58D663F71CDBCF4AD798BE46C42AE6EE8B599DB44A1A48D7BBBBA0F7D2750181E1C5E66967F7D57CBD30AFBDA5727", | |||
"79E7E150934BBEBF7013F61C60462A14D8B15AF7A248AFB8A344EF021C1500E16666891D6E973D8BB56B71A371F12CA34660C4410C016982B20F547E3762A58B7BF4F20236CADCF559E2BE7D783B13723B2741FC7CDC8997D839E39A3DDD2BADB96743DD7049F1BDB0516A262869915B3F70498AFB7B191BF960"}, | |||
{"F10619EF02E5D94D7550EB84ED364A21", | |||
"8DC0D4F2F745BBAE835CC5574B942D20", | |||
"FE561358F2E8DF7E1024FF1AE9A8D36EBD01352214505CB99D644777A8A1F6027FA2BDBFC529A9B91136D5F2416CFC5F0F4EC3A1AFD32BDDA23CA504C5A5CB451785FABF4DFE4CD50D817491991A60615B30286361C100A95D1712F2A45F8E374461F4CA2B", | |||
"D7B5A971FC219631D30EFC3664AE3127D9CF3097DAD9C24AC7905D15E8D9B25B026B31D68CAE00975CDB81EB1FD96FD5E1A12E2BB83FA25F1B1D91363457657FC03875C27F2946C5", | |||
"2F336ED42D3CC38FC61660C4CD60BA4BD438B05F5965D8B7B399D2E7167F5D34F792D318F94DB15D67463AC449E13D568CC09BFCE32A35EE3EE96A041927680AE329811811E27F2D1E8E657707AF99BA96D13A478D695D59"}, | |||
{"429F514EFC64D98A698A9247274CFF45", | |||
"976AA5EB072F912D126ACEBC954FEC38", | |||
"A71D89DC5B6CEDBB7451A27C3C2CAE09126DB4C421", | |||
"5632FE62AB1DC549D54D3BC3FC868ACCEDEFD9ECF5E9F8", | |||
"848AE4306CA8C7F416F8707625B7F55881C0AB430353A5C967CDA2DA787F581A70E34DBEBB2385"}, | |||
{"398138F309085F47F8457CDF53895A63", | |||
"F8A8A7F2D28E5FFF7BBC2F24353F7A36", | |||
"5D633C21BA7764B8855CAB586F3746E236AD486039C83C6B56EFA9C651D38A41D6B20DAEE3418BFEA44B8BD6", | |||
"A3BBAA91920AF5E10659818B1B3B300AC79BFC129C8329E75251F73A66D3AE0128EB91D5031E0A65C329DB7D1E9C0493E268", | |||
"D078097267606E5FB07CFB7E2B4B718172A82C6A4CEE65D549A4DFB9838003BD2FBF64A7A66988AC1A632FD88F9E9FBB57C5A78AD2E086EACBA3DB68511D81C2970A"}, | |||
{"7A4151EBD3901B42CBA45DAFB2E931BA", | |||
"0FC88ACEE74DD538040321C330974EB8", | |||
"250464FB04733BAB934C59E6AD2D6AE8D662CBCFEFBE61E5A308D4211E58C4C25935B72C69107722E946BFCBF416796600542D76AEB73F2B25BF53BAF97BDEB36ED3A7A51C31E7F170EB897457E7C17571D1BA0A908954E9", | |||
"88C41F3EBEC23FAB8A362D969CAC810FAD4F7CA6A7F7D0D44F060F92E37E1183768DD4A8C733F71C96058D362A39876D183B86C103DE", | |||
"74A25B2182C51096D48A870D80F18E1CE15867778E34FCBA6BD7BFB3739FDCD42AD0F2D9F4EBA29085285C6048C15BCE5E5166F1F962D3337AA88E6062F05523029D0A7F0BF9"}, | |||
{"BFB147E1CD5459424F8C0271FC0E0DC5", | |||
"EABCC126442BF373969EA3015988CC45", | |||
"4C0880E1D71AA2C7", | |||
"BE1B5EC78FBF73E7A6682B21BA7E0E5D2D1C7ABE", | |||
"5660D7C1380E2F306895B1402CB2D6C37876504276B414D120F4CF92FDDDBB293A238EA0"}, | |||
{"595DD6F52D18BC2CA8EB4EDAA18D9FA3", | |||
"0F84B5D36CF4BC3B863313AF3B4D2E97", | |||
"30AE6CC5F99580F12A779D98BD379A60948020C0B6FBD5746B30BA3A15C6CD33DAF376C70A9F15B6C0EB410A93161F7958AE23", | |||
"8EF3687A1642B070970B0B91462229D1D76ABC154D18211F7152AA9FF368", | |||
"317C1DDB11417E5A9CC4DDE7FDFF6659A5AC4B31DE025212580A05CDAC6024D3E4AE7C2966E52B9129E9ECDBED86"}, | |||
{"44E6F2DC8FDC778AD007137D11410F50", | |||
"270A237AD977F7187AA6C158A0BAB24F", | |||
"509B0F0EB12E2AA5C5BA2DE553C07FAF4CE0C9E926531AA709A3D6224FCB783ACCF1559E10B1123EBB7D52E8AB54E6B5352A9ED0D04124BF0E9D9BACFD7E32B817B2E625F5EE94A64EDE9E470DE7FE6886C19B294F9F828209FE257A78", | |||
"8B3D7815DF25618A5D0C55A601711881483878F113A12EC36CF64900549A3199555528559DC118F789788A55FAFD944E6E99A9CA3F72F238CD3F4D88223F7A745992B3FAED1848", | |||
"1CC00D79F7AD82FDA71B58D286E5F34D0CC4CEF30704E771CC1E50746BDF83E182B078DB27149A42BAE619DF0F85B0B1090AD55D3B4471B0D6F6ECCD09C8F876B30081F0E7537A9624F8AAF29DA85E324122EFB4D68A56"}, | |||
{"BB7BC352A03044B4428D8DBB4B0701FDEC4649FD17B81452", | |||
"8B4BBE26CCD9859DCD84884159D6B0A4", | |||
"2212BEB0E78E0F044A86944CF33C8D5C80D9DBE1034BF3BCF73611835C7D3A52F5BD2D81B68FD681B68540A496EE5DA16FD8AC8824E60E1EC2042BE28FB0BFAD4E4B03596446BDD8C37D936D9B3D5295BE19F19CF5ACE1D33A46C952CE4DE5C12F92C1DD051E04AEED", | |||
"9037234CC44FFF828FABED3A7084AF40FA7ABFF8E0C0EFB57A1CC361E18FC4FAC1AB54F3ABFE9FF77263ACE16C3A", | |||
"A9391B805CCD956081E0B63D282BEA46E7025126F1C1631239C33E92AA6F92CD56E5A4C56F00FF9658E93D48AF4EF0EF81628E34AD4DB0CDAEDCD2A17EE7"}, | |||
{"99C0AD703196D2F60A74E6B378B838B31F82EA861F06FC4E", | |||
"92745C018AA708ECFEB1667E9F3F1B01", | |||
"828C69F376C0C0EC651C67749C69577D589EE39E51404D80EBF70C8660A8F5FD375473F4A7C611D59CB546A605D67446CE2AA844135FCD78BB5FBC90222A00D42920BB1D7EEDFB0C4672554F583EF23184F89063CDECBE482367B5F9AF3ACBC3AF61392BD94CBCD9B64677", | |||
"A879214658FD0A5B0E09836639BF82E05EC7A5EF71D4701934BDA228435C68AC3D5CEB54997878B06A655EEACEFB1345C15867E7FE6C6423660C8B88DF128EBD6BCD85118DBAE16E9252FFB204324E5C8F38CA97759BDBF3CB0083", | |||
"51FE87996F194A2585E438B023B345439EA60D1AEBED4650CDAF48A4D4EEC4FC77DC71CC4B09D3BEEF8B7B7AF716CE2B4EFFB3AC9E6323C18AC35E0AA6E2BBBC8889490EB6226C896B0D105EAB42BFE7053CCF00ED66BA94C1BA09A792AA873F0C3B26C5C5F9A936E57B25"}, | |||
{"7086816D00D648FB8304AA8C9E552E1B69A9955FB59B25D1", | |||
"0F45CF7F0BF31CCEB85D9DA10F4D749F", | |||
"93F27C60A417D9F0669E86ACC784FC8917B502DAF30A6338F11B30B94D74FEFE2F8BE1BBE2EAD10FAB7EED3C6F72B7C3ECEE1937C32ED4970A6404E139209C05", | |||
"877F046601F3CBE4FB1491943FA29487E738F94B99AF206262A1D6FF856C9AA0B8D4D08A54370C98F8E88FA3DCC2B14C1F76D71B2A4C7963AEE8AF960464C5BEC8357AD00DC8", | |||
"FE96906B895CE6A8E72BC72344E2C8BB3C63113D70EAFA26C299BAFE77A8A6568172EB447FB3E86648A0AF3512DEB1AAC0819F3EC553903BF28A9FB0F43411237A774BF9EE03E445D280FBB9CD12B9BAAB6EF5E52691"}, | |||
{"062F65A896D5BF1401BADFF70E91B458E1F9BD4888CB2E4D", | |||
"5B11EA1D6008EBB41CF892FCA5B943D1", | |||
"BAF4FF5C8242", | |||
"A8870E091238355984EB2F7D61A865B9170F440BFF999A5993DD41A10F4440D21FF948DDA2BF663B2E03AC3324492DC5E40262ECC6A65C07672353BE23E7FB3A9D79FF6AA38D97960905A38DECC312CB6A59E5467ECF06C311CD43ADC0B543EDF34FE8BE611F176460D5627CA51F8F8D9FED71F55C", | |||
"B10E127A632172CF8AA7539B140D2C9C2590E6F28C3CB892FC498FCE56A34F732FBFF32E79C7B9747D9094E8635A0C084D6F0247F9768FB5FF83493799A9BEC6C39572120C40E9292C8C947AE8573462A9108C36D9D7112E6995AE5867E6C8BB387D1C5D4BEF524F391B9FD9F0A3B4BFA079E915BCD920185CFD38D114C558928BD7D47877"}, | |||
{"38A8E45D6D705A11AF58AED5A1344896998EACF359F2E26A", | |||
"FD82B5B31804FF47D44199B533D0CF84", | |||
"DE454D4E62FE879F2050EE3E25853623D3E9AC52EEC1A1779A48CFAF5ECA0BFDE44749391866D1", | |||
"B804", | |||
"164BB965C05EBE0931A1A63293EDF9C38C27"}, | |||
{"34C33C97C6D7A0850DA94D78A58DC61EC717CD7574833068", | |||
"343BE00DA9483F05C14F2E9EB8EA6AE8", | |||
"78312A43EFDE3CAE34A65796FF059A3FE15304EEA5CF1D9306949FE5BF3349D4977D4EBE76C040FE894C5949E4E4D6681153DA87FB9AC5062063CA2EA183566343362370944CE0362D25FC195E124FD60E8682E665D13F2229DDA3E4B2CB1DCA", | |||
"CC11BB284B1153578E4A5ED9D937B869DAF00F5B1960C23455CA9CC43F486A3BE0B66254F1041F04FDF459C8640465B6E1D2CF899A381451E8E7FCB50CF87823BE77E24B132BBEEDC72E53369B275E1D8F49ECE59F4F215230AC4FE133FC80E4F634EE80BA4682B62C86", | |||
"E7F703DC31A95E3A4919FF957836CB76C063D81702AEA4703E1C2BF30831E58C4609D626EC6810E12EAA5B930F049FF9EFC22C3E3F1EBD4A1FB285CB02A1AC5AD46B425199FC0A85670A5C4E3DAA9636C8F64C199F42F18AAC8EA7457FD377F322DD7752D7D01B946C8F0A97E6113F0D50106F319AFD291AAACE"}, | |||
{"C6ECF7F053573E403E61B83052A343D93CBCC179D1E835BE", | |||
"E280E13D7367042E3AA09A80111B6184", | |||
"21486C9D7A9647", | |||
"5F2639AFA6F17931853791CD8C92382BBB677FD72D0AB1A080D0E49BFAA21810E963E4FACD422E92F65CBFAD5884A60CD94740DF31AF02F95AA57DA0C4401B0ED906", | |||
"5C51DB20755302070C45F52E50128A67C8B2E4ED0EACB7E29998CCE2E8C289DD5655913EC1A51CC3AABE5CDC2402B2BE7D6D4BF6945F266FBD70BA9F37109067157AE7530678B45F64475D4EBFCB5FFF46A5"}, | |||
{"5EC6CF7401BC57B18EF154E8C38ACCA8959E57D2F3975FF5", | |||
"656B41CB3F9CF8C08BAD7EBFC80BD225", | |||
"6B817C2906E2AF425861A7EF59BA5801F143EE2A139EE72697CDE168B4", | |||
"2C0E1DDC9B1E5389BA63845B18B1F8A1DB062037151BCC56EF7C21C0BB4DAE366636BBA975685D7CC5A94AFBE89C769016388C56FB7B57CE750A12B718A8BDCF70E80E8659A8330EFC8F86640F21735E8C80E23FE43ABF23507CE3F964AE4EC99D", | |||
"ED780CF911E6D1AA8C979B889B0B9DC1ABE261832980BDBFB576901D9EF5AB8048998E31A15BE54B3E5845A4D136AD24D0BDA1C3006168DF2F8AC06729CB0818867398150020131D8F04EDF1923758C9EABB5F735DE5EA1758D4BC0ACFCA98AFD202E9839B8720253693B874C65586C6F0"}, | |||
{"C92F678EB2208662F5BCF3403EC05F5961E957908A3E79421E1D25FC19054153", | |||
"DA0F3A40983D92F2D4C01FED33C7A192", | |||
"2B6E9D26DB406A0FAB47608657AA10EFC2B4AA5F459B29FF85AC9A40BFFE7AEB04F77E9A11FAAA116D7F6D4DA417671A9AB02C588E0EF59CB1BFB4B1CC931B63A3B3A159FCEC97A04D1E6F0C7E6A9CEF6B0ABB04758A69F1FE754DF4C2610E8C46B6CF413BDB31351D55BEDCB7B4A13A1C98E10984475E0F2F957853", | |||
"F37326A80E08", | |||
"83519E53E321D334F7C10B568183775C0E9AAE55F806"}, | |||
{"6847E0491BE57E72995D186D50094B0B3593957A5146798FCE68B287B2FB37B5", | |||
"3EE1182AEBB19A02B128F28E1D5F7F99", | |||
"D9F35ABB16D776CE", | |||
"DB7566ED8EA95BDF837F23DB277BAFBC5E70D1105ADFD0D9EF15475051B1EF94709C67DCA9F8D5", | |||
"2CDCED0C9EBD6E2A508822A685F7DCD1CDD99E7A5FCA786C234E7F7F1D27EC49751AD5DCFA30C5EDA87C43CAE3B919B6BBCFE34C8EDA59"}, | |||
{"82B019673642C08388D3E42075A4D5D587558C229E4AB8F660E37650C4C41A0A", | |||
"336F5D681E0410FAE7B607246092C6DC", | |||
"D430CBD8FE435B64214E9E9CDC5DE99D31CFCFB8C10AA0587A49DF276611", | |||
"998404153AD77003E1737EDE93ED79859EE6DCCA93CB40C4363AA817ABF2DBBD46E42A14A7183B6CC01E12A577888141363D0AE011EB6E8D28C0B235", | |||
"9BEF69EEB60BD3D6065707B7557F25292A8872857CFBD24F2F3C088E4450995333088DA50FD9121221C504DF1D0CD5EFE6A12666C5D5BB12282CF4C19906E9CFAB97E9BDF7F49DC17CFC384B"}, | |||
{"747B2E269B1859F0622C15C8BAD6A725028B1F94B8DB7326948D1E6ED663A8BC", | |||
"AB91F7245DDCE3F1C747872D47BE0A8A", | |||
"3B03F786EF1DDD76E1D42646DA4CD2A5165DC5383CE86D1A0B5F13F910DC278A4E451EE0192CBA178E13B3BA27FDC7840DF73D2E104B", | |||
"6B803F4701114F3E5FE21718845F8416F70F626303F545BE197189E0A2BA396F37CE06D389EB2658BC7D56D67868708F6D0D32", | |||
"1570DDB0BCE75AA25D1957A287A2C36B1A5F2270186DA81BA6112B7F43B0F3D1D0ED072591DCF1F1C99BBB25621FC39B896FF9BD9413A2845363A9DCD310C32CF98E57"}, | |||
{"02E59853FB29AEDA0FE1C5F19180AD99A12FF2F144670BB2B8BADF09AD812E0A", | |||
"C691294EF67CD04D1B9242AF83DD1421", | |||
"879334DAE3", | |||
"1E17F46A98FEF5CBB40759D95354", | |||
"FED8C3FF27DDF6313AED444A2985B36CBA268AAD6AAC563C0BA28F6DB5DB"}, | |||
{"F6C1FB9B4188F2288FF03BD716023198C3582CF2A037FC2F29760916C2B7FCDB", | |||
"4228DA0678CA3534588859E77DFF014C", | |||
"D8153CAF35539A61DD8D05B3C9B44F01E564FB9348BCD09A1C23B84195171308861058F0A3CD2A55B912A3AAEE06FF4D356C77275828F2157C2FC7C115DA39E443210CCC56BEDB0CC99BBFB227ABD5CC454F4E7F547C7378A659EEB6A7E809101A84F866503CB18D4484E1FA09B3EC7FC75EB2E35270800AA7", | |||
"23B660A779AD285704B12EC1C580387A47BEC7B00D452C6570", | |||
"5AA642BBABA8E49849002A2FAF31DB8FC7773EFDD656E469CEC19B3206D4174C9A263D0A05484261F6"}, | |||
{"8FF6086F1FADB9A3FBE245EAC52640C43B39D43F89526BB5A6EBA47710931446", | |||
"943188480C99437495958B0AE4831AA9", | |||
"AD5CD0BDA426F6EBA23C8EB23DC73FF9FEC173355EDBD6C9344C4C4383F211888F7CE6B29899A6801DF6B38651A7C77150941A", | |||
"80CD5EA8D7F81DDF5070B934937912E8F541A5301877528EB41AB60C020968D459960ED8FB73083329841A", | |||
"ABAE8EB7F36FCA2362551E72DAC890BA1BB6794797E0FC3B67426EC9372726ED4725D379EA0AC9147E48DCD0005C502863C2C5358A38817C8264B5"}, | |||
{"A083B54E6B1FE01B65D42FCD248F97BB477A41462BBFE6FD591006C022C8FD84", | |||
"B0490F5BD68A52459556B3749ACDF40E", | |||
"8892E047DA5CFBBDF7F3CFCBD1BD21C6D4C80774B1826999234394BD3E513CC7C222BB40E1E3140A152F19B3802F0D036C24A590512AD0E8", | |||
"D7B15752789DC94ED0F36778A5C7BBB207BEC32BAC66E702B39966F06E381E090C6757653C3D26A81EC6AD6C364D66867A334C91BB0B8A8A4B6EACDF0783D09010AEBA2DD2062308FE99CC1F", | |||
"C071280A732ADC93DF272BF1E613B2BB7D46FC6665EF2DC1671F3E211D6BDE1D6ADDD28DF3AA2E47053FC8BB8AE9271EC8BC8B2CFFA320D225B451685B6D23ACEFDD241FE284F8ADC8DB07F456985B14330BBB66E0FB212213E05B3E"}, | |||
} |
@@ -0,0 +1,90 @@ | |||
// Copyright (C) 2019 ProtonTech AG | |||
// This file contains necessary tools for the aex and ocb packages. | |||
// | |||
// These functions SHOULD NOT be used elsewhere, since they are optimized for | |||
// specific input nature in the EAX and OCB modes of operation. | |||
package byteutil | |||
// GfnDouble computes 2 * input in the field of 2^n elements. | |||
// The irreducible polynomial in the finite field for n=128 is | |||
// x^128 + x^7 + x^2 + x + 1 (equals 0x87) | |||
// Constant-time execution in order to avoid side-channel attacks | |||
func GfnDouble(input []byte) []byte { | |||
if len(input) != 16 { | |||
panic("Doubling in GFn only implemented for n = 128") | |||
} | |||
// If the first bit is zero, return 2L = L << 1 | |||
// Else return (L << 1) xor 0^120 10000111 | |||
shifted := ShiftBytesLeft(input) | |||
shifted[15] ^= ((input[0] >> 7) * 0x87) | |||
return shifted | |||
} | |||
// ShiftBytesLeft outputs the byte array corresponding to x << 1 in binary. | |||
func ShiftBytesLeft(x []byte) []byte { | |||
l := len(x) | |||
dst := make([]byte, l) | |||
for i := 0; i < l-1; i++ { | |||
dst[i] = (x[i] << 1) | (x[i+1] >> 7) | |||
} | |||
dst[l-1] = x[l-1] << 1 | |||
return dst | |||
} | |||
// ShiftNBytesLeft puts in dst the byte array corresponding to x << n in binary. | |||
func ShiftNBytesLeft(dst, x []byte, n int) { | |||
// Erase first n / 8 bytes | |||
copy(dst, x[n/8:]) | |||
// Shift the remaining n % 8 bits | |||
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[l-1] = dst[l-1] << bits | |||
// Append trailing zeroes | |||
dst = append(dst, make([]byte, n/8)...) | |||
} | |||
// XorBytesMut assumes equal input length, replaces X with X XOR Y | |||
func XorBytesMut(X, Y []byte) { | |||
for i := 0; i < len(X); i++ { | |||
X[i] ^= Y[i] | |||
} | |||
} | |||
// XorBytes assumes equal input length, puts X XOR Y into Z | |||
func XorBytes(Z, X, Y []byte) { | |||
for i := 0; i < len(X); i++ { | |||
Z[i] = X[i] ^ Y[i] | |||
} | |||
} | |||
// 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)) | |||
copy(xored, X) | |||
for i := 0; i < len(Y); i++ { | |||
xored[offset+i] ^= Y[i] | |||
} | |||
return xored | |||
} | |||
// SliceForAppend takes a slice and a requested number of bytes. It returns a | |||
// slice with the contents of the given slice followed by that many bytes and a | |||
// second slice that aliases into it and contains only the extra bytes. If the | |||
// original slice has sufficient capacity then no allocation is performed. | |||
func SliceForAppend(in []byte, n int) (head, tail []byte) { | |||
if total := len(in) + n; cap(in) >= total { | |||
head = in[:total] | |||
} else { | |||
head = make([]byte, total) | |||
copy(head, in) | |||
} | |||
tail = head[len(in):] | |||
return | |||
} |
@@ -0,0 +1,317 @@ | |||
// Copyright (C) 2019 ProtonTech AG | |||
// Package ocb provides an implementation of the OCB (offset codebook) mode of | |||
// operation, as described in RFC-7253 of the IRTF and in Rogaway, Bellare, | |||
// Black and Krovetz - OCB: A BLOCK-CIPHER MODE OF OPERATION FOR EFFICIENT | |||
// AUTHENTICATED ENCRYPTION (2003). | |||
// Security considerations (from RFC-7253): A private key MUST NOT be used to | |||
// encrypt more than 2^48 blocks. Tag length should be at least 12 bytes (a | |||
// brute-force forging adversary succeeds after 2^{tag length} attempts). A | |||
// single key SHOULD NOT be used to decrypt ciphertext with different tag | |||
// lengths. Nonces need not be secret, but MUST NOT be reused. | |||
// This package only supports underlying block ciphers with 128-bit blocks, | |||
// such as AES-{128, 192, 256}, but may be extended to other sizes. | |||
package ocb | |||
import ( | |||
"bytes" | |||
"crypto/cipher" | |||
"crypto/subtle" | |||
"errors" | |||
"github.com/ProtonMail/go-crypto/internal/byteutil" | |||
"math/bits" | |||
) | |||
type ocb struct { | |||
block cipher.Block | |||
tagSize int | |||
nonceSize int | |||
mask mask | |||
// Optimized en/decrypt: For each nonce N used to en/decrypt, the 'Ktop' | |||
// internal variable can be reused for en/decrypting with nonces sharing | |||
// all but the last 6 bits with N. The prefix of the first nonce used to | |||
// compute the new Ktop, and the Ktop value itself, are stored in | |||
// reusableKtop. If using incremental nonces, this saves one block cipher | |||
// call every 63 out of 64 OCB encryptions, and stores one nonce and one | |||
// output of the block cipher in memory only. | |||
reusableKtop reusableKtop | |||
} | |||
type mask struct { | |||
// L_*, L_$, (L_i)_{i ∈ N} | |||
lAst []byte | |||
lDol []byte | |||
L [][]byte | |||
} | |||
type reusableKtop struct { | |||
noncePrefix []byte | |||
Ktop []byte | |||
} | |||
const ( | |||
defaultTagSize = 16 | |||
defaultNonceSize = 15 | |||
) | |||
const ( | |||
enc = iota | |||
dec | |||
) | |||
func (o *ocb) NonceSize() int { | |||
return o.nonceSize | |||
} | |||
func (o *ocb) Overhead() int { | |||
return o.tagSize | |||
} | |||
// NewOCB returns an OCB instance with the given block cipher and default | |||
// tag and nonce sizes. | |||
func NewOCB(block cipher.Block) (cipher.AEAD, error) { | |||
return NewOCBWithNonceAndTagSize(block, defaultNonceSize, defaultTagSize) | |||
} | |||
// NewOCBWithNonceAndTagSize returns an OCB instance with the given block | |||
// cipher, nonce length, and tag length. Panics on zero nonceSize and | |||
// exceedingly long tag size. | |||
// | |||
// It is recommended to use at least 12 bytes as tag length. | |||
func NewOCBWithNonceAndTagSize( | |||
block cipher.Block, nonceSize, tagSize int) (cipher.AEAD, error) { | |||
if block.BlockSize() != 16 { | |||
return nil, ocbError("Block cipher must have 128-bit blocks") | |||
} | |||
if nonceSize < 1 { | |||
return nil, ocbError("Incorrect nonce length") | |||
} | |||
if nonceSize >= block.BlockSize() { | |||
return nil, ocbError("Nonce length exceeds blocksize - 1") | |||
} | |||
if tagSize > block.BlockSize() { | |||
return nil, ocbError("Custom tag length exceeds blocksize") | |||
} | |||
return &ocb{ | |||
block: block, | |||
tagSize: tagSize, | |||
nonceSize: nonceSize, | |||
mask: initializeMaskTable(block), | |||
reusableKtop: reusableKtop{ | |||
noncePrefix: nil, | |||
Ktop: nil, | |||
}, | |||
}, nil | |||
} | |||
func (o *ocb) Seal(dst, nonce, plaintext, adata []byte) []byte { | |||
if len(nonce) > o.nonceSize { | |||
panic("crypto/ocb: Incorrect nonce length given to OCB") | |||
} | |||
ret, out := byteutil.SliceForAppend(dst, len(plaintext)+o.tagSize) | |||
o.crypt(enc, out, nonce, adata, plaintext) | |||
return ret | |||
} | |||
func (o *ocb) Open(dst, nonce, ciphertext, adata []byte) ([]byte, error) { | |||
if len(nonce) > o.nonceSize { | |||
panic("Nonce too long for this instance") | |||
} | |||
if len(ciphertext) < o.tagSize { | |||
return nil, ocbError("Ciphertext shorter than tag length") | |||
} | |||
sep := len(ciphertext) - o.tagSize | |||
ret, out := byteutil.SliceForAppend(dst, len(ciphertext)) | |||
ciphertextData := ciphertext[:sep] | |||
tag := ciphertext[sep:] | |||
o.crypt(dec, out, nonce, adata, ciphertextData) | |||
if subtle.ConstantTimeCompare(ret[sep:], tag) == 1 { | |||
ret = ret[:sep] | |||
return ret, nil | |||
} | |||
for i := range out { | |||
out[i] = 0 | |||
} | |||
return nil, ocbError("Tag authentication failed") | |||
} | |||
// On instruction enc (resp. dec), crypt is the encrypt (resp. decrypt) | |||
// function. It returns the resulting plain/ciphertext with the tag appended. | |||
func (o *ocb) crypt(instruction int, Y, nonce, adata, X []byte) []byte { | |||
// | |||
// Consider X as a sequence of 128-bit blocks | |||
// | |||
// Note: For encryption (resp. decryption), X is the plaintext (resp., the | |||
// ciphertext without the tag). | |||
blockSize := o.block.BlockSize() | |||
// | |||
// Nonce-dependent and per-encryption variables | |||
// | |||
// Zero out the last 6 bits of the nonce into truncatedNonce to see if Ktop | |||
// is already computed. | |||
truncatedNonce := make([]byte, len(nonce)) | |||
copy(truncatedNonce, nonce) | |||
truncatedNonce[len(truncatedNonce)-1] &= 192 | |||
Ktop := make([]byte, blockSize) | |||
if bytes.Equal(truncatedNonce, o.reusableKtop.noncePrefix) { | |||
Ktop = o.reusableKtop.Ktop | |||
} else { | |||
// Nonce = num2str(TAGLEN mod 128, 7) || zeros(120 - bitlen(N)) || 1 || N | |||
paddedNonce := append(make([]byte, blockSize-1-len(nonce)), 1) | |||
paddedNonce = append(paddedNonce, truncatedNonce...) | |||
paddedNonce[0] |= byte(((8 * o.tagSize) % (8 * blockSize)) << 1) | |||
// Last 6 bits of paddedNonce are already zero. Encrypt into Ktop | |||
paddedNonce[blockSize-1] &= 192 | |||
Ktop = paddedNonce | |||
o.block.Encrypt(Ktop, Ktop) | |||
o.reusableKtop.noncePrefix = truncatedNonce | |||
o.reusableKtop.Ktop = Ktop | |||
} | |||
// Stretch = Ktop || ((lower half of Ktop) XOR (lower half of Ktop << 8)) | |||
xorHalves := make([]byte, blockSize/2) | |||
byteutil.XorBytes(xorHalves, Ktop[:blockSize/2], Ktop[1:1+blockSize/2]) | |||
stretch := append(Ktop, xorHalves...) | |||
bottom := int(nonce[len(nonce)-1] & 63) | |||
offset := make([]byte, len(stretch)) | |||
byteutil.ShiftNBytesLeft(offset, stretch, bottom) | |||
offset = offset[:blockSize] | |||
// | |||
// Process any whole blocks | |||
// | |||
// Note: For encryption Y is ciphertext || tag, for decryption Y is | |||
// plaintext || tag. | |||
checksum := make([]byte, blockSize) | |||
m := len(X) / blockSize | |||
for i := 0; i < m; i++ { | |||
index := bits.TrailingZeros(uint(i + 1)) | |||
if len(o.mask.L)-1 < index { | |||
o.mask.extendTable(index) | |||
} | |||
byteutil.XorBytesMut(offset, o.mask.L[bits.TrailingZeros(uint(i+1))]) | |||
blockX := X[i*blockSize : (i+1)*blockSize] | |||
blockY := Y[i*blockSize : (i+1)*blockSize] | |||
byteutil.XorBytes(blockY, blockX, offset) | |||
switch instruction { | |||
case enc: | |||
o.block.Encrypt(blockY, blockY) | |||
byteutil.XorBytesMut(blockY, offset) | |||
byteutil.XorBytesMut(checksum, blockX) | |||
case dec: | |||
o.block.Decrypt(blockY, blockY) | |||
byteutil.XorBytesMut(blockY, offset) | |||
byteutil.XorBytesMut(checksum, blockY) | |||
} | |||
} | |||
// | |||
// Process any final partial block and compute raw tag | |||
// | |||
tag := make([]byte, blockSize) | |||
if len(X)%blockSize != 0 { | |||
byteutil.XorBytesMut(offset, o.mask.lAst) | |||
pad := make([]byte, blockSize) | |||
o.block.Encrypt(pad, offset) | |||
chunkX := X[blockSize*m:] | |||
chunkY := Y[blockSize*m : len(X)] | |||
byteutil.XorBytes(chunkY, chunkX, pad[:len(chunkX)]) | |||
// P_* || bit(1) || zeroes(127) - len(P_*) | |||
switch instruction { | |||
case enc: | |||
paddedY := append(chunkX, byte(128)) | |||
paddedY = append(paddedY, make([]byte, blockSize-len(chunkX)-1)...) | |||
byteutil.XorBytesMut(checksum, paddedY) | |||
case dec: | |||
paddedX := append(chunkY, byte(128)) | |||
paddedX = append(paddedX, make([]byte, blockSize-len(chunkY)-1)...) | |||
byteutil.XorBytesMut(checksum, paddedX) | |||
} | |||
byteutil.XorBytes(tag, checksum, offset) | |||
byteutil.XorBytesMut(tag, o.mask.lDol) | |||
o.block.Encrypt(tag, tag) | |||
byteutil.XorBytesMut(tag, o.hash(adata)) | |||
copy(Y[blockSize*m+len(chunkY):], tag[:o.tagSize]) | |||
} else { | |||
byteutil.XorBytes(tag, checksum, offset) | |||
byteutil.XorBytesMut(tag, o.mask.lDol) | |||
o.block.Encrypt(tag, tag) | |||
byteutil.XorBytesMut(tag, o.hash(adata)) | |||
copy(Y[blockSize*m:], tag[:o.tagSize]) | |||
} | |||
return Y | |||
} | |||
// This hash function is used to compute the tag. Per design, on empty input it | |||
// returns a slice of zeros, of the same length as the underlying block cipher | |||
// block size. | |||
func (o *ocb) hash(adata []byte) []byte { | |||
// | |||
// Consider A as a sequence of 128-bit blocks | |||
// | |||
A := make([]byte, len(adata)) | |||
copy(A, adata) | |||
blockSize := o.block.BlockSize() | |||
// | |||
// Process any whole blocks | |||
// | |||
sum := make([]byte, blockSize) | |||
offset := make([]byte, blockSize) | |||
m := len(A) / blockSize | |||
for i := 0; i < m; i++ { | |||
chunk := A[blockSize*i : blockSize*(i+1)] | |||
index := bits.TrailingZeros(uint(i + 1)) | |||
// If the mask table is too short | |||
if len(o.mask.L)-1 < index { | |||
o.mask.extendTable(index) | |||
} | |||
byteutil.XorBytesMut(offset, o.mask.L[index]) | |||
byteutil.XorBytesMut(chunk, offset) | |||
o.block.Encrypt(chunk, chunk) | |||
byteutil.XorBytesMut(sum, chunk) | |||
} | |||
// | |||
// Process any final partial block; compute final hash value | |||
// | |||
if len(A)%blockSize != 0 { | |||
byteutil.XorBytesMut(offset, o.mask.lAst) | |||
// Pad block with 1 || 0 ^ 127 - bitlength(a) | |||
ending := make([]byte, blockSize-len(A)%blockSize) | |||
ending[0] = 0x80 | |||
encrypted := append(A[blockSize*m:], ending...) | |||
byteutil.XorBytesMut(encrypted, offset) | |||
o.block.Encrypt(encrypted, encrypted) | |||
byteutil.XorBytesMut(sum, encrypted) | |||
} | |||
return sum | |||
} | |||
func initializeMaskTable(block cipher.Block) mask { | |||
// | |||
// Key-dependent variables | |||
// | |||
lAst := make([]byte, block.BlockSize()) | |||
block.Encrypt(lAst, lAst) | |||
lDol := byteutil.GfnDouble(lAst) | |||
L := make([][]byte, 1) | |||
L[0] = byteutil.GfnDouble(lDol) | |||
return mask{ | |||
lAst: lAst, | |||
lDol: lDol, | |||
L: L, | |||
} | |||
} | |||
// Extends the L array of mask m up to L[limit], with L[i] = GfnDouble(L[i-1]) | |||
func (m *mask) extendTable(limit int) { | |||
for i := len(m.L); i <= limit; i++ { | |||
m.L = append(m.L, byteutil.GfnDouble(m.L[i-1])) | |||
} | |||
} | |||
func ocbError(err string) error { | |||
return errors.New("crypto/ocb: " + err) | |||
} |
@@ -0,0 +1,136 @@ | |||
// In the test vectors provided by RFC 7253, the "bottom" | |||
// internal variable, which defines "offset" for the first time, does not | |||
// exceed 15. However, it can attain values up to 63. | |||
// These vectors include key length in {128, 192, 256}, tag size 128, and | |||
// random nonce, header, and plaintext lengths. | |||
// This file was automatically generated. | |||
package ocb | |||
var randomVectors = []struct { | |||
key, nonce, header, plaintext, ciphertext string | |||
}{ | |||
{"9438C5D599308EAF13F800D2D31EA7F0", | |||
"C38EE4801BEBFFA1CD8635BE", | |||
"0E507B7DADD8A98CDFE272D3CB6B3E8332B56AE583FB049C0874D4200BED16BD1A044182434E9DA0E841F182DFD5B3016B34641CED0784F1745F63AB3D0DA22D3351C9EF9A658B8081E24498EBF61FCE40DA6D8E184536", | |||
"962D227786FB8913A8BAD5DC3250", | |||
"EEDEF5FFA5986D1E3BF86DDD33EF9ADC79DCA06E215FA772CCBA814F63AD"}, | |||
{"BA7DE631C7D6712167C6724F5B9A2B1D", | |||
"35263EBDA05765DC0E71F1F5", | |||
"0103257B4224507C0242FEFE821EA7FA42E0A82863E5F8B68F7D881B4B44FA428A2B6B21D2F591260802D8AB6D83", | |||
"9D6D1FC93AE8A64E7889B7B2E3521EFA9B920A8DDB692E6F833DDC4A38AFA535E5E2A3ED82CB7E26404AB86C54D01C4668F28398C2DF33D5D561CBA1C8DCFA7A912F5048E545B59483C0E3221F54B14DAA2E4EB657B3BEF9554F34CAD69B2724AE962D3D8A", | |||
"E93852D1985C5E775655E937FA79CE5BF28A585F2AF53A5018853B9634BE3C84499AC0081918FDCE0624494D60E25F76ACD6853AC7576E3C350F332249BFCABD4E73CEABC36BE4EDDA40914E598AE74174A0D7442149B26990899491BDDFE8FC54D6C18E83AE9E9A6FFBF5D376565633862EEAD88D"}, | |||
{"2E74B25289F6FD3E578C24866E9C72A5", | |||
"FD912F15025AF8414642BA1D1D", | |||
"FB5FB8C26F365EEDAB5FE260C6E3CCD27806729C8335F146063A7F9EA93290E56CF84576EB446350D22AD730547C267B1F0BBB97EB34E1E2C41A", | |||
"6C092EBF78F76EE8C1C6E592277D9545BA16EDB67BC7D8480B9827702DC2F8A129E2B08A2CE710CA7E1DA45CE162BB6CD4B512E632116E2211D3C90871EFB06B8D4B902681C7FB", | |||
"6AC0A77F26531BF4F354A1737F99E49BE32ECD909A7A71AD69352906F54B08A9CE9B8CA5D724CBFFC5673437F23F630697F3B84117A1431D6FA8CC13A974FB4AD360300522E09511B99E71065D5AC4BBCB1D791E864EF4"}, | |||
{"E7EC507C802528F790AFF5303A017B17", | |||
"4B97A7A568940A9E3CE7A99E93031E", | |||
"28349BDC5A09390C480F9B8AA3EDEA3DDB8B9D64BCA322C570B8225DF0E31190DAB25A4014BA39519E02ABFB12B89AA28BBFD29E486E7FB28734258C817B63CED9912DBAFEBB93E2798AB2890DE3B0ACFCFF906AB15563EF7823CE83D27CDB251195E22BD1337BCBDE65E7C2C427321C463C2777BFE5AEAA", | |||
"9455B3EA706B74", | |||
"7F33BA3EA848D48A96B9530E26888F43EBD4463C9399B6"}, | |||
{"6C928AA3224736F28EE7378DE0090191", | |||
"8936138E2E4C6A13280017A1622D", | |||
"6202717F2631565BDCDC57C6584543E72A7C8BD444D0D108ED35069819633C", | |||
"DA0691439E5F035F3E455269D14FE5C201C8C9B0A3FE2D3F86BCC59387C868FE65733D388360B31E3CE28B4BF6A8BE636706B536D5720DB66B47CF1C7A5AFD6F61E0EF90F1726D6B0E169F9A768B2B7AE4EE00A17F630AC905FCAAA1B707FFF25B3A1AAE83B504837C64A5639B2A34002B300EC035C9B43654DA55", | |||
"B8804D182AB0F0EEB464FA7BD1329AD6154F982013F3765FEDFE09E26DAC078C9C1439BFC1159D6C02A25E3FF83EF852570117B315852AD5EE20E0FA3AA0A626B0E43BC0CEA38B44579DD36803455FB46989B90E6D229F513FD727AF8372517E9488384C515D6067704119C931299A0982EDDFB9C2E86A90C450C077EB222511EC9CCABC9FCFDB19F70088"}, | |||
{"ECEA315CA4B3F425B0C9957A17805EA4", | |||
"664CDAE18403F4F9BA13015A44FC", | |||
"642AFB090D6C6DB46783F08B01A3EF2A8FEB5736B531EAC226E7888FCC8505F396818F83105065FACB3267485B9E5E4A0261F621041C08FCCB2A809A49AB5252A91D0971BCC620B9D614BD77E57A0EED2FA5", | |||
"6852C31F8083E20E364CEA21BB7854D67CEE812FE1C9ED2425C0932A90D3780728D1BB", | |||
"2ECEF962A9695A463ADABB275BDA9FF8B2BA57AEC2F52EFFB700CD9271A74D2A011C24AEA946051BD6291776429B7E681BA33E"}, | |||
{"4EE616C4A58AAA380878F71A373461F6", | |||
"91B8C9C176D9C385E9C47E52", | |||
"CDA440B7F9762C572A718AC754EDEECC119E5EE0CCB9FEA4FFB22EEE75087C032EBF3DA9CDD8A28CC010B99ED45143B41A4BA50EA2A005473F89639237838867A57F23B0F0ED3BF22490E4501DAC9C658A9B9F", | |||
"D6E645FA9AE410D15B8123FD757FA356A8DBE9258DDB5BE88832E615910993F497EC", | |||
"B70ED7BF959FB2AAED4F36174A2A99BFB16992C8CDF369C782C4DB9C73DE78C5DB8E0615F647243B97ACDB24503BC9CADC48"}, | |||
{"DCD475773136C830D5E3D0C5FE05B7FF", | |||
"BB8E1FBB483BE7616A922C4A", | |||
"36FEF2E1CB29E76A6EA663FC3AF66ECD7404F466382F7B040AABED62293302B56E8783EF7EBC21B4A16C3E78A7483A0A403F253A2CDC5BBF79DC3DAE6C73F39A961D8FBBE8D41B", | |||
"441E886EA38322B2437ECA7DEB5282518865A66780A454E510878E61BFEC3106A3CD93D2A02052E6F9E1832F9791053E3B76BF4C07EFDD6D4106E3027FABB752E60C1AA425416A87D53938163817A1051EBA1D1DEEB4B9B25C7E97368B52E5911A31810B0EC5AF547559B6142D9F4C4A6EF24A4CF75271BF9D48F62B", | |||
"1BE4DD2F4E25A6512C2CC71D24BBB07368589A94C2714962CD0ACE5605688F06342587521E75F0ACAFFD86212FB5C34327D238DB36CF2B787794B9A4412E7CD1410EA5DDD2450C265F29CF96013CD213FD2880657694D718558964BC189B4A84AFCF47EB012935483052399DBA5B088B0A0477F20DFE0E85DCB735E21F22A439FB837DD365A93116D063E607"}, | |||
{"3FBA2B3D30177FFE15C1C59ED2148BB2C091F5615FBA7C07", | |||
"FACF804A4BEBF998505FF9DE", | |||
"8213B9263B2971A5BDA18DBD02208EE1", | |||
"15B323926993B326EA19F892D704439FC478828322AF72118748284A1FD8A6D814E641F70512FD706980337379F31DC63355974738D7FEA87AD2858C0C2EBBFBE74371C21450072373C7B651B334D7C4D43260B9D7CCD3AF9EDB", | |||
"6D35DC1469B26E6AAB26272A41B46916397C24C485B61162E640A062D9275BC33DDCFD3D9E1A53B6C8F51AC89B66A41D59B3574197A40D9B6DCF8A4E2A001409C8112F16B9C389E0096179DB914E05D6D11ED0005AD17E1CE105A2F0BAB8F6B1540DEB968B7A5428FF44"}, | |||
{"53B52B8D4D748BCDF1DDE68857832FA46227FA6E2F32EFA1", | |||
"0B0EF53D4606B28D1398355F", | |||
"F23882436349094AF98BCACA8218E81581A043B19009E28EFBF2DE37883E04864148CC01D240552CA8844EC1456F42034653067DA67E80F87105FD06E14FF771246C9612867BE4D215F6D761", | |||
"F15030679BD4088D42CAC9BF2E9606EAD4798782FA3ED8C57EBE7F84A53236F51B25967C6489D0CD20C9EEA752F9BC", | |||
"67B96E2D67C3729C96DAEAEDF821D61C17E648643A2134C5621FEC621186915AD80864BFD1EB5B238BF526A679385E012A457F583AFA78134242E9D9C1B4E4"}, | |||
{"0272DD80F23399F49BFC320381A5CD8225867245A49A7D41", | |||
"5C83F4896D0738E1366B1836", | |||
"69B0337289B19F73A12BAEEA857CCAF396C11113715D9500CCCF48BA08CFF12BC8B4BADB3084E63B85719DB5058FA7C2C11DEB096D7943CFA7CAF5", | |||
"C01AD10FC8B562CD17C7BC2FAB3E26CBDFF8D7F4DEA816794BBCC12336991712972F52816AABAB244EB43B0137E2BAC1DD413CE79531E78BEF782E6B439612BB3AEF154DE3502784F287958EBC159419F9EBA27916A28D6307324129F506B1DE80C1755A929F87", | |||
"FEFE52DD7159C8DD6E8EC2D3D3C0F37AB6CB471A75A071D17EC4ACDD8F3AA4D7D4F7BB559F3C09099E3D9003E5E8AA1F556B79CECDE66F85B08FA5955E6976BF2695EA076388A62D2AD5BAB7CBF1A7F3F4C8D5CDF37CDE99BD3E30B685D9E5EEE48C7C89118EF4878EB89747F28271FA2CC45F8E9E7601"}, | |||
{"3EEAED04A455D6E5E5AB53CFD5AFD2F2BC625C7BF4BE49A5", | |||
"36B88F63ADBB5668588181D774", | |||
"D367E3CB3703E762D23C6533188EF7028EFF9D935A3977150361997EC9DEAF1E4794BDE26AA8B53C124980B1362EC86FCDDFC7A90073171C1BAEE351A53234B86C66E8AB92FAE99EC6967A6D3428892D80", | |||
"573454C719A9A55E04437BF7CBAAF27563CCCD92ADD5E515CD63305DFF0687E5EEF790C5DCA5C0033E9AB129505E2775438D92B38F08F3B0356BA142C6F694", | |||
"E9F79A5B432D9E682C9AAA5661CFC2E49A0FCB81A431E54B42EB73DD3BED3F377FEC556ABA81624BA64A5D739AD41467460088F8D4F442180A9382CA635745473794C382FCDDC49BA4EB6D8A44AE3C"}, | |||
{"B695C691538F8CBD60F039D0E28894E3693CC7C36D92D79D", | |||
"BC099AEB637361BAC536B57618", | |||
"BFFF1A65AE38D1DC142C71637319F5F6508E2CB33C9DCB94202B359ED5A5ED8042E7F4F09231D32A7242976677E6F4C549BF65FADC99E5AF43F7A46FD95E16C2", | |||
"081DF3FD85B415D803F0BE5AC58CFF0023FDDED99788296C3731D8", | |||
"E50C64E3614D94FE69C47092E46ACC9957C6FEA2CCBF96BC62FBABE7424753C75F9C147C42AE26FE171531"}, | |||
{"C9ACBD2718F0689A1BE9802A551B6B8D9CF5614DAF5E65ED", | |||
"B1B0AAF373B8B026EB80422051D8", | |||
"6648C0E61AC733C76119D23FB24548D637751387AA2EAE9D80E912B7BD486CAAD9EAF4D7A5FE2B54AAD481E8EC94BB4D558000896E2010462B70C9FED1E7273080D1", | |||
"189F591F6CB6D59AFEDD14C341741A8F1037DC0DF00FC57CE65C30F49E860255CEA5DC6019380CC0FE8880BC1A9E685F41C239C38F36E3F2A1388865C5C311059C0A", | |||
"922A5E949B61D03BE34AB5F4E58607D4504EA14017BB363DAE3C873059EA7A1C77A746FB78981671D26C2CF6D9F24952D510044CE02A10177E9DB42D0145211DFE6E84369C5E3BC2669EAB4147B2822895F9"}, | |||
{"7A832BD2CF5BF4919F353CE2A8C86A5E406DA2D52BE16A72", | |||
"2F2F17CECF7E5A756D10785A3CB9DB", | |||
"61DA05E3788CC2D8405DBA70C7A28E5AF699863C9F72E6C6770126929F5D6FA267F005EBCF49495CB46400958A3AE80D1289D1C671", | |||
"44E91121195A41AF14E8CFDBD39A4B517BE0DF1A72977ED8A3EEF8EEDA1166B2EB6DB2C4AE2E74FA0F0C74537F659BFBD141E5DDEC67E64EDA85AABD3F52C85A785B9FB3CECD70E7DF", | |||
"BEDF596EA21288D2B84901E188F6EE1468B14D5161D3802DBFE00D60203A24E2AB62714BF272A45551489838C3A7FEAADC177B591836E73684867CCF4E12901DCF2064058726BBA554E84ADC5136F507E961188D4AF06943D3"}, | |||
{"1508E8AE9079AA15F1CEC4F776B4D11BCCB061B58AA56C18", | |||
"BCA625674F41D1E3AB47672DC0C3", | |||
"8B12CF84F16360F0EAD2A41BC021530FFCEC7F3579CAE658E10E2D3D81870F65AFCED0C77C6C4C6E6BA424FF23088C796BA6195ABA35094BF1829E089662E7A95FC90750AE16D0C8AFA55DAC789D7735B970B58D4BE7CEC7341DA82A0179A01929C27A59C5063215B859EA43", | |||
"E525422519ECE070E82C", | |||
"B47BC07C3ED1C0A43BA52C43CBACBCDBB29CAF1001E09FDF7107"}, | |||
{"7550C2761644E911FE9ADD119BAC07376BEA442845FEAD876D7E7AC1B713E464", | |||
"36D2EC25ADD33CDEDF495205BBC923", | |||
"7FCFE81A3790DE97FFC3DE160C470847EA7E841177C2F759571CBD837EA004A6CA8C6F4AEBFF2E9FD552D73EB8A30705D58D70C0B67AEEA280CBBF0A477358ACEF1E7508F2735CD9A0E4F9AC92B8C008F575D3B6278F1C18BD01227E3502E5255F3AB1893632AD00C717C588EF652A51A43209E7EE90", | |||
"2B1A62F8FDFAA3C16470A21AD307C9A7D03ADE8EF72C69B06F8D738CDE578D7AEFD0D40BD9C022FB9F580DF5394C998ACCCEFC5471A3996FB8F1045A81FDC6F32D13502EA65A211390C8D882B8E0BEFD8DD8CBEF51D1597B124E9F7F", | |||
"C873E02A22DB89EB0787DB6A60B99F7E4A0A085D5C4232A81ADCE2D60AA36F92DDC33F93DD8640AC0E08416B187FB382B3EC3EE85A64B0E6EE41C1366A5AD2A282F66605E87031CCBA2FA7B2DA201D975994AADE3DD1EE122AE09604AD489B84BF0C1AB7129EE16C6934850E"}, | |||
{"A51300285E554FDBDE7F771A9A9A80955639DD87129FAEF74987C91FB9687C71", | |||
"81691D5D20EC818FCFF24B33DECC", | |||
"C948093218AA9EB2A8E44A87EEA73FC8B6B75A196819A14BD83709EA323E8DF8B491045220E1D88729A38DBCFFB60D3056DAD4564498FD6574F74512945DEB34B69329ACED9FFC05D5D59DFCD5B973E2ACAFE6AD1EF8BBBC49351A2DD12508ED89ED", | |||
"EB861165DAF7625F827C6B574ED703F03215", | |||
"C6CD1CE76D2B3679C1B5AA1CFD67CCB55444B6BFD3E22C81CBC9BB738796B83E54E3"}, | |||
{"8CE0156D26FAEB7E0B9B800BBB2E9D4075B5EAC5C62358B0E7F6FCE610223282", | |||
"D2A7B94DD12CDACA909D3AD7", | |||
"E021A78F374FC271389AB9A3E97077D755", | |||
"7C26000B58929F5095E1CEE154F76C2A299248E299F9B5ADE6C403AA1FD4A67FD4E0232F214CE7B919EE7A1027D2B76C57475715CD078461", | |||
"C556FB38DF069B56F337B5FF5775CE6EAA16824DFA754F20B78819028EA635C3BB7AA731DE8776B2DCB67DCA2D33EEDF3C7E52EA450013722A41755A0752433ED17BDD5991AAE77A"}, | |||
{"1E8000A2CE00A561C9920A30BF0D7B983FEF8A1014C8F04C35CA6970E6BA02BD", | |||
"65ED3D63F79F90BBFD19775E", | |||
"336A8C0B7243582A46B221AA677647FCAE91", | |||
"134A8B34824A290E7B", | |||
"914FBEF80D0E6E17F8BDBB6097EBF5FBB0554952DC2B9E5151"}, | |||
{"53D5607BBE690B6E8D8F6D97F3DF2BA853B682597A214B8AA0EA6E598650AF15", | |||
"C391A856B9FE234E14BA1AC7BB40FF", | |||
"479682BC21349C4BE1641D5E78FE2C79EC1B9CF5470936DCAD9967A4DCD7C4EFADA593BC9EDE71E6A08829B8580901B61E274227E9D918502DE3", | |||
"EAD154DC09C5E26C5D26FF33ED148B27120C7F2C23225CC0D0631B03E1F6C6D96FEB88C1A4052ACB4CE746B884B6502931F407021126C6AAB8C514C077A5A38438AE88EE", | |||
"938821286EBB671D999B87C032E1D6055392EB564E57970D55E545FC5E8BAB90E6E3E3C0913F6320995FC636D72CD9919657CC38BD51552F4A502D8D1FE56DB33EBAC5092630E69EBB986F0E15CEE9FC8C052501"}, | |||
{"294362FCC984F440CEA3E9F7D2C06AF20C53AAC1B3738CA2186C914A6E193ABB", | |||
"B15B61C8BB39261A8F55AB178EC3", | |||
"D0729B6B75BB", | |||
"2BD089ADCE9F334BAE3B065996C7D616DD0C27DF4218DCEEA0FBCA0F968837CE26B0876083327E25681FDDD620A32EC0DA12F73FAE826CC94BFF2B90A54D2651", | |||
"AC94B25E4E21DE2437B806966CCD5D9385EF0CD4A51AB9FA6DE675C7B8952D67802E9FEC1FDE9F5D1EAB06057498BC0EEA454804FC9D2068982A3E24182D9AC2E7AB9994DDC899A604264583F63D066B"}, | |||
{"959DBFEB039B1A5B8CE6A44649B602AAA5F98A906DB96143D202CD2024F749D9", | |||
"01D7BDB1133E9C347486C1EFA6", | |||
"F3843955BD741F379DD750585EDC55E2CDA05CCBA8C1F4622AC2FE35214BC3A019B8BD12C4CC42D9213D1E1556941E8D8450830287FFB3B763A13722DD4140ED9846FB5FFF745D7B0B967D810A068222E10B259AF1D392035B0D83DC1498A6830B11B2418A840212599171E0258A1C203B05362978", | |||
"A21811232C950FA8B12237C2EBD6A7CD2C3A155905E9E0C7C120", | |||
"63C1CE397B22F1A03F1FA549B43178BC405B152D3C95E977426D519B3DFCA28498823240592B6EEE7A14"}, | |||
{"096AE499F5294173F34FF2B375F0E5D5AB79D0D03B33B1A74D7D576826345DF4", | |||
"0C52B3D11D636E5910A4DD76D32C", | |||
"229E9ECA3053789E937447BC719467075B6138A142DA528DA8F0CF8DDF022FD9AF8E74779BA3AC306609", | |||
"8B7A00038783E8BAF6EDEAE0C4EAB48FC8FD501A588C7E4A4DB71E3604F2155A97687D3D2FFF8569261375A513CF4398CE0F87CA1658A1050F6EF6C4EA3E25", | |||
"C20B6CF8D3C8241825FD90B2EDAC7593600646E579A8D8DAAE9E2E40C3835FE801B2BE4379131452BC5182C90307B176DFBE2049544222FE7783147B690774F6D9D7CEF52A91E61E298E9AA15464AC"}, | |||
} |
@@ -0,0 +1,78 @@ | |||
package ocb | |||
import ( | |||
"encoding/hex" | |||
) | |||
// Test vectors from https://tools.ietf.org/html/rfc7253. Note that key is | |||
// shared across tests. | |||
var testKey, _ = hex.DecodeString("000102030405060708090A0B0C0D0E0F") | |||
var rfc7253testVectors = []struct { | |||
nonce, header, plaintext, ciphertext string | |||
}{ | |||
{"BBAA99887766554433221100", | |||
"", | |||
"", | |||
"785407BFFFC8AD9EDCC5520AC9111EE6"}, | |||
{"BBAA99887766554433221101", | |||
"0001020304050607", | |||
"0001020304050607", | |||
"6820B3657B6F615A5725BDA0D3B4EB3A257C9AF1F8F03009"}, | |||
{"BBAA99887766554433221102", | |||
"0001020304050607", | |||
"", | |||
"81017F8203F081277152FADE694A0A00"}, | |||
{"BBAA99887766554433221103", | |||
"", | |||
"0001020304050607", | |||
"45DD69F8F5AAE72414054CD1F35D82760B2CD00D2F99BFA9"}, | |||
{"BBAA99887766554433221104", | |||
"000102030405060708090A0B0C0D0E0F", | |||
"000102030405060708090A0B0C0D0E0F", | |||
"571D535B60B277188BE5147170A9A22C3AD7A4FF3835B8C5701C1CCEC8FC3358"}, | |||
{"BBAA99887766554433221105", | |||
"000102030405060708090A0B0C0D0E0F", | |||
"", | |||
"8CF761B6902EF764462AD86498CA6B97"}, | |||
{"BBAA99887766554433221106", | |||
"", | |||
"000102030405060708090A0B0C0D0E0F", | |||
"5CE88EC2E0692706A915C00AEB8B2396F40E1C743F52436BDF06D8FA1ECA343D"}, | |||
{"BBAA99887766554433221107", | |||
"000102030405060708090A0B0C0D0E0F1011121314151617", | |||
"000102030405060708090A0B0C0D0E0F1011121314151617", | |||
"1CA2207308C87C010756104D8840CE1952F09673A448A122C92C62241051F57356D7F3C90BB0E07F"}, | |||
{"BBAA99887766554433221108", | |||
"000102030405060708090A0B0C0D0E0F1011121314151617", | |||
"", | |||
"6DC225A071FC1B9F7C69F93B0F1E10DE"}, | |||
{"BBAA99887766554433221109", | |||
"", | |||
"000102030405060708090A0B0C0D0E0F1011121314151617", | |||
"221BD0DE7FA6FE993ECCD769460A0AF2D6CDED0C395B1C3CE725F32494B9F914D85C0B1EB38357FF"}, | |||
{"BBAA9988776655443322110A", | |||
"000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F", | |||
"000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F", | |||
"BD6F6C496201C69296C11EFD138A467ABD3C707924B964DEAFFC40319AF5A48540FBBA186C5553C68AD9F592A79A4240"}, | |||
{"BBAA9988776655443322110B", | |||
"000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F", | |||
"", | |||
"FE80690BEE8A485D11F32965BC9D2A32"}, | |||
{"BBAA9988776655443322110C", | |||
"", | |||
"000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F", | |||
"2942BFC773BDA23CABC6ACFD9BFD5835BD300F0973792EF46040C53F1432BCDFB5E1DDE3BC18A5F840B52E653444D5DF"}, | |||
{"BBAA9988776655443322110D", | |||
"000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627", | |||
"000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627", | |||
"D5CA91748410C1751FF8A2F618255B68A0A12E093FF454606E59F9C1D0DDC54B65E8628E568BAD7AED07BA06A4A69483A7035490C5769E60"}, | |||
{"BBAA9988776655443322110E", | |||
"000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627", | |||
"", | |||
"C5CD9D1850C141E358649994EE701B68"}, | |||
{"BBAA9988776655443322110F", | |||
"", | |||
"000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627", | |||
"4412923493C57D5DE0D700F753CCE0D1D2D95060122E9F15A5DDBFC5787E50B5CC55EE507BCB084E479AD363AC366B95A98CA5F3000B1479"}, | |||
} |
@@ -0,0 +1,25 @@ | |||
package ocb | |||
// Second set of test vectors from https://tools.ietf.org/html/rfc7253 | |||
var rfc7253TestVectorTaglen96 = struct { | |||
key, nonce, header, plaintext, ciphertext string | |||
}{"0F0E0D0C0B0A09080706050403020100", | |||
"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"}, | |||
} |
@@ -0,0 +1,153 @@ | |||
// Copyright 2014 Matthew Endsley | |||
// All rights reserved | |||
// | |||
// Redistribution and use in source and binary forms, with or without | |||
// modification, are permitted providing that the following conditions | |||
// are met: | |||
// 1. Redistributions of source code must retain the above copyright | |||
// notice, this list of conditions and the following disclaimer. | |||
// 2. Redistributions in binary form must reproduce the above copyright | |||
// notice, this list of conditions and the following disclaimer in the | |||
// documentation and/or other materials provided with the distribution. | |||
// | |||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |||
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | |||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |||
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |||
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | |||
// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |||
// POSSIBILITY OF SUCH DAMAGE. | |||
// Package keywrap is an implementation of the RFC 3394 AES key wrapping | |||
// algorithm. This is used in OpenPGP with elliptic curve keys. | |||
package keywrap | |||
import ( | |||
"crypto/aes" | |||
"encoding/binary" | |||
"errors" | |||
) | |||
var ( | |||
// ErrWrapPlaintext is returned if the plaintext is not a multiple | |||
// of 64 bits. | |||
ErrWrapPlaintext = errors.New("keywrap: plainText must be a multiple of 64 bits") | |||
// ErrUnwrapCiphertext is returned if the ciphertext is not a | |||
// multiple of 64 bits. | |||
ErrUnwrapCiphertext = errors.New("keywrap: cipherText must by a multiple of 64 bits") | |||
// ErrUnwrapFailed is returned if unwrapping a key fails. | |||
ErrUnwrapFailed = errors.New("keywrap: failed to unwrap key") | |||
// NB: the AES NewCipher call only fails if the key is an invalid length. | |||
// ErrInvalidKey is returned when the AES key is invalid. | |||
ErrInvalidKey = errors.New("keywrap: invalid AES key") | |||
) | |||
// Wrap a key using the RFC 3394 AES Key Wrap Algorithm. | |||
func Wrap(key, plainText []byte) ([]byte, error) { | |||
if len(plainText)%8 != 0 { | |||
return nil, ErrWrapPlaintext | |||
} | |||
c, err := aes.NewCipher(key) | |||
if err != nil { | |||
return nil, ErrInvalidKey | |||
} | |||
nblocks := len(plainText) / 8 | |||
// 1) Initialize variables. | |||
var block [aes.BlockSize]byte | |||
// - Set A = IV, an initial value (see 2.2.3) | |||
for ii := 0; ii < 8; ii++ { | |||
block[ii] = 0xA6 | |||
} | |||
// - For i = 1 to n | |||
// - Set R[i] = P[i] | |||
intermediate := make([]byte, len(plainText)) | |||
copy(intermediate, plainText) | |||
// 2) Calculate intermediate values. | |||
for ii := 0; ii < 6; ii++ { | |||
for jj := 0; jj < nblocks; jj++ { | |||
// - B = AES(K, A | R[i]) | |||
copy(block[8:], intermediate[jj*8:jj*8+8]) | |||
c.Encrypt(block[:], block[:]) | |||
// - A = MSB(64, B) ^ t where t = (n*j)+1 | |||
t := uint64(ii*nblocks + jj + 1) | |||
val := binary.BigEndian.Uint64(block[:8]) ^ t | |||
binary.BigEndian.PutUint64(block[:8], val) | |||
// - R[i] = LSB(64, B) | |||
copy(intermediate[jj*8:jj*8+8], block[8:]) | |||
} | |||
} | |||
// 3) Output results. | |||
// - Set C[0] = A | |||
// - For i = 1 to n | |||
// - C[i] = R[i] | |||
return append(block[:8], intermediate...), nil | |||
} | |||
// Unwrap a key using the RFC 3394 AES Key Wrap Algorithm. | |||
func Unwrap(key, cipherText []byte) ([]byte, error) { | |||
if len(cipherText)%8 != 0 { | |||
return nil, ErrUnwrapCiphertext | |||
} | |||
c, err := aes.NewCipher(key) | |||
if err != nil { | |||
return nil, ErrInvalidKey | |||
} | |||
nblocks := len(cipherText)/8 - 1 | |||
// 1) Initialize variables. | |||
var block [aes.BlockSize]byte | |||
// - Set A = C[0] | |||
copy(block[:8], cipherText[:8]) | |||
// - For i = 1 to n | |||
// - Set R[i] = C[i] | |||
intermediate := make([]byte, len(cipherText)-8) | |||
copy(intermediate, cipherText[8:]) | |||
// 2) Compute intermediate values. | |||
for jj := 5; jj >= 0; jj-- { | |||
for ii := nblocks - 1; ii >= 0; ii-- { | |||
// - B = AES-1(K, (A ^ t) | R[i]) where t = n*j+1 | |||
// - A = MSB(64, B) | |||
t := uint64(jj*nblocks + ii + 1) | |||
val := binary.BigEndian.Uint64(block[:8]) ^ t | |||
binary.BigEndian.PutUint64(block[:8], val) | |||
copy(block[8:], intermediate[ii*8:ii*8+8]) | |||
c.Decrypt(block[:], block[:]) | |||
// - R[i] = LSB(B, 64) | |||
copy(intermediate[ii*8:ii*8+8], block[8:]) | |||
} | |||
} | |||
// 3) Output results. | |||
// - If A is an appropriate initial value (see 2.2.3), | |||
for ii := 0; ii < 8; ii++ { | |||
if block[ii] != 0xA6 { | |||
return nil, ErrUnwrapFailed | |||
} | |||
} | |||
// - For i = 1 to n | |||
// - P[i] = R[i] | |||
return intermediate, nil | |||
} |
@@ -0,0 +1,226 @@ | |||
// Copyright 2010 The Go Authors. All rights reserved. | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
// Package armor implements OpenPGP ASCII Armor, see RFC 4880. OpenPGP Armor is | |||
// very similar to PEM except that it has an additional CRC checksum. | |||
package armor // import "github.com/ProtonMail/go-crypto/openpgp/armor" | |||
import ( | |||
"bufio" | |||
"bytes" | |||
"encoding/base64" | |||
"github.com/ProtonMail/go-crypto/openpgp/errors" | |||
"io" | |||
) | |||
// A Block represents an OpenPGP armored structure. | |||
// | |||
// The encoded form is: | |||
// | |||
// -----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 | |||
// interface. | |||
type Block struct { | |||
Type string // The type, taken from the preamble (i.e. "PGP SIGNATURE"). | |||
Header map[string]string // Optional headers. | |||
Body io.Reader // A Reader from which the contents can be read | |||
lReader lineReader | |||
oReader openpgpReader | |||
} | |||
var ArmorCorrupt error = errors.StructuralError("armor invalid") | |||
const crc24Init = 0xb704ce | |||
const crc24Poly = 0x1864cfb | |||
const crc24Mask = 0xffffff | |||
// crc24 calculates the OpenPGP checksum as specified in RFC 4880, section 6.1 | |||
func crc24(crc uint32, d []byte) uint32 { | |||
for _, b := range d { | |||
crc ^= uint32(b) << 16 | |||
for i := 0; i < 8; i++ { | |||
crc <<= 1 | |||
if crc&0x1000000 != 0 { | |||
crc ^= crc24Poly | |||
} | |||
} | |||
} | |||
return crc | |||
} | |||
var armorStart = []byte("-----BEGIN ") | |||
var armorEnd = []byte("-----END ") | |||
var armorEndOfLine = []byte("-----") | |||
// lineReader wraps a line based reader. It watches for the end of an armor | |||
// block and records the expected CRC value. | |||
type lineReader struct { | |||
in *bufio.Reader | |||
buf []byte | |||
eof bool | |||
crc uint32 | |||
crcSet bool | |||
} | |||
func (l *lineReader) Read(p []byte) (n int, err error) { | |||
if l.eof { | |||
return 0, io.EOF | |||
} | |||
if len(l.buf) > 0 { | |||
n = copy(p, l.buf) | |||
l.buf = l.buf[n:] | |||
return | |||
} | |||
line, isPrefix, err := l.in.ReadLine() | |||
if err != nil { | |||
return | |||
} | |||
if isPrefix { | |||
return 0, ArmorCorrupt | |||
} | |||
if bytes.HasPrefix(line, armorEnd) { | |||
l.eof = true | |||
return 0, io.EOF | |||
} | |||
if len(line) == 5 && line[0] == '=' { | |||
// This is the checksum line | |||
var expectedBytes [3]byte | |||
var m int | |||
m, err = base64.StdEncoding.Decode(expectedBytes[0:], line[1:]) | |||
if m != 3 || err != nil { | |||
return | |||
} | |||
l.crc = uint32(expectedBytes[0])<<16 | | |||
uint32(expectedBytes[1])<<8 | | |||
uint32(expectedBytes[2]) | |||
line, _, err = l.in.ReadLine() | |||
if err != nil && err != io.EOF { | |||
return | |||
} | |||
if !bytes.HasPrefix(line, armorEnd) { | |||
return 0, ArmorCorrupt | |||
} | |||
l.eof = true | |||
l.crcSet = true | |||
return 0, io.EOF | |||
} | |||
if len(line) > 96 { | |||
return 0, ArmorCorrupt | |||
} | |||
n = copy(p, line) | |||
bytesToSave := len(line) - n | |||
if bytesToSave > 0 { | |||
if cap(l.buf) < bytesToSave { | |||
l.buf = make([]byte, 0, bytesToSave) | |||
} | |||
l.buf = l.buf[0:bytesToSave] | |||
copy(l.buf, line[n:]) | |||
} | |||
return | |||
} | |||
// openpgpReader passes Read calls to the underlying base64 decoder, but keeps | |||
// a running CRC of the resulting data and checks the CRC against the value | |||
// found by the lineReader at EOF. | |||
type openpgpReader struct { | |||
lReader *lineReader | |||
b64Reader io.Reader | |||
currentCRC uint32 | |||
} | |||
func (r *openpgpReader) Read(p []byte) (n int, err error) { | |||
n, err = r.b64Reader.Read(p) | |||
r.currentCRC = crc24(r.currentCRC, p[:n]) | |||
if err == io.EOF && r.lReader.crcSet && r.lReader.crc != uint32(r.currentCRC&crc24Mask) { | |||
return 0, ArmorCorrupt | |||
} | |||
return | |||
} | |||
// Decode reads a PGP armored block from the given Reader. It will ignore | |||
// leading garbage. If it doesn't find a block, it will return nil, io.EOF. The | |||
// given Reader is not usable after calling this function: an arbitrary amount | |||
// of data may have been read past the end of the block. | |||
func Decode(in io.Reader) (p *Block, err error) { | |||
r := bufio.NewReaderSize(in, 100) | |||
var line []byte | |||
ignoreNext := false | |||
TryNextBlock: | |||
p = nil | |||
// Skip leading garbage | |||
for { | |||
ignoreThis := ignoreNext | |||
line, ignoreNext, err = r.ReadLine() | |||
if err != nil { | |||
return | |||
} | |||
if ignoreNext || ignoreThis { | |||
continue | |||
} | |||
line = bytes.TrimSpace(line) | |||
if len(line) > len(armorStart)+len(armorEndOfLine) && bytes.HasPrefix(line, armorStart) { | |||
break | |||
} | |||
} | |||
p = new(Block) | |||
p.Type = string(line[len(armorStart) : len(line)-len(armorEndOfLine)]) | |||
p.Header = make(map[string]string) | |||
nextIsContinuation := false | |||
var lastKey string | |||
// Read headers | |||
for { | |||
isContinuation := nextIsContinuation | |||
line, nextIsContinuation, err = r.ReadLine() | |||
if err != nil { | |||
p = nil | |||
return | |||
} | |||
if isContinuation { | |||
p.Header[lastKey] += string(line) | |||
continue | |||
} | |||
line = bytes.TrimSpace(line) | |||
if len(line) == 0 { | |||
break | |||
} | |||
i := bytes.Index(line, []byte(": ")) | |||
if i == -1 { | |||
goto TryNextBlock | |||
} | |||
lastKey = string(line[:i]) | |||
p.Header[lastKey] = string(line[i+2:]) | |||
} | |||
p.lReader.in = r | |||
p.oReader.currentCRC = crc24Init | |||
p.oReader.lReader = &p.lReader | |||
p.oReader.b64Reader = base64.NewDecoder(base64.StdEncoding, &p.lReader) | |||
p.Body = &p.oReader | |||
return | |||
} |
@@ -0,0 +1,161 @@ | |||
// Copyright 2010 The Go Authors. All rights reserved. | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
package armor | |||
import ( | |||
"encoding/base64" | |||
"io" | |||
) | |||
var armorHeaderSep = []byte(": ") | |||
var blockEnd = []byte("\n=") | |||
var newline = []byte("\n") | |||
var armorEndOfLineOut = []byte("-----\n") | |||
// writeSlices writes its arguments to the given Writer. | |||
func writeSlices(out io.Writer, slices ...[]byte) (err error) { | |||
for _, s := range slices { | |||
_, err = out.Write(s) | |||
if err != nil { | |||
return err | |||
} | |||
} | |||
return | |||
} | |||
// lineBreaker breaks data across several lines, all of the same byte length | |||
// (except possibly the last). Lines are broken with a single '\n'. | |||
type lineBreaker struct { | |||
lineLength int | |||
line []byte | |||
used int | |||
out io.Writer | |||
haveWritten bool | |||
} | |||
func newLineBreaker(out io.Writer, lineLength int) *lineBreaker { | |||
return &lineBreaker{ | |||
lineLength: lineLength, | |||
line: make([]byte, lineLength), | |||
used: 0, | |||
out: out, | |||
} | |||
} | |||
func (l *lineBreaker) Write(b []byte) (n int, err error) { | |||
n = len(b) | |||
if n == 0 { | |||
return | |||
} | |||
if l.used == 0 && l.haveWritten { | |||
_, err = l.out.Write([]byte{'\n'}) | |||
if err != nil { | |||
return | |||
} | |||
} | |||
if l.used+len(b) < l.lineLength { | |||
l.used += copy(l.line[l.used:], b) | |||
return | |||
} | |||
l.haveWritten = true | |||
_, err = l.out.Write(l.line[0:l.used]) | |||
if err != nil { | |||
return | |||
} | |||
excess := l.lineLength - l.used | |||
l.used = 0 | |||
_, err = l.out.Write(b[0:excess]) | |||
if err != nil { | |||
return | |||
} | |||
_, err = l.Write(b[excess:]) | |||
return | |||
} | |||
func (l *lineBreaker) Close() (err error) { | |||
if l.used > 0 { | |||
_, err = l.out.Write(l.line[0:l.used]) | |||
if err != nil { | |||
return | |||
} | |||
} | |||
return | |||
} | |||
// encoding keeps track of a running CRC24 over the data which has been written | |||
// to it and outputs a OpenPGP checksum when closed, followed by an armor | |||
// trailer. | |||
// | |||
// It's built into a stack of io.Writers: | |||
// | |||
// encoding -> base64 encoder -> lineBreaker -> out | |||
type encoding struct { | |||
out io.Writer | |||
breaker *lineBreaker | |||
b64 io.WriteCloser | |||
crc uint32 | |||
blockType []byte | |||
} | |||
func (e *encoding) Write(data []byte) (n int, err error) { | |||
e.crc = crc24(e.crc, data) | |||
return e.b64.Write(data) | |||
} | |||
func (e *encoding) Close() (err error) { | |||
err = e.b64.Close() | |||
if err != nil { | |||
return | |||
} | |||
e.breaker.Close() | |||
var checksumBytes [3]byte | |||
checksumBytes[0] = byte(e.crc >> 16) | |||
checksumBytes[1] = byte(e.crc >> 8) | |||
checksumBytes[2] = byte(e.crc) | |||
var b64ChecksumBytes [4]byte | |||
base64.StdEncoding.Encode(b64ChecksumBytes[:], checksumBytes[:]) | |||
return writeSlices(e.out, blockEnd, b64ChecksumBytes[:], newline, armorEnd, e.blockType, armorEndOfLine) | |||
} | |||
// Encode returns a WriteCloser which will encode the data written to it in | |||
// OpenPGP armor. | |||
func Encode(out io.Writer, blockType string, headers map[string]string) (w io.WriteCloser, err error) { | |||
bType := []byte(blockType) | |||
err = writeSlices(out, armorStart, bType, armorEndOfLineOut) | |||
if err != nil { | |||
return | |||
} | |||
for k, v := range headers { | |||
err = writeSlices(out, []byte(k), armorHeaderSep, []byte(v), newline) | |||
if err != nil { | |||
return | |||
} | |||
} | |||
_, err = out.Write(newline) | |||
if err != nil { | |||
return | |||
} | |||
e := &encoding{ | |||
out: out, | |||
breaker: newLineBreaker(out, 64), | |||
crc: crc24Init, | |||
blockType: bType, | |||
} | |||
e.b64 = base64.NewEncoder(base64.StdEncoding, e.breaker) | |||
return e, nil | |||
} |
@@ -0,0 +1,65 @@ | |||
// Copyright 2011 The Go Authors. All rights reserved. | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
package openpgp | |||
import ( | |||
"hash" | |||
"io" | |||
) | |||
// NewCanonicalTextHash reformats text written to it into the canonical | |||
// form and then applies the hash h. See RFC 4880, section 5.2.1. | |||
func NewCanonicalTextHash(h hash.Hash) hash.Hash { | |||
return &canonicalTextHash{h, 0} | |||
} | |||
type canonicalTextHash struct { | |||
h hash.Hash | |||
s int | |||
} | |||
var newline = []byte{'\r', '\n'} | |||
func writeCanonical(cw io.Writer, buf []byte, s *int) (int, error) { | |||
start := 0 | |||
for i, c := range buf { | |||
switch *s { | |||
case 0: | |||
if c == '\r' { | |||
*s = 1 | |||
} else if c == '\n' { | |||
cw.Write(buf[start:i]) | |||
cw.Write(newline) | |||
start = i + 1 | |||
} | |||
case 1: | |||
*s = 0 | |||
} | |||
} | |||
cw.Write(buf[start:]) | |||
return len(buf), nil | |||
} | |||
func (cth *canonicalTextHash) Write(buf []byte) (int, error) { | |||
return writeCanonical(cth.h, buf, &cth.s) | |||
} | |||
func (cth *canonicalTextHash) Sum(in []byte) []byte { | |||
return cth.h.Sum(in) | |||
} | |||
func (cth *canonicalTextHash) Reset() { | |||
cth.h.Reset() | |||
cth.s = 0 | |||
} | |||
func (cth *canonicalTextHash) Size() int { | |||
return cth.h.Size() | |||
} | |||
func (cth *canonicalTextHash) BlockSize() int { | |||
return cth.h.BlockSize() | |||
} |
@@ -0,0 +1,210 @@ | |||
// Copyright 2017 The Go Authors. All rights reserved. | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
// Package ecdh implements ECDH encryption, suitable for OpenPGP, | |||
// as specified in RFC 6637, section 8. | |||
package ecdh | |||
import ( | |||
"bytes" | |||
"errors" | |||
"io" | |||
"github.com/ProtonMail/go-crypto/openpgp/aes/keywrap" | |||
"github.com/ProtonMail/go-crypto/openpgp/internal/algorithm" | |||
"github.com/ProtonMail/go-crypto/openpgp/internal/ecc" | |||
) | |||
type KDF struct { | |||
Hash algorithm.Hash | |||
Cipher algorithm.Cipher | |||
} | |||
type PublicKey struct { | |||
curve ecc.ECDHCurve | |||
Point []byte | |||
KDF | |||
} | |||
type PrivateKey struct { | |||
PublicKey | |||
D []byte | |||
} | |||
func NewPublicKey(curve ecc.ECDHCurve, kdfHash algorithm.Hash, kdfCipher algorithm.Cipher) *PublicKey { | |||
return &PublicKey{ | |||
curve: curve, | |||
KDF: KDF{ | |||
Hash: kdfHash, | |||
Cipher: kdfCipher, | |||
}, | |||
} | |||
} | |||
func NewPrivateKey(key PublicKey) *PrivateKey { | |||
return &PrivateKey{ | |||
PublicKey: key, | |||
} | |||
} | |||
func (pk *PublicKey) GetCurve() ecc.ECDHCurve { | |||
return pk.curve | |||
} | |||
func (pk *PublicKey) MarshalPoint() []byte { | |||
return pk.curve.MarshalBytePoint(pk.Point) | |||
} | |||
func (pk *PublicKey) UnmarshalPoint(p []byte) error { | |||
pk.Point = pk.curve.UnmarshalBytePoint(p) | |||
if pk.Point == nil { | |||
return errors.New("ecdh: failed to parse EC point") | |||
} | |||
return nil | |||
} | |||
func (sk *PrivateKey) MarshalByteSecret() []byte { | |||
return sk.curve.MarshalByteSecret(sk.D) | |||
} | |||
func (sk *PrivateKey) UnmarshalByteSecret(d []byte) error { | |||
sk.D = sk.curve.UnmarshalByteSecret(d) | |||
if sk.D == nil { | |||
return errors.New("ecdh: failed to parse scalar") | |||
} | |||
return nil | |||
} | |||
func GenerateKey(rand io.Reader, c ecc.ECDHCurve, kdf KDF) (priv *PrivateKey, err error) { | |||
priv = new(PrivateKey) | |||
priv.PublicKey.curve = c | |||
priv.PublicKey.KDF = kdf | |||
priv.PublicKey.Point, priv.D, err = c.GenerateECDH(rand) | |||
return | |||
} | |||
func Encrypt(random io.Reader, pub *PublicKey, msg, curveOID, fingerprint []byte) (vsG, c []byte, err error) { | |||
if len(msg) > 40 { | |||
return nil, nil, errors.New("ecdh: message too long") | |||
} | |||
// the sender MAY use 21, 13, and 5 bytes of padding for AES-128, | |||
// AES-192, and AES-256, respectively, to provide the same number of | |||
// octets, 40 total, as an input to the key wrapping method. | |||
padding := make([]byte, 40-len(msg)) | |||
for i := range padding { | |||
padding[i] = byte(40 - len(msg)) | |||
} | |||
m := append(msg, padding...) | |||
ephemeral, zb, err := pub.curve.Encaps(random, pub.Point) | |||
if err != nil { | |||
return nil, nil, err | |||
} | |||
vsG = pub.curve.MarshalBytePoint(ephemeral) | |||
z, err := buildKey(pub, zb, curveOID, fingerprint, false, false) | |||
if err != nil { | |||
return nil, nil, err | |||
} | |||
if c, err = keywrap.Wrap(z, m); err != nil { | |||
return nil, nil, err | |||
} | |||
return vsG, c, nil | |||
} | |||
func Decrypt(priv *PrivateKey, vsG, c, curveOID, fingerprint []byte) (msg []byte, err error) { | |||
var m []byte | |||
zb, err := priv.PublicKey.curve.Decaps(priv.curve.UnmarshalBytePoint(vsG), priv.D) | |||
// Try buildKey three times to workaround an old bug, see comments in buildKey. | |||
for i := 0; i < 3; i++ { | |||
var z []byte | |||
// RFC6637 §8: "Compute Z = KDF( S, Z_len, Param );" | |||
z, err = buildKey(&priv.PublicKey, zb, curveOID, fingerprint, i == 1, i == 2) | |||
if err != nil { | |||
return nil, err | |||
} | |||
// RFC6637 §8: "Compute C = AESKeyWrap( Z, c ) as per [RFC3394]" | |||
m, err = keywrap.Unwrap(z, c) | |||
if err == nil { | |||
break | |||
} | |||
} | |||
// Only return an error after we've tried all (required) variants of buildKey. | |||
if err != nil { | |||
return nil, err | |||
} | |||
// RFC6637 §8: "m = symm_alg_ID || session key || checksum || pkcs5_padding" | |||
// The last byte should be the length of the padding, as per PKCS5; strip it off. | |||
return m[:len(m)-int(m[len(m)-1])], nil | |||
} | |||
func buildKey(pub *PublicKey, zb []byte, curveOID, fingerprint []byte, stripLeading, stripTrailing bool) ([]byte, error) { | |||
// Param = curve_OID_len || curve_OID || public_key_alg_ID || 03 | |||
// || 01 || KDF_hash_ID || KEK_alg_ID for AESKeyWrap | |||
// || "Anonymous Sender " || recipient_fingerprint; | |||
param := new(bytes.Buffer) | |||
if _, err := param.Write(curveOID); err != nil { | |||
return nil, err | |||
} | |||
algKDF := []byte{18, 3, 1, pub.KDF.Hash.Id(), pub.KDF.Cipher.Id()} | |||
if _, err := param.Write(algKDF); err != nil { | |||
return nil, err | |||
} | |||
if _, err := param.Write([]byte("Anonymous Sender ")); err != nil { | |||
return nil, err | |||
} | |||
// For v5 keys, the 20 leftmost octets of the fingerprint are used. | |||
if _, err := param.Write(fingerprint[:20]); err != nil { | |||
return nil, err | |||
} | |||
if param.Len()-len(curveOID) != 45 { | |||
return nil, errors.New("ecdh: malformed KDF Param") | |||
} | |||
// MB = Hash ( 00 || 00 || 00 || 01 || ZB || Param ); | |||
h := pub.KDF.Hash.New() | |||
if _, err := h.Write([]byte{0x0, 0x0, 0x0, 0x1}); err != nil { | |||
return nil, err | |||
} | |||
zbLen := len(zb) | |||
i := 0 | |||
j := zbLen - 1 | |||
if stripLeading { | |||
// Work around old go crypto bug where the leading zeros are missing. | |||
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-- | |||
} | |||
} | |||
if _, err := h.Write(zb[i : j+1]); err != nil { | |||
return nil, err | |||
} | |||
if _, err := h.Write(param.Bytes()); err != nil { | |||
return nil, err | |||
} | |||
mb := h.Sum(nil) | |||
return mb[:pub.KDF.Cipher.KeySize()], nil // return oBits leftmost bits of MB. | |||
} | |||
func Validate(priv *PrivateKey) error { | |||
return priv.curve.ValidateECDH(priv.Point, priv.D) | |||
} |
@@ -0,0 +1,80 @@ | |||
// Package ecdsa implements ECDSA signature, suitable for OpenPGP, | |||
// as specified in RFC 6637, section 5. | |||
package ecdsa | |||
import ( | |||
"errors" | |||
"github.com/ProtonMail/go-crypto/openpgp/internal/ecc" | |||
"io" | |||
"math/big" | |||
) | |||
type PublicKey struct { | |||
X, Y *big.Int | |||
curve ecc.ECDSACurve | |||
} | |||
type PrivateKey struct { | |||
PublicKey | |||
D *big.Int | |||
} | |||
func NewPublicKey(curve ecc.ECDSACurve) *PublicKey { | |||
return &PublicKey{ | |||
curve: curve, | |||
} | |||
} | |||
func NewPrivateKey(key PublicKey) *PrivateKey { | |||
return &PrivateKey{ | |||
PublicKey: key, | |||
} | |||
} | |||
func (pk *PublicKey) GetCurve() ecc.ECDSACurve { | |||
return pk.curve | |||
} | |||
func (pk *PublicKey) MarshalPoint() []byte { | |||
return pk.curve.MarshalIntegerPoint(pk.X, pk.Y) | |||
} | |||
func (pk *PublicKey) UnmarshalPoint(p []byte) error { | |||
pk.X, pk.Y = pk.curve.UnmarshalIntegerPoint(p) | |||
if pk.X == nil { | |||
return errors.New("ecdsa: failed to parse EC point") | |||
} | |||
return nil | |||
} | |||
func (sk *PrivateKey) MarshalIntegerSecret() []byte { | |||
return sk.curve.MarshalIntegerSecret(sk.D) | |||
} | |||
func (sk *PrivateKey) UnmarshalIntegerSecret(d []byte) error { | |||
sk.D = sk.curve.UnmarshalIntegerSecret(d) | |||
if sk.D == nil { | |||
return errors.New("ecdsa: failed to parse scalar") | |||
} | |||
return nil | |||
} | |||
func GenerateKey(rand io.Reader, c ecc.ECDSACurve) (priv *PrivateKey, err error) { | |||
priv = new(PrivateKey) | |||
priv.PublicKey.curve = c | |||
priv.PublicKey.X, priv.PublicKey.Y, priv.D, err = c.GenerateECDSA(rand) | |||
return | |||
} | |||
func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error) { | |||
return priv.PublicKey.curve.Sign(rand, priv.X, priv.Y, priv.D, hash) | |||
} | |||
func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool { | |||
return pub.curve.Verify(pub.X, pub.Y, hash, r, s) | |||
} | |||
func Validate(priv *PrivateKey) error { | |||
return priv.curve.ValidateECDSA(priv.X, priv.Y, priv.D.Bytes()) | |||
} |
@@ -0,0 +1,91 @@ | |||
// Package eddsa implements EdDSA signature, suitable for OpenPGP, as specified in | |||
// https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-13.7 | |||
package eddsa | |||
import ( | |||
"errors" | |||
"github.com/ProtonMail/go-crypto/openpgp/internal/ecc" | |||
"io" | |||
) | |||
type PublicKey struct { | |||
X []byte | |||
curve ecc.EdDSACurve | |||
} | |||
type PrivateKey struct { | |||
PublicKey | |||
D []byte | |||
} | |||
func NewPublicKey(curve ecc.EdDSACurve) *PublicKey { | |||
return &PublicKey{ | |||
curve: curve, | |||
} | |||
} | |||
func NewPrivateKey(key PublicKey) *PrivateKey { | |||
return &PrivateKey{ | |||
PublicKey: key, | |||
} | |||
} | |||
func (pk *PublicKey) GetCurve() ecc.EdDSACurve { | |||
return pk.curve | |||
} | |||
func (pk *PublicKey) MarshalPoint() []byte { | |||
return pk.curve.MarshalBytePoint(pk.X) | |||
} | |||
func (pk *PublicKey) UnmarshalPoint(x []byte) error { | |||
pk.X = pk.curve.UnmarshalBytePoint(x) | |||
if pk.X == nil { | |||
return errors.New("eddsa: failed to parse EC point") | |||
} | |||
return nil | |||
} | |||
func (sk *PrivateKey) MarshalByteSecret() []byte { | |||
return sk.curve.MarshalByteSecret(sk.D) | |||
} | |||
func (sk *PrivateKey) UnmarshalByteSecret(d []byte) error { | |||
sk.D = sk.curve.UnmarshalByteSecret(d) | |||
if sk.D == nil { | |||
return errors.New("eddsa: failed to parse scalar") | |||
} | |||
return nil | |||
} | |||
func GenerateKey(rand io.Reader, c ecc.EdDSACurve) (priv *PrivateKey, err error) { | |||
priv = new(PrivateKey) | |||
priv.PublicKey.curve = c | |||
priv.PublicKey.X, priv.D, err = c.GenerateEdDSA(rand) | |||
return | |||
} | |||
func Sign(priv *PrivateKey, message []byte) (r, s []byte, err error) { | |||
sig, err := priv.PublicKey.curve.Sign(priv.PublicKey.X, priv.D, message) | |||
if err != nil { | |||
return nil, nil, err | |||
} | |||
r, s = priv.PublicKey.curve.MarshalSignature(sig) | |||
return | |||
} | |||
func Verify(pub *PublicKey, message, r, s []byte) bool { | |||
sig := pub.curve.UnmarshalSignature(r, s) | |||
if sig == nil { | |||
return false | |||
} | |||
return pub.curve.Verify(pub.X, message, sig) | |||
} | |||
func Validate(priv *PrivateKey) error { | |||
return priv.curve.ValidateEdDSA(priv.PublicKey.X, priv.D) | |||
} |
@@ -0,0 +1,124 @@ | |||
// Copyright 2011 The Go Authors. All rights reserved. | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
// Package elgamal implements ElGamal encryption, suitable for OpenPGP, | |||
// as specified in "A Public-Key Cryptosystem and a Signature Scheme Based on | |||
// Discrete Logarithms," IEEE Transactions on Information Theory, v. IT-31, | |||
// n. 4, 1985, pp. 469-472. | |||
// | |||
// This form of ElGamal embeds PKCS#1 v1.5 padding, which may make it | |||
// unsuitable for other protocols. RSA should be used in preference in any | |||
// case. | |||
package elgamal // import "github.com/ProtonMail/go-crypto/openpgp/elgamal" | |||
import ( | |||
"crypto/rand" | |||
"crypto/subtle" | |||
"errors" | |||
"io" | |||
"math/big" | |||
) | |||
// PublicKey represents an ElGamal public key. | |||
type PublicKey struct { | |||
G, P, Y *big.Int | |||
} | |||
// PrivateKey represents an ElGamal private key. | |||
type PrivateKey struct { | |||
PublicKey | |||
X *big.Int | |||
} | |||
// Encrypt encrypts the given message to the given public key. The result is a | |||
// pair of integers. Errors can result from reading random, or because msg is | |||
// too large to be encrypted to the public key. | |||
func Encrypt(random io.Reader, pub *PublicKey, msg []byte) (c1, c2 *big.Int, err error) { | |||
pLen := (pub.P.BitLen() + 7) / 8 | |||
if len(msg) > pLen-11 { | |||
err = errors.New("elgamal: message too long") | |||
return | |||
} | |||
// EM = 0x02 || PS || 0x00 || M | |||
em := make([]byte, pLen-1) | |||
em[0] = 2 | |||
ps, mm := em[1:len(em)-len(msg)-1], em[len(em)-len(msg):] | |||
err = nonZeroRandomBytes(ps, random) | |||
if err != nil { | |||
return | |||
} | |||
em[len(em)-len(msg)-1] = 0 | |||
copy(mm, msg) | |||
m := new(big.Int).SetBytes(em) | |||
k, err := rand.Int(random, pub.P) | |||
if err != nil { | |||
return | |||
} | |||
c1 = new(big.Int).Exp(pub.G, k, pub.P) | |||
s := new(big.Int).Exp(pub.Y, k, pub.P) | |||
c2 = s.Mul(s, m) | |||
c2.Mod(c2, pub.P) | |||
return | |||
} | |||
// Decrypt takes two integers, resulting from an ElGamal encryption, and | |||
// 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 | |||
// 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) | |||
if s.ModInverse(s, priv.P) == nil { | |||
return nil, errors.New("elgamal: invalid private key") | |||
} | |||
s.Mul(s, c2) | |||
s.Mod(s, priv.P) | |||
em := s.Bytes() | |||
firstByteIsTwo := subtle.ConstantTimeByteEq(em[0], 2) | |||
// The remainder of the plaintext must be a string of non-zero random | |||
// octets, followed by a 0, followed by the message. | |||
// lookingForIndex: 1 iff we are still looking for the zero. | |||
// index: the offset of the first zero byte. | |||
var lookingForIndex, index int | |||
lookingForIndex = 1 | |||
for i := 1; i < len(em); i++ { | |||
equals0 := subtle.ConstantTimeByteEq(em[i], 0) | |||
index = subtle.ConstantTimeSelect(lookingForIndex&equals0, i, index) | |||
lookingForIndex = subtle.ConstantTimeSelect(equals0, 0, lookingForIndex) | |||
} | |||
if firstByteIsTwo != 1 || lookingForIndex != 0 || index < 9 { | |||
return nil, errors.New("elgamal: decryption error") | |||
} | |||
return em[index+1:], nil | |||
} | |||
// nonZeroRandomBytes fills the given slice with non-zero random octets. | |||
func nonZeroRandomBytes(s []byte, rand io.Reader) (err error) { | |||
_, err = io.ReadFull(rand, s) | |||
if err != nil { | |||
return | |||
} | |||
for i := 0; i < len(s); i++ { | |||
for s[i] == 0 { | |||
_, err = io.ReadFull(rand, s[i:i+1]) | |||
if err != nil { | |||
return | |||
} | |||
} | |||
} | |||
return | |||
} |
@@ -0,0 +1,116 @@ | |||
// Copyright 2010 The Go Authors. All rights reserved. | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
// Package errors contains common error types for the OpenPGP packages. | |||
package errors // import "github.com/ProtonMail/go-crypto/openpgp/errors" | |||
import ( | |||
"strconv" | |||
) | |||
// A StructuralError is returned when OpenPGP data is found to be syntactically | |||
// invalid. | |||
type StructuralError string | |||
func (s StructuralError) Error() string { | |||
return "openpgp: invalid data: " + string(s) | |||
} | |||
// UnsupportedError indicates that, although the OpenPGP data is valid, it | |||
// makes use of currently unimplemented features. | |||
type UnsupportedError string | |||
func (s UnsupportedError) Error() string { | |||
return "openpgp: unsupported feature: " + string(s) | |||
} | |||
// InvalidArgumentError indicates that the caller is in error and passed an | |||
// incorrect value. | |||
type InvalidArgumentError string | |||
func (i InvalidArgumentError) Error() string { | |||
return "openpgp: invalid argument: " + string(i) | |||
} | |||
// SignatureError indicates that a syntactically valid signature failed to | |||
// validate. | |||
type SignatureError string | |||
func (b SignatureError) Error() string { | |||
return "openpgp: invalid signature: " + string(b) | |||
} | |||
var ErrMDCHashMismatch error = SignatureError("MDC hash mismatch") | |||
var ErrMDCMissing error = SignatureError("MDC packet not found") | |||
type signatureExpiredError int | |||
func (se signatureExpiredError) Error() string { | |||
return "openpgp: signature expired" | |||
} | |||
var ErrSignatureExpired error = signatureExpiredError(0) | |||
type keyExpiredError int | |||
func (ke keyExpiredError) Error() string { | |||
return "openpgp: key expired" | |||
} | |||
var ErrKeyExpired error = keyExpiredError(0) | |||
type keyIncorrectError int | |||
func (ki keyIncorrectError) Error() string { | |||
return "openpgp: incorrect key" | |||
} | |||
var ErrKeyIncorrect error = keyIncorrectError(0) | |||
// KeyInvalidError indicates that the public key parameters are invalid | |||
// as they do not match the private ones | |||
type KeyInvalidError string | |||
func (e KeyInvalidError) Error() string { | |||
return "openpgp: invalid key: " + string(e) | |||
} | |||
type unknownIssuerError int | |||
func (unknownIssuerError) Error() string { | |||
return "openpgp: signature made by unknown entity" | |||
} | |||
var ErrUnknownIssuer error = unknownIssuerError(0) | |||
type keyRevokedError int | |||
func (keyRevokedError) Error() string { | |||
return "openpgp: signature made by revoked key" | |||
} | |||
var ErrKeyRevoked error = keyRevokedError(0) | |||
type UnknownPacketTypeError uint8 | |||
func (upte UnknownPacketTypeError) Error() string { | |||
return "openpgp: unknown packet type: " + strconv.Itoa(int(upte)) | |||
} | |||
// AEADError indicates that there is a problem when initializing or using a | |||
// AEAD instance, configuration struct, nonces or index values. | |||
type AEADError string | |||
func (ae AEADError) Error() string { | |||
return "openpgp: aead error: " + string(ae) | |||
} | |||
// ErrDummyPrivateKey results when operations are attempted on a private key | |||
// that is just a dummy key. See | |||
// https://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=blob;f=doc/DETAILS;h=fe55ae16ab4e26d8356dc574c9e8bc935e71aef1;hb=23191d7851eae2217ecdac6484349849a24fd94a#l1109 | |||
type ErrDummyPrivateKey string | |||
func (dke ErrDummyPrivateKey) Error() string { | |||
return "openpgp: s2k GNU dummy key: " + string(dke) | |||
} |
@@ -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) | |||
} |
@@ -0,0 +1,65 @@ | |||
// Copyright (C) 2019 ProtonTech AG | |||
package algorithm | |||
import ( | |||
"crypto/cipher" | |||
"github.com/ProtonMail/go-crypto/eax" | |||
"github.com/ProtonMail/go-crypto/ocb" | |||
) | |||
// AEADMode defines the Authenticated Encryption with Associated Data mode of | |||
// operation. | |||
type AEADMode uint8 | |||
// Supported modes of operation (see RFC4880bis [EAX] and RFC7253) | |||
const ( | |||
AEADModeEAX = AEADMode(1) | |||
AEADModeOCB = AEADMode(2) | |||
AEADModeGCM = AEADMode(3) | |||
) | |||
// TagLength returns the length in bytes of authentication tags. | |||
func (mode AEADMode) TagLength() int { | |||
switch mode { | |||
case AEADModeEAX: | |||
return 16 | |||
case AEADModeOCB: | |||
return 16 | |||
case AEADModeGCM: | |||
return 16 | |||
default: | |||
return 0 | |||
} | |||
} | |||
// NonceLength returns the length in bytes of nonces. | |||
func (mode AEADMode) NonceLength() int { | |||
switch mode { | |||
case AEADModeEAX: | |||
return 16 | |||
case AEADModeOCB: | |||
return 15 | |||
case AEADModeGCM: | |||
return 12 | |||
default: | |||
return 0 | |||
} | |||
} | |||
// New returns a fresh instance of the given mode | |||
func (mode AEADMode) New(block cipher.Block) (alg cipher.AEAD) { | |||
var err error | |||
switch mode { | |||
case AEADModeEAX: | |||
alg, err = eax.NewEAX(block) | |||
case AEADModeOCB: | |||
alg, err = ocb.NewOCB(block) | |||
case AEADModeGCM: | |||
alg, err = cipher.NewGCM(block) | |||
} | |||
if err != nil { | |||
panic(err.Error()) | |||
} | |||
return alg | |||
} |
@@ -0,0 +1,107 @@ | |||
// Copyright 2017 The Go Authors. All rights reserved. | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
package algorithm | |||
import ( | |||
"crypto/aes" | |||
"crypto/cipher" | |||
"crypto/des" | |||
"golang.org/x/crypto/cast5" | |||
) | |||
// Cipher is an official symmetric key cipher algorithm. See RFC 4880, | |||
// section 9.2. | |||
type Cipher interface { | |||
// Id returns the algorithm ID, as a byte, of the cipher. | |||
Id() uint8 | |||
// KeySize returns the key size, in bytes, of the cipher. | |||
KeySize() int | |||
// BlockSize returns the block size, in bytes, of the cipher. | |||
BlockSize() int | |||
// New returns a fresh instance of the given cipher. | |||
New(key []byte) cipher.Block | |||
} | |||
// The following constants mirror the OpenPGP standard (RFC 4880). | |||
const ( | |||
TripleDES = CipherFunction(2) | |||
CAST5 = CipherFunction(3) | |||
AES128 = CipherFunction(7) | |||
AES192 = CipherFunction(8) | |||
AES256 = CipherFunction(9) | |||
) | |||
// CipherById represents the different block ciphers specified for OpenPGP. See | |||
// http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-13 | |||
var CipherById = map[uint8]Cipher{ | |||
TripleDES.Id(): TripleDES, | |||
CAST5.Id(): CAST5, | |||
AES128.Id(): AES128, | |||
AES192.Id(): AES192, | |||
AES256.Id(): AES256, | |||
} | |||
type CipherFunction uint8 | |||
// ID returns the algorithm Id, as a byte, of cipher. | |||
func (sk CipherFunction) Id() uint8 { | |||
return uint8(sk) | |||
} | |||
var keySizeByID = map[uint8]int{ | |||
TripleDES.Id(): 24, | |||
CAST5.Id(): cast5.KeySize, | |||
AES128.Id(): 16, | |||
AES192.Id(): 24, | |||
AES256.Id(): 32, | |||
} | |||
// KeySize returns the key size, in bytes, of cipher. | |||
func (cipher CipherFunction) KeySize() int { | |||
switch cipher { | |||
case TripleDES: | |||
return 24 | |||
case CAST5: | |||
return cast5.KeySize | |||
case AES128: | |||
return 16 | |||
case AES192: | |||
return 24 | |||
case AES256: | |||
return 32 | |||
} | |||
return 0 | |||
} | |||
// BlockSize returns the block size, in bytes, of cipher. | |||
func (cipher CipherFunction) BlockSize() int { | |||
switch cipher { | |||
case TripleDES: | |||
return des.BlockSize | |||
case CAST5: | |||
return 8 | |||
case AES128, AES192, AES256: | |||
return 16 | |||
} | |||
return 0 | |||
} | |||
// New returns a fresh instance of the given cipher. | |||
func (cipher CipherFunction) New(key []byte) (block cipher.Block) { | |||
var err error | |||
switch cipher { | |||
case TripleDES: | |||
block, err = des.NewTripleDESCipher(key) | |||
case CAST5: | |||
block, err = cast5.NewCipher(key) | |||
case AES128, AES192, AES256: | |||
block, err = aes.NewCipher(key) | |||
} | |||
if err != nil { | |||
panic(err.Error()) | |||
} | |||
return | |||
} |
@@ -0,0 +1,143 @@ | |||
// Copyright 2017 The Go Authors. All rights reserved. | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
package algorithm | |||
import ( | |||
"crypto" | |||
"fmt" | |||
"hash" | |||
) | |||
// Hash is an official hash function algorithm. See RFC 4880, section 9.4. | |||
type Hash interface { | |||
// Id returns the algorithm ID, as a byte, of Hash. | |||
Id() uint8 | |||
// Available reports whether the given hash function is linked into the binary. | |||
Available() bool | |||
// HashFunc simply returns the value of h so that Hash implements SignerOpts. | |||
HashFunc() crypto.Hash | |||
// New returns a new hash.Hash calculating the given hash function. New | |||
// panics if the hash function is not linked into the binary. | |||
New() hash.Hash | |||
// Size returns the length, in bytes, of a digest resulting from the given | |||
// hash function. It doesn't require that the hash function in question be | |||
// linked into the program. | |||
Size() int | |||
// String is the name of the hash function corresponding to the given | |||
// OpenPGP hash id. | |||
String() string | |||
} | |||
// 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} | |||
) | |||
// 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, | |||
} | |||
) | |||
// cryptoHash contains pairs relating OpenPGP's hash identifier with | |||
// Go's crypto.Hash type. See RFC 4880, section 9.4. | |||
type cryptoHash struct { | |||
id uint8 | |||
crypto.Hash | |||
} | |||
// Id returns the algorithm ID, as a byte, of cryptoHash. | |||
func (h cryptoHash) Id() uint8 { | |||
return h.id | |||
} | |||
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", | |||
} | |||
func (h cryptoHash) String() string { | |||
s, ok := hashNames[h.id] | |||
if !ok { | |||
panic(fmt.Sprintf("Unsupported hash function %d", h.id)) | |||
} | |||
return s | |||
} | |||
// HashIdToHash returns a crypto.Hash which corresponds to the given OpenPGP | |||
// hash id. | |||
func HashIdToHash(id byte) (h crypto.Hash, ok bool) { | |||
if hash, ok := HashById[id]; ok { | |||
return hash.HashFunc(), true | |||
} | |||
return 0, false | |||
} | |||
// HashIdToHashWithSha1 returns a crypto.Hash which corresponds to the given OpenPGP | |||
// hash id, allowing sha1. | |||
func HashIdToHashWithSha1(id byte) (h crypto.Hash, ok bool) { | |||
if hash, ok := HashById[id]; ok { | |||
return hash.HashFunc(), true | |||
} | |||
if id == SHA1.Id() { | |||
return SHA1.HashFunc(), true | |||
} | |||
return 0, false | |||
} | |||
// HashIdToString returns the name of the hash function corresponding to the | |||
// given OpenPGP hash id. | |||
func HashIdToString(id byte) (name string, ok bool) { | |||
if hash, ok := HashById[id]; ok { | |||
return hash.String(), true | |||
} | |||
return "", false | |||
} | |||
// HashToHashId returns an OpenPGP hash id which corresponds the given Hash. | |||
func HashToHashId(h crypto.Hash) (id byte, ok bool) { | |||
for id, hash := range HashById { | |||
if hash.HashFunc() == h { | |||
return id, true | |||
} | |||
} | |||
return 0, false | |||
} | |||
// HashToHashIdWithSha1 returns an OpenPGP hash id which corresponds the given Hash, | |||
// allowing instances of SHA1 | |||
func HashToHashIdWithSha1(h crypto.Hash) (id byte, ok bool) { | |||
for id, hash := range HashById { | |||
if hash.HashFunc() == h { | |||
return id, true | |||
} | |||
} | |||
if h == SHA1.HashFunc() { | |||
return SHA1.Id(), true | |||
} | |||
return 0, false | |||
} |
@@ -0,0 +1,171 @@ | |||
// Package ecc implements a generic interface for ECDH, ECDSA, and EdDSA. | |||
package ecc | |||
import ( | |||
"crypto/subtle" | |||
"io" | |||
"github.com/ProtonMail/go-crypto/openpgp/errors" | |||
x25519lib "github.com/cloudflare/circl/dh/x25519" | |||
) | |||
type curve25519 struct{} | |||
func NewCurve25519() *curve25519 { | |||
return &curve25519{} | |||
} | |||
func (c *curve25519) GetCurveName() string { | |||
return "curve25519" | |||
} | |||
// 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 { | |||
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 { | |||
return nil | |||
} | |||
// Remove prefix | |||
return point[1:] | |||
} | |||
// MarshalByteSecret encodes the secret scalar from native format. | |||
// Note that the EC secret scalar differs from the definition of public keys in | |||
// [Curve25519] in two ways: (1) the byte-ordering is big-endian, which is | |||
// more uniform with how big integers are represented in OpenPGP, and (2) the | |||
// leading zeros are truncated. | |||
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.6.1.1 | |||
// Note that leading zero bytes are stripped later when encoding as an MPI. | |||
func (c *curve25519) MarshalByteSecret(secret []byte) []byte { | |||
d := make([]byte, x25519lib.Size) | |||
copyReversed(d, secret) | |||
// The following ensures that the private key is a number of the form | |||
// 2^{254} + 8 * [0, 2^{251}), in order to avoid the small subgroup of | |||
// the curve. | |||
// | |||
// This masking is done internally in the underlying lib and so is unnecessary | |||
// for security, but OpenPGP implementations require that private keys be | |||
// pre-masked. | |||
d[0] &= 127 | |||
d[0] |= 64 | |||
d[31] &= 248 | |||
return d | |||
} | |||
// UnmarshalByteSecret decodes the secret scalar from native format. | |||
// Note that the EC secret scalar differs from the definition of public keys in | |||
// [Curve25519] in two ways: (1) the byte-ordering is big-endian, which is | |||
// more uniform with how big integers are represented in OpenPGP, and (2) the | |||
// leading zeros are truncated. | |||
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.6.1.1 | |||
func (c *curve25519) UnmarshalByteSecret(d []byte) []byte { | |||
if len(d) > x25519lib.Size { | |||
return nil | |||
} | |||
// Ensure truncated leading bytes are re-added | |||
secret := make([]byte, x25519lib.Size) | |||
copyReversed(secret, d) | |||
return secret | |||
} | |||
// generateKeyPairBytes Generates a private-public key-pair. | |||
// 'priv' is a private key; a little-endian scalar belonging to the set | |||
// 2^{254} + 8 * [0, 2^{251}), in order to avoid the small subgroup of the | |||
// curve. 'pub' is simply 'priv' * G where G is the base point. | |||
// See https://cr.yp.to/ecdh.html and RFC7748, sec 5. | |||
func (c *curve25519) generateKeyPairBytes(rand io.Reader) (priv, pub x25519lib.Key, err error) { | |||
_, err = io.ReadFull(rand, priv[:]) | |||
if err != nil { | |||
return | |||
} | |||
x25519lib.KeyGen(&pub, &priv) | |||
return | |||
} | |||
func (c *curve25519) GenerateECDH(rand io.Reader) (point []byte, secret []byte, err error) { | |||
priv, pub, err := c.generateKeyPairBytes(rand) | |||
if err != nil { | |||
return | |||
} | |||
return pub[:], priv[:], nil | |||
} | |||
func (c *genericCurve) MaskSecret(secret []byte) []byte { | |||
return secret | |||
} | |||
func (c *curve25519) Encaps(rand io.Reader, point []byte) (ephemeral, sharedSecret []byte, err error) { | |||
// RFC6637 §8: "Generate an ephemeral key pair {v, V=vG}" | |||
// ephemeralPrivate corresponds to `v`. | |||
// ephemeralPublic corresponds to `V`. | |||
ephemeralPrivate, ephemeralPublic, err := c.generateKeyPairBytes(rand) | |||
if err != nil { | |||
return nil, nil, err | |||
} | |||
// RFC6637 §8: "Obtain the authenticated recipient public key R" | |||
// pubKey corresponds to `R`. | |||
var pubKey x25519lib.Key | |||
copy(pubKey[:], point) | |||
// RFC6637 §8: "Compute the shared point S = vR" | |||
// "VB = convert point V to the octet string" | |||
// sharedPoint corresponds to `VB`. | |||
var sharedPoint x25519lib.Key | |||
x25519lib.Shared(&sharedPoint, &ephemeralPrivate, &pubKey) | |||
return ephemeralPublic[:], sharedPoint[:], nil | |||
} | |||
func (c *curve25519) Decaps(vsG, secret []byte) (sharedSecret []byte, err error) { | |||
var ephemeralPublic, decodedPrivate, sharedPoint x25519lib.Key | |||
// RFC6637 §8: "The decryption is the inverse of the method given." | |||
// All quoted descriptions in comments below describe encryption, and | |||
// the reverse is performed. | |||
// vsG corresponds to `VB` in RFC6637 §8 . | |||
// RFC6637 §8: "VB = convert point V to the octet string" | |||
copy(ephemeralPublic[:], vsG) | |||
// decodedPrivate corresponds to `r` in RFC6637 §8 . | |||
copy(decodedPrivate[:], secret) | |||
// RFC6637 §8: "Note that the recipient obtains the shared secret by calculating | |||
// S = rV = rvG, where (r,R) is the recipient's key pair." | |||
// sharedPoint corresponds to `S`. | |||
x25519lib.Shared(&sharedPoint, &decodedPrivate, &ephemeralPublic) | |||
return sharedPoint[:], nil | |||
} | |||
func (c *curve25519) ValidateECDH(point []byte, secret []byte) (err error) { | |||
var pk, sk x25519lib.Key | |||
copy(sk[:], secret) | |||
x25519lib.KeyGen(&pk, &sk) | |||
if subtle.ConstantTimeCompare(point, pk[:]) == 0 { | |||
return errors.KeyInvalidError("ecc: invalid curve25519 public point") | |||
} | |||
return nil | |||
} | |||
func copyReversed(out []byte, in []byte) { | |||
l := len(in) | |||
for i := 0; i < l; i++ { | |||
out[i] = in[l-i-1] | |||
} | |||
} |
@@ -0,0 +1,140 @@ | |||
// Package ecc implements a generic interface for ECDH, ECDSA, and EdDSA. | |||
package ecc | |||
import ( | |||
"bytes" | |||
"crypto/elliptic" | |||
"github.com/ProtonMail/go-crypto/bitcurves" | |||
"github.com/ProtonMail/go-crypto/brainpool" | |||
"github.com/ProtonMail/go-crypto/openpgp/internal/encoding" | |||
) | |||
type CurveInfo struct { | |||
GenName string | |||
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()), | |||
}, | |||
{ | |||
// NIST P-384 | |||
GenName: "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()), | |||
}, | |||
{ | |||
// SecP256k1 | |||
GenName: "SecP256k1", | |||
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(), | |||
}, | |||
{ | |||
// X448 | |||
GenName: "Curve448", | |||
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(), | |||
}, | |||
{ | |||
// Ed448 | |||
GenName: "Curve448", | |||
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()), | |||
}, | |||
{ | |||
// BrainpoolP384r1 | |||
GenName: "BrainpoolP384", | |||
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()), | |||
}, | |||
} | |||
func FindByCurve(curve Curve) *CurveInfo { | |||
for _, curveInfo := range Curves { | |||
if curveInfo.Curve.GetCurveName() == curve.GetCurveName() { | |||
return &curveInfo | |||
} | |||
} | |||
return nil | |||
} | |||
func FindByOid(oid encoding.Field) *CurveInfo { | |||
var rawBytes = oid.Bytes() | |||
for _, curveInfo := range Curves { | |||
if bytes.Equal(curveInfo.Oid.Bytes(), rawBytes) { | |||
return &curveInfo | |||
} | |||
} | |||
return nil | |||
} | |||
func FindEdDSAByGenName(curveGenName string) EdDSACurve { | |||
for _, curveInfo := range Curves { | |||
if curveInfo.GenName == curveGenName { | |||
curve, ok := curveInfo.Curve.(EdDSACurve) | |||
if ok { | |||
return curve | |||
} | |||
} | |||
} | |||
return nil | |||
} | |||
func FindECDSAByGenName(curveGenName string) ECDSACurve { | |||
for _, curveInfo := range Curves { | |||
if curveInfo.GenName == curveGenName { | |||
curve, ok := curveInfo.Curve.(ECDSACurve) | |||
if ok { | |||
return curve | |||
} | |||
} | |||
} | |||
return nil | |||
} | |||
func FindECDHByGenName(curveGenName string) ECDHCurve { | |||
for _, curveInfo := range Curves { | |||
if curveInfo.GenName == curveGenName { | |||
curve, ok := curveInfo.Curve.(ECDHCurve) | |||
if ok { | |||
return curve | |||
} | |||
} | |||
} | |||
return nil | |||
} |
@@ -0,0 +1,48 @@ | |||
// Package ecc implements a generic interface for ECDH, ECDSA, and EdDSA. | |||
package ecc | |||
import ( | |||
"io" | |||
"math/big" | |||
) | |||
type Curve interface { | |||
GetCurveName() string | |||
} | |||
type ECDSACurve interface { | |||
Curve | |||
MarshalIntegerPoint(x, y *big.Int) []byte | |||
UnmarshalIntegerPoint([]byte) (x, y *big.Int) | |||
MarshalIntegerSecret(d *big.Int) []byte | |||
UnmarshalIntegerSecret(d []byte) *big.Int | |||
GenerateECDSA(rand io.Reader) (x, y, secret *big.Int, err error) | |||
Sign(rand io.Reader, x, y, d *big.Int, hash []byte) (r, s *big.Int, err error) | |||
Verify(x, y *big.Int, hash []byte, r, s *big.Int) bool | |||
ValidateECDSA(x, y *big.Int, secret []byte) error | |||
} | |||
type EdDSACurve interface { | |||
Curve | |||
MarshalBytePoint(x []byte) []byte | |||
UnmarshalBytePoint([]byte) (x []byte) | |||
MarshalByteSecret(d []byte) []byte | |||
UnmarshalByteSecret(d []byte) []byte | |||
MarshalSignature(sig []byte) (r, s []byte) | |||
UnmarshalSignature(r, s []byte) (sig []byte) | |||
GenerateEdDSA(rand io.Reader) (pub, priv []byte, err error) | |||
Sign(publicKey, privateKey, message []byte) (sig []byte, err error) | |||
Verify(publicKey, message, sig []byte) bool | |||
ValidateEdDSA(publicKey, privateKey []byte) (err error) | |||
} | |||
type ECDHCurve interface { | |||
Curve | |||
MarshalBytePoint([]byte) (encoded []byte) | |||
UnmarshalBytePoint(encoded []byte) []byte | |||
MarshalByteSecret(d []byte) []byte | |||
UnmarshalByteSecret(d []byte) []byte | |||
GenerateECDH(rand io.Reader) (point []byte, secret []byte, err error) | |||
Encaps(rand io.Reader, point []byte) (ephemeral, sharedSecret []byte, err error) | |||
Decaps(ephemeral, secret []byte) (sharedSecret []byte, err error) | |||
ValidateECDH(public []byte, secret []byte) error | |||
} |
@@ -0,0 +1,112 @@ | |||
// Package ecc implements a generic interface for ECDH, ECDSA, and EdDSA. | |||
package ecc | |||
import ( | |||
"crypto/subtle" | |||
"io" | |||
"github.com/ProtonMail/go-crypto/openpgp/errors" | |||
ed25519lib "github.com/cloudflare/circl/sign/ed25519" | |||
) | |||
const ed25519Size = 32 | |||
type ed25519 struct{} | |||
func NewEd25519() *ed25519 { | |||
return &ed25519{} | |||
} | |||
func (c *ed25519) GetCurveName() string { | |||
return "ed25519" | |||
} | |||
// 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.5 | |||
func (c *ed25519) MarshalBytePoint(x []byte) []byte { | |||
return append([]byte{0x40}, x...) | |||
} | |||
// 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 { | |||
return nil | |||
} | |||
// Return unprefixed | |||
return point[1:] | |||
} | |||
// MarshalByteSecret encodes a scalar in native format. | |||
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.5 | |||
func (c *ed25519) MarshalByteSecret(d []byte) []byte { | |||
return d | |||
} | |||
// UnmarshalByteSecret decodes a scalar in native format and re-adds the stripped leading zeroes | |||
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.5 | |||
func (c *ed25519) UnmarshalByteSecret(s []byte) (d []byte) { | |||
if len(s) > ed25519lib.SeedSize { | |||
return nil | |||
} | |||
// Handle stripped leading zeroes | |||
d = make([]byte, ed25519lib.SeedSize) | |||
copy(d[ed25519lib.SeedSize-len(s):], s) | |||
return | |||
} | |||
// MarshalSignature splits a signature in R and S. | |||
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.2.3.3.1 | |||
func (c *ed25519) MarshalSignature(sig []byte) (r, s []byte) { | |||
return sig[:ed25519Size], sig[ed25519Size:] | |||
} | |||
// UnmarshalSignature decodes R and S in the native format, re-adding the stripped leading zeroes | |||
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.2.3.3.1 | |||
func (c *ed25519) UnmarshalSignature(r, s []byte) (sig []byte) { | |||
// Check size | |||
if len(r) > 32 || len(s) > 32 { | |||
return nil | |||
} | |||
sig = make([]byte, ed25519lib.SignatureSize) | |||
// Handle stripped leading zeroes | |||
copy(sig[ed25519Size-len(r):ed25519Size], r) | |||
copy(sig[ed25519lib.SignatureSize-len(s):], s) | |||
return sig | |||
} | |||
func (c *ed25519) GenerateEdDSA(rand io.Reader) (pub, priv []byte, err error) { | |||
pk, sk, err := ed25519lib.GenerateKey(rand) | |||
if err != nil { | |||
return nil, nil, err | |||
} | |||
return pk, sk[:ed25519lib.SeedSize], nil | |||
} | |||
func getEd25519Sk(publicKey, privateKey []byte) ed25519lib.PrivateKey { | |||
return append(privateKey, publicKey...) | |||
} | |||
func (c *ed25519) Sign(publicKey, privateKey, message []byte) (sig []byte, err error) { | |||
sig = ed25519lib.Sign(getEd25519Sk(publicKey, privateKey), message) | |||
return sig, nil | |||
} | |||
func (c *ed25519) Verify(publicKey, message, sig []byte) bool { | |||
return ed25519lib.Verify(publicKey, message, sig) | |||
} | |||
func (c *ed25519) ValidateEdDSA(publicKey, privateKey []byte) (err error) { | |||
priv := getEd25519Sk(publicKey, privateKey) | |||
expectedPriv := ed25519lib.NewKeyFromSeed(priv.Seed()) | |||
if subtle.ConstantTimeCompare(priv, expectedPriv) == 0 { | |||
return errors.KeyInvalidError("ecc: invalid ed25519 secret") | |||
} | |||
return nil | |||
} |
@@ -0,0 +1,111 @@ | |||
// Package ecc implements a generic interface for ECDH, ECDSA, and EdDSA. | |||
package ecc | |||
import ( | |||
"crypto/subtle" | |||
"io" | |||
"github.com/ProtonMail/go-crypto/openpgp/errors" | |||
ed448lib "github.com/cloudflare/circl/sign/ed448" | |||
) | |||
type ed448 struct{} | |||
func NewEd448() *ed448 { | |||
return &ed448{} | |||
} | |||
func (c *ed448) GetCurveName() string { | |||
return "ed448" | |||
} | |||
// 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.5 | |||
func (c *ed448) MarshalBytePoint(x []byte) []byte { | |||
// Return prefixed | |||
return append([]byte{0x40}, x...) | |||
} | |||
// 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 { | |||
return nil | |||
} | |||
// Strip prefix | |||
return point[1:] | |||
} | |||
// MarshalByteSecret encoded a scalar from native format to prefixed. | |||
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.5 | |||
func (c *ed448) MarshalByteSecret(d []byte) []byte { | |||
// Return prefixed | |||
return append([]byte{0x40}, d...) | |||
} | |||
// 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.5 | |||
func (c *ed448) UnmarshalByteSecret(s []byte) (d []byte) { | |||
// Check prefixed size | |||
if len(s) != ed448lib.SeedSize+1 { | |||
return nil | |||
} | |||
// Strip prefix | |||
return s[1:] | |||
} | |||
// MarshalSignature splits a signature in R and S, where R is in prefixed native format and | |||
// S is an MPI with value zero. | |||
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.2.3.3.2 | |||
func (c *ed448) MarshalSignature(sig []byte) (r, s []byte) { | |||
return append([]byte{0x40}, sig...), []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 { | |||
return nil | |||
} | |||
return r[1:] | |||
} | |||
func (c *ed448) GenerateEdDSA(rand io.Reader) (pub, priv []byte, err error) { | |||
pk, sk, err := ed448lib.GenerateKey(rand) | |||
if err != nil { | |||
return nil, nil, err | |||
} | |||
return pk, sk[:ed448lib.SeedSize], nil | |||
} | |||
func getEd448Sk(publicKey, privateKey []byte) ed448lib.PrivateKey { | |||
return append(privateKey, publicKey...) | |||
} | |||
func (c *ed448) Sign(publicKey, privateKey, message []byte) (sig []byte, err error) { | |||
// Ed448 is used with the empty string as a context string. | |||
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-13.7 | |||
sig = ed448lib.Sign(getEd448Sk(publicKey, privateKey), message, "") | |||
return sig, nil | |||
} | |||
func (c *ed448) Verify(publicKey, message, sig []byte) bool { | |||
// Ed448 is used with the empty string as a context string. | |||
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-13.7 | |||
return ed448lib.Verify(publicKey, message, sig, "") | |||
} | |||
func (c *ed448) ValidateEdDSA(publicKey, privateKey []byte) (err error) { | |||
priv := getEd448Sk(publicKey, privateKey) | |||
expectedPriv := ed448lib.NewKeyFromSeed(priv.Seed()) | |||
if subtle.ConstantTimeCompare(priv, expectedPriv) == 0 { | |||
return errors.KeyInvalidError("ecc: invalid ed448 secret") | |||
} | |||
return nil | |||
} |
@@ -0,0 +1,149 @@ | |||
// Package ecc implements a generic interface for ECDH, ECDSA, and EdDSA. | |||
package ecc | |||
import ( | |||
"crypto/ecdsa" | |||
"crypto/elliptic" | |||
"fmt" | |||
"github.com/ProtonMail/go-crypto/openpgp/errors" | |||
"io" | |||
"math/big" | |||
) | |||
type genericCurve struct { | |||
Curve elliptic.Curve | |||
} | |||
func NewGenericCurve(c elliptic.Curve) *genericCurve { | |||
return &genericCurve{ | |||
Curve: c, | |||
} | |||
} | |||
func (c *genericCurve) GetCurveName() string { | |||
return c.Curve.Params().Name | |||
} | |||
func (c *genericCurve) MarshalBytePoint(point []byte) []byte { | |||
return point | |||
} | |||
func (c *genericCurve) UnmarshalBytePoint(point []byte) []byte { | |||
return point | |||
} | |||
func (c *genericCurve) MarshalIntegerPoint(x, y *big.Int) []byte { | |||
return elliptic.Marshal(c.Curve, x, y) | |||
} | |||
func (c *genericCurve) UnmarshalIntegerPoint(point []byte) (x, y *big.Int) { | |||
return elliptic.Unmarshal(c.Curve, point) | |||
} | |||
func (c *genericCurve) MarshalByteSecret(d []byte) []byte { | |||
return d | |||
} | |||
func (c *genericCurve) UnmarshalByteSecret(d []byte) []byte { | |||
return d | |||
} | |||
func (c *genericCurve) MarshalIntegerSecret(d *big.Int) []byte { | |||
return d.Bytes() | |||
} | |||
func (c *genericCurve) UnmarshalIntegerSecret(d []byte) *big.Int { | |||
return new(big.Int).SetBytes(d) | |||
} | |||
func (c *genericCurve) GenerateECDH(rand io.Reader) (point, secret []byte, err error) { | |||
secret, x, y, err := elliptic.GenerateKey(c.Curve, rand) | |||
if err != nil { | |||
return nil, nil, err | |||
} | |||
point = elliptic.Marshal(c.Curve, x, y) | |||
return point, secret, nil | |||
} | |||
func (c *genericCurve) GenerateECDSA(rand io.Reader) (x, y, secret *big.Int, err error) { | |||
priv, err := ecdsa.GenerateKey(c.Curve, rand) | |||
if err != nil { | |||
return | |||
} | |||
return priv.X, priv.Y, priv.D, nil | |||
} | |||
func (c *genericCurve) Encaps(rand io.Reader, point []byte) (ephemeral, sharedSecret []byte, err error) { | |||
xP, yP := elliptic.Unmarshal(c.Curve, point) | |||
if xP == nil { | |||
panic("invalid point") | |||
} | |||
d, x, y, err := elliptic.GenerateKey(c.Curve, rand) | |||
if err != nil { | |||
return nil, nil, err | |||
} | |||
vsG := elliptic.Marshal(c.Curve, x, y) | |||
zbBig, _ := c.Curve.ScalarMult(xP, yP, d) | |||
byteLen := (c.Curve.Params().BitSize + 7) >> 3 | |||
zb := make([]byte, byteLen) | |||
zbBytes := zbBig.Bytes() | |||
copy(zb[byteLen-len(zbBytes):], zbBytes) | |||
return vsG, zb, nil | |||
} | |||
func (c *genericCurve) Decaps(ephemeral, secret []byte) (sharedSecret []byte, err error) { | |||
x, y := elliptic.Unmarshal(c.Curve, ephemeral) | |||
zbBig, _ := c.Curve.ScalarMult(x, y, secret) | |||
byteLen := (c.Curve.Params().BitSize + 7) >> 3 | |||
zb := make([]byte, byteLen) | |||
zbBytes := zbBig.Bytes() | |||
copy(zb[byteLen-len(zbBytes):], zbBytes) | |||
return zb, nil | |||
} | |||
func (c *genericCurve) Sign(rand io.Reader, x, y, d *big.Int, hash []byte) (r, s *big.Int, err error) { | |||
priv := &ecdsa.PrivateKey{D: d, PublicKey: ecdsa.PublicKey{X: x, Y: y, Curve: c.Curve}} | |||
return ecdsa.Sign(rand, priv, hash) | |||
} | |||
func (c *genericCurve) Verify(x, y *big.Int, hash []byte, r, s *big.Int) bool { | |||
pub := &ecdsa.PublicKey{X: x, Y: y, Curve: c.Curve} | |||
return ecdsa.Verify(pub, hash, r, s) | |||
} | |||
func (c *genericCurve) validate(xP, yP *big.Int, secret []byte) error { | |||
// the public point should not be at infinity (0,0) | |||
zero := new(big.Int) | |||
if xP.Cmp(zero) == 0 && yP.Cmp(zero) == 0 { | |||
return errors.KeyInvalidError(fmt.Sprintf("ecc (%s): infinity point", c.Curve.Params().Name)) | |||
} | |||
// re-derive the public point Q' = (X,Y) = dG | |||
// to compare to declared Q in public key | |||
expectedX, expectedY := c.Curve.ScalarBaseMult(secret) | |||
if xP.Cmp(expectedX) != 0 || yP.Cmp(expectedY) != 0 { | |||
return errors.KeyInvalidError(fmt.Sprintf("ecc (%s): invalid point", c.Curve.Params().Name)) | |||
} | |||
return nil | |||
} | |||
func (c *genericCurve) ValidateECDSA(xP, yP *big.Int, secret []byte) error { | |||
return c.validate(xP, yP, secret) | |||
} | |||
func (c *genericCurve) ValidateECDH(point []byte, secret []byte) error { | |||
xP, yP := elliptic.Unmarshal(c.Curve, point) | |||
if xP == nil { | |||
return errors.KeyInvalidError(fmt.Sprintf("ecc (%s): invalid point", c.Curve.Params().Name)) | |||
} | |||
return c.validate(xP, yP, secret) | |||
} |
@@ -0,0 +1,105 @@ | |||
// Package ecc implements a generic interface for ECDH, ECDSA, and EdDSA. | |||
package ecc | |||
import ( | |||
"crypto/subtle" | |||
"io" | |||
"github.com/ProtonMail/go-crypto/openpgp/errors" | |||
x448lib "github.com/cloudflare/circl/dh/x448" | |||
) | |||
type x448 struct{} | |||
func NewX448() *x448 { | |||
return &x448{} | |||
} | |||
func (c *x448) GetCurveName() string { | |||
return "x448" | |||
} | |||
// 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 *x448) MarshalBytePoint(point []byte) []byte { | |||
return append([]byte{0x40}, point...) | |||
} | |||
// 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 { | |||
return nil | |||
} | |||
return point[1:] | |||
} | |||
// MarshalByteSecret encoded a scalar from native format to prefixed. | |||
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.6.1.2 | |||
func (c *x448) MarshalByteSecret(d []byte) []byte { | |||
return append([]byte{0x40}, d...) | |||
} | |||
// 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 { | |||
return nil | |||
} | |||
// Store without prefix | |||
return d[1:] | |||
} | |||
func (c *x448) generateKeyPairBytes(rand io.Reader) (sk, pk x448lib.Key, err error) { | |||
if _, err = rand.Read(sk[:]); err != nil { | |||
return | |||
} | |||
x448lib.KeyGen(&pk, &sk) | |||
return | |||
} | |||
func (c *x448) GenerateECDH(rand io.Reader) (point []byte, secret []byte, err error) { | |||
priv, pub, err := c.generateKeyPairBytes(rand) | |||
if err != nil { | |||
return | |||
} | |||
return pub[:], priv[:], nil | |||
} | |||
func (c *x448) Encaps(rand io.Reader, point []byte) (ephemeral, sharedSecret []byte, err error) { | |||
var pk, ss x448lib.Key | |||
seed, e, err := c.generateKeyPairBytes(rand) | |||
copy(pk[:], point) | |||
x448lib.Shared(&ss, &seed, &pk) | |||
return e[:], ss[:], nil | |||
} | |||
func (c *x448) Decaps(ephemeral, secret []byte) (sharedSecret []byte, err error) { | |||
var ss, sk, e x448lib.Key | |||
copy(sk[:], secret) | |||
copy(e[:], ephemeral) | |||
x448lib.Shared(&ss, &sk, &e) | |||
return ss[:], nil | |||
} | |||
func (c *x448) ValidateECDH(point []byte, secret []byte) error { | |||
var sk, pk, expectedPk x448lib.Key | |||
copy(pk[:], point) | |||
copy(sk[:], secret) | |||
x448lib.KeyGen(&expectedPk, &sk) | |||
if subtle.ConstantTimeCompare(expectedPk[:], pk[:]) == 0 { | |||
return errors.KeyInvalidError("ecc: invalid curve25519 public point") | |||
} | |||
return nil | |||
} |
@@ -0,0 +1,27 @@ | |||
// Copyright 2017 The Go Authors. All rights reserved. | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
// Package encoding implements openpgp packet field encodings as specified in | |||
// RFC 4880 and 6637. | |||
package encoding | |||
import "io" | |||
// Field is an encoded field of an openpgp packet. | |||
type Field interface { | |||
// Bytes returns the decoded data. | |||
Bytes() []byte | |||
// BitLength is the size in bits of the decoded data. | |||
BitLength() uint16 | |||
// EncodedBytes returns the encoded data. | |||
EncodedBytes() []byte | |||
// EncodedLength is the size in bytes of the encoded data. | |||
EncodedLength() uint16 | |||
// ReadFrom reads the next Field from r. | |||
ReadFrom(r io.Reader) (int64, error) | |||
} |
@@ -0,0 +1,91 @@ | |||
// Copyright 2017 The Go Authors. All rights reserved. | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
package encoding | |||
import ( | |||
"io" | |||
"math/big" | |||
"math/bits" | |||
) | |||
// An MPI is used to store the contents of a big integer, along with the bit | |||
// length that was specified in the original input. This allows the MPI to be | |||
// reserialized exactly. | |||
type MPI struct { | |||
bytes []byte | |||
bitLength uint16 | |||
} | |||
// NewMPI returns a MPI initialized with bytes. | |||
func NewMPI(bytes []byte) *MPI { | |||
for len(bytes) != 0 && bytes[0] == 0 { | |||
bytes = bytes[1:] | |||
} | |||
if len(bytes) == 0 { | |||
bitLength := uint16(0) | |||
return &MPI{bytes, bitLength} | |||
} | |||
bitLength := 8*uint16(len(bytes)-1) + uint16(bits.Len8(bytes[0])) | |||
return &MPI{bytes, bitLength} | |||
} | |||
// Bytes returns the decoded data. | |||
func (m *MPI) Bytes() []byte { | |||
return m.bytes | |||
} | |||
// BitLength is the size in bits of the decoded data. | |||
func (m *MPI) BitLength() uint16 { | |||
return m.bitLength | |||
} | |||
// EncodedBytes returns the encoded data. | |||
func (m *MPI) EncodedBytes() []byte { | |||
return append([]byte{byte(m.bitLength >> 8), byte(m.bitLength)}, m.bytes...) | |||
} | |||
// EncodedLength is the size in bytes of the encoded data. | |||
func (m *MPI) EncodedLength() uint16 { | |||
return uint16(2 + len(m.bytes)) | |||
} | |||
// ReadFrom reads into m the next MPI from r. | |||
func (m *MPI) ReadFrom(r io.Reader) (int64, error) { | |||
var buf [2]byte | |||
n, err := io.ReadFull(r, buf[0:]) | |||
if err != nil { | |||
if err == io.EOF { | |||
err = io.ErrUnexpectedEOF | |||
} | |||
return int64(n), err | |||
} | |||
m.bitLength = uint16(buf[0])<<8 | uint16(buf[1]) | |||
m.bytes = make([]byte, (int(m.bitLength)+7)/8) | |||
nn, err := io.ReadFull(r, m.bytes) | |||
if err == io.EOF { | |||
err = io.ErrUnexpectedEOF | |||
} | |||
// remove leading zero bytes from malformed GnuPG encoded MPIs: | |||
// https://bugs.gnupg.org/gnupg/issue1853 | |||
// for _, b := range m.bytes { | |||
// if b != 0 { | |||
// break | |||
// } | |||
// m.bytes = m.bytes[1:] | |||
// m.bitLength -= 8 | |||
// } | |||
return int64(n) + int64(nn), err | |||
} | |||
// SetBig initializes m with the bits from n. | |||
func (m *MPI) SetBig(n *big.Int) *MPI { | |||
m.bytes = n.Bytes() | |||
m.bitLength = uint16(n.BitLen()) | |||
return m | |||
} |
@@ -0,0 +1,88 @@ | |||
// Copyright 2017 The Go Authors. All rights reserved. | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
package encoding | |||
import ( | |||
"io" | |||
"github.com/ProtonMail/go-crypto/openpgp/errors" | |||
) | |||
// OID is used to store a variable-length field with a one-octet size | |||
// prefix. See https://tools.ietf.org/html/rfc6637#section-9. | |||
type OID struct { | |||
bytes []byte | |||
} | |||
const ( | |||
// maxOID is the maximum number of bytes in a OID. | |||
maxOID = 254 | |||
// reservedOIDLength1 and reservedOIDLength2 are OID lengths that the RFC | |||
// specifies are reserved. | |||
reservedOIDLength1 = 0 | |||
reservedOIDLength2 = 0xff | |||
) | |||
// NewOID returns a OID initialized with bytes. | |||
func NewOID(bytes []byte) *OID { | |||
switch len(bytes) { | |||
case reservedOIDLength1, reservedOIDLength2: | |||
panic("encoding: NewOID argument length is reserved") | |||
default: | |||
if len(bytes) > maxOID { | |||
panic("encoding: NewOID argument too large") | |||
} | |||
} | |||
return &OID{ | |||
bytes: bytes, | |||
} | |||
} | |||
// Bytes returns the decoded data. | |||
func (o *OID) Bytes() []byte { | |||
return o.bytes | |||
} | |||
// BitLength is the size in bits of the decoded data. | |||
func (o *OID) BitLength() uint16 { | |||
return uint16(len(o.bytes) * 8) | |||
} | |||
// EncodedBytes returns the encoded data. | |||
func (o *OID) EncodedBytes() []byte { | |||
return append([]byte{byte(len(o.bytes))}, o.bytes...) | |||
} | |||
// EncodedLength is the size in bytes of the encoded data. | |||
func (o *OID) EncodedLength() uint16 { | |||
return uint16(1 + len(o.bytes)) | |||
} | |||
// ReadFrom reads into b the next OID from r. | |||
func (o *OID) ReadFrom(r io.Reader) (int64, error) { | |||
var buf [1]byte | |||
n, err := io.ReadFull(r, buf[:]) | |||
if err != nil { | |||
if err == io.EOF { | |||
err = io.ErrUnexpectedEOF | |||
} | |||
return int64(n), err | |||
} | |||
switch buf[0] { | |||
case reservedOIDLength1, reservedOIDLength2: | |||
return int64(n), errors.UnsupportedError("reserved for future extensions") | |||
} | |||
o.bytes = make([]byte, buf[0]) | |||
nn, err := io.ReadFull(r, o.bytes) | |||
if err == io.EOF { | |||
err = io.ErrUnexpectedEOF | |||
} | |||
return int64(n) + int64(nn), err | |||
} |
@@ -0,0 +1,389 @@ | |||
// Copyright 2011 The Go Authors. All rights reserved. | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
package openpgp | |||
import ( | |||
"crypto" | |||
"crypto/rand" | |||
"crypto/rsa" | |||
goerrors "errors" | |||
"io" | |||
"math/big" | |||
"time" | |||
"github.com/ProtonMail/go-crypto/openpgp/ecdh" | |||
"github.com/ProtonMail/go-crypto/openpgp/ecdsa" | |||
"github.com/ProtonMail/go-crypto/openpgp/eddsa" | |||
"github.com/ProtonMail/go-crypto/openpgp/errors" | |||
"github.com/ProtonMail/go-crypto/openpgp/internal/algorithm" | |||
"github.com/ProtonMail/go-crypto/openpgp/internal/ecc" | |||
"github.com/ProtonMail/go-crypto/openpgp/packet" | |||
) | |||
// NewEntity returns an Entity that contains a fresh RSA/RSA keypair with a | |||
// single identity composed of the given full name, comment and email, any of | |||
// which may be empty but must not contain any of "()<>\x00". | |||
// If config is nil, sensible defaults will be used. | |||
func NewEntity(name, comment, email string, config *packet.Config) (*Entity, error) { | |||
creationTime := config.Now() | |||
keyLifetimeSecs := config.KeyLifetime() | |||
// Generate a primary signing key | |||
primaryPrivRaw, err := newSigner(config) | |||
if err != nil { | |||
return nil, err | |||
} | |||
primary := packet.NewSignerPrivateKey(creationTime, primaryPrivRaw) | |||
if config != nil && config.V5Keys { | |||
primary.UpgradeToV5() | |||
} | |||
e := &Entity{ | |||
PrimaryKey: &primary.PublicKey, | |||
PrivateKey: primary, | |||
Identities: make(map[string]*Identity), | |||
Subkeys: []Subkey{}, | |||
} | |||
err = e.addUserId(name, comment, email, config, creationTime, keyLifetimeSecs) | |||
if err != nil { | |||
return nil, err | |||
} | |||
// NOTE: No key expiry here, but we will not return this subkey in EncryptionKey() | |||
// if the primary/master key has expired. | |||
err = e.addEncryptionSubkey(config, creationTime, 0) | |||
if err != nil { | |||
return nil, err | |||
} | |||
return e, nil | |||
} | |||
func (t *Entity) AddUserId(name, comment, email string, config *packet.Config) error { | |||
creationTime := config.Now() | |||
keyLifetimeSecs := config.KeyLifetime() | |||
return t.addUserId(name, comment, email, config, creationTime, keyLifetimeSecs) | |||
} | |||
func (t *Entity) addUserId(name, comment, email string, config *packet.Config, creationTime time.Time, keyLifetimeSecs uint32) error { | |||
uid := packet.NewUserId(name, comment, email) | |||
if uid == nil { | |||
return errors.InvalidArgumentError("user id field contained invalid characters") | |||
} | |||
if _, ok := t.Identities[uid.Id]; ok { | |||
return errors.InvalidArgumentError("user id exist") | |||
} | |||
primary := t.PrivateKey | |||
isPrimaryId := len(t.Identities) == 0 | |||
selfSignature := createSignaturePacket(&primary.PublicKey, packet.SigTypePositiveCert, config) | |||
selfSignature.CreationTime = creationTime | |||
selfSignature.KeyLifetimeSecs = &keyLifetimeSecs | |||
selfSignature.IsPrimaryId = &isPrimaryId | |||
selfSignature.FlagsValid = true | |||
selfSignature.FlagSign = true | |||
selfSignature.FlagCertify = true | |||
selfSignature.SEIPDv1 = true // true by default, see 5.8 vs. 5.14 | |||
selfSignature.SEIPDv2 = config.AEAD() != nil | |||
// Set the PreferredHash for the SelfSignature from the packet.Config. | |||
// If it is not the must-implement algorithm from rfc4880bis, append that. | |||
hash, ok := algorithm.HashToHashId(config.Hash()) | |||
if !ok { | |||
return errors.UnsupportedError("unsupported preferred hash function") | |||
} | |||
selfSignature.PreferredHash = []uint8{hash} | |||
if config.Hash() != crypto.SHA256 { | |||
selfSignature.PreferredHash = append(selfSignature.PreferredHash, hashToHashId(crypto.SHA256)) | |||
} | |||
// Likewise for DefaultCipher. | |||
selfSignature.PreferredSymmetric = []uint8{uint8(config.Cipher())} | |||
if config.Cipher() != packet.CipherAES128 { | |||
selfSignature.PreferredSymmetric = append(selfSignature.PreferredSymmetric, uint8(packet.CipherAES128)) | |||
} | |||
// We set CompressionNone as the preferred compression algorithm because | |||
// of compression side channel attacks, then append the configured | |||
// DefaultCompressionAlgo if any is set (to signal support for cases | |||
// where the application knows that using compression is safe). | |||
selfSignature.PreferredCompression = []uint8{uint8(packet.CompressionNone)} | |||
if config.Compression() != packet.CompressionNone { | |||
selfSignature.PreferredCompression = append(selfSignature.PreferredCompression, uint8(config.Compression())) | |||
} | |||
// And for DefaultMode. | |||
modes := []uint8{uint8(config.AEAD().Mode())} | |||
if config.AEAD().Mode() != packet.AEADModeOCB { | |||
modes = append(modes, uint8(packet.AEADModeOCB)) | |||
} | |||
// For preferred (AES256, GCM), we'll generate (AES256, GCM), (AES256, OCB), (AES128, GCM), (AES128, OCB) | |||
for _, cipher := range selfSignature.PreferredSymmetric { | |||
for _, mode := range modes { | |||
selfSignature.PreferredCipherSuites = append(selfSignature.PreferredCipherSuites, [2]uint8{cipher, mode}) | |||
} | |||
} | |||
// User ID binding signature | |||
err := selfSignature.SignUserId(uid.Id, &primary.PublicKey, primary, config) | |||
if err != nil { | |||
return err | |||
} | |||
t.Identities[uid.Id] = &Identity{ | |||
Name: uid.Id, | |||
UserId: uid, | |||
SelfSignature: selfSignature, | |||
Signatures: []*packet.Signature{selfSignature}, | |||
} | |||
return nil | |||
} | |||
// AddSigningSubkey adds a signing keypair as a subkey to the Entity. | |||
// If config is nil, sensible defaults will be used. | |||
func (e *Entity) AddSigningSubkey(config *packet.Config) error { | |||
creationTime := config.Now() | |||
keyLifetimeSecs := config.KeyLifetime() | |||
subPrivRaw, err := newSigner(config) | |||
if err != nil { | |||
return err | |||
} | |||
sub := packet.NewSignerPrivateKey(creationTime, subPrivRaw) | |||
sub.IsSubkey = true | |||
if config != nil && config.V5Keys { | |||
sub.UpgradeToV5() | |||
} | |||
subkey := Subkey{ | |||
PublicKey: &sub.PublicKey, | |||
PrivateKey: sub, | |||
} | |||
subkey.Sig = createSignaturePacket(e.PrimaryKey, packet.SigTypeSubkeyBinding, config) | |||
subkey.Sig.CreationTime = creationTime | |||
subkey.Sig.KeyLifetimeSecs = &keyLifetimeSecs | |||
subkey.Sig.FlagsValid = true | |||
subkey.Sig.FlagSign = true | |||
subkey.Sig.EmbeddedSignature = createSignaturePacket(subkey.PublicKey, packet.SigTypePrimaryKeyBinding, config) | |||
subkey.Sig.EmbeddedSignature.CreationTime = creationTime | |||
err = subkey.Sig.EmbeddedSignature.CrossSignKey(subkey.PublicKey, e.PrimaryKey, subkey.PrivateKey, config) | |||
if err != nil { | |||
return err | |||
} | |||
err = subkey.Sig.SignKey(subkey.PublicKey, e.PrivateKey, config) | |||
if err != nil { | |||
return err | |||
} | |||
e.Subkeys = append(e.Subkeys, subkey) | |||
return nil | |||
} | |||
// AddEncryptionSubkey adds an encryption keypair as a subkey to the Entity. | |||
// If config is nil, sensible defaults will be used. | |||
func (e *Entity) AddEncryptionSubkey(config *packet.Config) error { | |||
creationTime := config.Now() | |||
keyLifetimeSecs := config.KeyLifetime() | |||
return e.addEncryptionSubkey(config, creationTime, keyLifetimeSecs) | |||
} | |||
func (e *Entity) addEncryptionSubkey(config *packet.Config, creationTime time.Time, keyLifetimeSecs uint32) error { | |||
subPrivRaw, err := newDecrypter(config) | |||
if err != nil { | |||
return err | |||
} | |||
sub := packet.NewDecrypterPrivateKey(creationTime, subPrivRaw) | |||
sub.IsSubkey = true | |||
if config != nil && config.V5Keys { | |||
sub.UpgradeToV5() | |||
} | |||
subkey := Subkey{ | |||
PublicKey: &sub.PublicKey, | |||
PrivateKey: sub, | |||
} | |||
subkey.Sig = createSignaturePacket(e.PrimaryKey, packet.SigTypeSubkeyBinding, config) | |||
subkey.Sig.CreationTime = creationTime | |||
subkey.Sig.KeyLifetimeSecs = &keyLifetimeSecs | |||
subkey.Sig.FlagsValid = true | |||
subkey.Sig.FlagEncryptStorage = true | |||
subkey.Sig.FlagEncryptCommunications = true | |||
err = subkey.Sig.SignKey(subkey.PublicKey, e.PrivateKey, config) | |||
if err != nil { | |||
return err | |||
} | |||
e.Subkeys = append(e.Subkeys, subkey) | |||
return nil | |||
} | |||
// Generates a signing key | |||
func newSigner(config *packet.Config) (signer interface{}, err error) { | |||
switch config.PublicKeyAlgorithm() { | |||
case packet.PubKeyAlgoRSA: | |||
bits := config.RSAModulusBits() | |||
if bits < 1024 { | |||
return nil, errors.InvalidArgumentError("bits must be >= 1024") | |||
} | |||
if config != nil && len(config.RSAPrimes) >= 2 { | |||
primes := config.RSAPrimes[0:2] | |||
config.RSAPrimes = config.RSAPrimes[2:] | |||
return generateRSAKeyWithPrimes(config.Random(), 2, bits, primes) | |||
} | |||
return rsa.GenerateKey(config.Random(), bits) | |||
case packet.PubKeyAlgoEdDSA: | |||
curve := ecc.FindEdDSAByGenName(string(config.CurveName())) | |||
if curve == nil { | |||
return nil, errors.InvalidArgumentError("unsupported curve") | |||
} | |||
priv, err := eddsa.GenerateKey(config.Random(), curve) | |||
if err != nil { | |||
return nil, err | |||
} | |||
return priv, nil | |||
case packet.PubKeyAlgoECDSA: | |||
curve := ecc.FindECDSAByGenName(string(config.CurveName())) | |||
if curve == nil { | |||
return nil, errors.InvalidArgumentError("unsupported curve") | |||
} | |||
priv, err := ecdsa.GenerateKey(config.Random(), curve) | |||
if err != nil { | |||
return nil, err | |||
} | |||
return priv, nil | |||
default: | |||
return nil, errors.InvalidArgumentError("unsupported public key algorithm") | |||
} | |||
} | |||
// Generates an encryption/decryption key | |||
func newDecrypter(config *packet.Config) (decrypter interface{}, err error) { | |||
switch config.PublicKeyAlgorithm() { | |||
case packet.PubKeyAlgoRSA: | |||
bits := config.RSAModulusBits() | |||
if bits < 1024 { | |||
return nil, errors.InvalidArgumentError("bits must be >= 1024") | |||
} | |||
if config != nil && len(config.RSAPrimes) >= 2 { | |||
primes := config.RSAPrimes[0:2] | |||
config.RSAPrimes = config.RSAPrimes[2:] | |||
return generateRSAKeyWithPrimes(config.Random(), 2, bits, primes) | |||
} | |||
return rsa.GenerateKey(config.Random(), bits) | |||
case packet.PubKeyAlgoEdDSA, packet.PubKeyAlgoECDSA: | |||
fallthrough // When passing EdDSA or ECDSA, we generate an ECDH subkey | |||
case packet.PubKeyAlgoECDH: | |||
var kdf = ecdh.KDF{ | |||
Hash: algorithm.SHA512, | |||
Cipher: algorithm.AES256, | |||
} | |||
curve := ecc.FindECDHByGenName(string(config.CurveName())) | |||
if curve == nil { | |||
return nil, errors.InvalidArgumentError("unsupported curve") | |||
} | |||
return ecdh.GenerateKey(config.Random(), curve, kdf) | |||
default: | |||
return nil, errors.InvalidArgumentError("unsupported public key algorithm") | |||
} | |||
} | |||
var bigOne = big.NewInt(1) | |||
// generateRSAKeyWithPrimes generates a multi-prime RSA keypair of the | |||
// given bit size, using the given random source and prepopulated primes. | |||
func generateRSAKeyWithPrimes(random io.Reader, nprimes int, bits int, prepopulatedPrimes []*big.Int) (*rsa.PrivateKey, error) { | |||
priv := new(rsa.PrivateKey) | |||
priv.E = 65537 | |||
if nprimes < 2 { | |||
return nil, goerrors.New("generateRSAKeyWithPrimes: nprimes must be >= 2") | |||
} | |||
if bits < 1024 { | |||
return nil, goerrors.New("generateRSAKeyWithPrimes: bits must be >= 1024") | |||
} | |||
primes := make([]*big.Int, nprimes) | |||
NextSetOfPrimes: | |||
for { | |||
todo := bits | |||
// crypto/rand should set the top two bits in each prime. | |||
// Thus each prime has the form | |||
// p_i = 2^bitlen(p_i) × 0.11... (in base 2). | |||
// And the product is: | |||
// P = 2^todo × α | |||
// where α is the product of nprimes numbers of the form 0.11... | |||
// | |||
// If α < 1/2 (which can happen for nprimes > 2), we need to | |||
// shift todo to compensate for lost bits: the mean value of 0.11... | |||
// is 7/8, so todo + shift - nprimes * log2(7/8) ~= bits - 1/2 | |||
// will give good results. | |||
if nprimes >= 7 { | |||
todo += (nprimes - 2) / 5 | |||
} | |||
for i := 0; i < nprimes; i++ { | |||
var err error | |||
if len(prepopulatedPrimes) == 0 { | |||
primes[i], err = rand.Prime(random, todo/(nprimes-i)) | |||
if err != nil { | |||
return nil, err | |||
} | |||
} else { | |||
primes[i] = prepopulatedPrimes[0] | |||
prepopulatedPrimes = prepopulatedPrimes[1:] | |||
} | |||
todo -= primes[i].BitLen() | |||
} | |||
// Make sure that primes is pairwise unequal. | |||
for i, prime := range primes { | |||
for j := 0; j < i; j++ { | |||
if prime.Cmp(primes[j]) == 0 { | |||
continue NextSetOfPrimes | |||
} | |||
} | |||
} | |||
n := new(big.Int).Set(bigOne) | |||
totient := new(big.Int).Set(bigOne) | |||
pminus1 := new(big.Int) | |||
for _, prime := range primes { | |||
n.Mul(n, prime) | |||
pminus1.Sub(prime, bigOne) | |||
totient.Mul(totient, pminus1) | |||
} | |||
if n.BitLen() != bits { | |||
// This should never happen for nprimes == 2 because | |||
// crypto/rand should set the top two bits in each prime. | |||
// For nprimes > 2 we hope it does not happen often. | |||
continue NextSetOfPrimes | |||
} | |||
priv.D = new(big.Int) | |||
e := big.NewInt(int64(priv.E)) | |||
ok := priv.D.ModInverse(e, totient) | |||
if ok != nil { | |||
priv.Primes = primes | |||
priv.N = n | |||
break | |||
} | |||
} | |||
priv.Precompute() | |||
return priv, nil | |||
} |
@@ -0,0 +1,842 @@ | |||
// Copyright 2011 The Go Authors. All rights reserved. | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
package openpgp | |||
import ( | |||
goerrors "errors" | |||
"io" | |||
"time" | |||
"github.com/ProtonMail/go-crypto/openpgp/armor" | |||
"github.com/ProtonMail/go-crypto/openpgp/errors" | |||
"github.com/ProtonMail/go-crypto/openpgp/packet" | |||
) | |||
// PublicKeyType is the armor type for a PGP public key. | |||
var PublicKeyType = "PGP PUBLIC KEY BLOCK" | |||
// PrivateKeyType is the armor type for a PGP private key. | |||
var PrivateKeyType = "PGP PRIVATE KEY BLOCK" | |||
// An Entity represents the components of an OpenPGP key: a primary public key | |||
// (which must be a signing key), one or more identities claimed by that key, | |||
// and zero or more subkeys, which may be encryption keys. | |||
type Entity struct { | |||
PrimaryKey *packet.PublicKey | |||
PrivateKey *packet.PrivateKey | |||
Identities map[string]*Identity // indexed by Identity.Name | |||
Revocations []*packet.Signature | |||
Subkeys []Subkey | |||
} | |||
// An Identity represents an identity claimed by an Entity and zero or more | |||
// assertions by other entities about that claim. | |||
type Identity struct { | |||
Name string // by convention, has the form "Full Name (comment) <email@example.com>" | |||
UserId *packet.UserId | |||
SelfSignature *packet.Signature | |||
Revocations []*packet.Signature | |||
Signatures []*packet.Signature // all (potentially unverified) self-signatures, revocations, and third-party signatures | |||
} | |||
// A Subkey is an additional public key in an Entity. Subkeys can be used for | |||
// encryption. | |||
type Subkey struct { | |||
PublicKey *packet.PublicKey | |||
PrivateKey *packet.PrivateKey | |||
Sig *packet.Signature | |||
Revocations []*packet.Signature | |||
} | |||
// A Key identifies a specific public key in an Entity. This is either the | |||
// Entity's primary key or a subkey. | |||
type Key struct { | |||
Entity *Entity | |||
PublicKey *packet.PublicKey | |||
PrivateKey *packet.PrivateKey | |||
SelfSignature *packet.Signature | |||
Revocations []*packet.Signature | |||
} | |||
// A KeyRing provides access to public and private keys. | |||
type KeyRing interface { | |||
// KeysById returns the set of keys that have the given key id. | |||
KeysById(id uint64) []Key | |||
// KeysByIdAndUsage returns the set of keys with the given id | |||
// that also meet the key usage given by requiredUsage. | |||
// The requiredUsage is expressed as the bitwise-OR of | |||
// packet.KeyFlag* values. | |||
KeysByIdUsage(id uint64, requiredUsage byte) []Key | |||
// DecryptionKeys returns all private keys that are valid for | |||
// decryption. | |||
DecryptionKeys() []Key | |||
} | |||
// PrimaryIdentity returns an Identity, preferring non-revoked identities, | |||
// identities marked as primary, or the latest-created identity, in that order. | |||
func (e *Entity) PrimaryIdentity() *Identity { | |||
var primaryIdentity *Identity | |||
for _, ident := range e.Identities { | |||
if shouldPreferIdentity(primaryIdentity, ident) { | |||
primaryIdentity = ident | |||
} | |||
} | |||
return primaryIdentity | |||
} | |||
func shouldPreferIdentity(existingId, potentialNewId *Identity) bool { | |||
if existingId == nil { | |||
return true | |||
} | |||
if len(existingId.Revocations) > len(potentialNewId.Revocations) { | |||
return true | |||
} | |||
if len(existingId.Revocations) < len(potentialNewId.Revocations) { | |||
return false | |||
} | |||
if existingId.SelfSignature == nil { | |||
return true | |||
} | |||
if existingId.SelfSignature.IsPrimaryId != nil && *existingId.SelfSignature.IsPrimaryId && | |||
!(potentialNewId.SelfSignature.IsPrimaryId != nil && *potentialNewId.SelfSignature.IsPrimaryId) { | |||
return false | |||
} | |||
if !(existingId.SelfSignature.IsPrimaryId != nil && *existingId.SelfSignature.IsPrimaryId) && | |||
potentialNewId.SelfSignature.IsPrimaryId != nil && *potentialNewId.SelfSignature.IsPrimaryId { | |||
return true | |||
} | |||
return potentialNewId.SelfSignature.CreationTime.After(existingId.SelfSignature.CreationTime) | |||
} | |||
// EncryptionKey returns the best candidate Key for encrypting a message to the | |||
// given Entity. | |||
func (e *Entity) EncryptionKey(now time.Time) (Key, bool) { | |||
// Fail to find any encryption key if the... | |||
i := e.PrimaryIdentity() | |||
if e.PrimaryKey.KeyExpired(i.SelfSignature, now) || // primary key has expired | |||
i.SelfSignature == nil || // user ID has no self-signature | |||
i.SelfSignature.SigExpired(now) || // user ID self-signature has expired | |||
e.Revoked(now) || // primary key has been revoked | |||
i.Revoked(now) { // user ID has been revoked | |||
return Key{}, false | |||
} | |||
// Iterate the keys to find the newest, unexpired one | |||
candidateSubkey := -1 | |||
var maxTime time.Time | |||
for i, subkey := range e.Subkeys { | |||
if subkey.Sig.FlagsValid && | |||
subkey.Sig.FlagEncryptCommunications && | |||
subkey.PublicKey.PubKeyAlgo.CanEncrypt() && | |||
!subkey.PublicKey.KeyExpired(subkey.Sig, now) && | |||
!subkey.Sig.SigExpired(now) && | |||
!subkey.Revoked(now) && | |||
(maxTime.IsZero() || subkey.Sig.CreationTime.After(maxTime)) { | |||
candidateSubkey = i | |||
maxTime = subkey.Sig.CreationTime | |||
} | |||
} | |||
if candidateSubkey != -1 { | |||
subkey := e.Subkeys[candidateSubkey] | |||
return Key{e, subkey.PublicKey, subkey.PrivateKey, subkey.Sig, subkey.Revocations}, true | |||
} | |||
// 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 | |||
} | |||
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) { | |||
return e.CertificationKeyById(now, 0) | |||
} | |||
// CertificationKeyById return the Key for key certification with this | |||
// Entity and keyID. | |||
func (e *Entity) CertificationKeyById(now time.Time, id uint64) (Key, bool) { | |||
return e.signingKeyByIdUsage(now, id, packet.KeyFlagCertify) | |||
} | |||
// SigningKey return the best candidate Key for signing a message with this | |||
// Entity. | |||
func (e *Entity) SigningKey(now time.Time) (Key, bool) { | |||
return e.SigningKeyById(now, 0) | |||
} | |||
// SigningKeyById return the Key for signing a message with this | |||
// Entity and keyID. | |||
func (e *Entity) SigningKeyById(now time.Time, id uint64) (Key, bool) { | |||
return e.signingKeyByIdUsage(now, id, packet.KeyFlagSign) | |||
} | |||
func (e *Entity) signingKeyByIdUsage(now time.Time, id uint64, flags int) (Key, bool) { | |||
// Fail to find any signing key if the... | |||
i := e.PrimaryIdentity() | |||
if e.PrimaryKey.KeyExpired(i.SelfSignature, now) || // primary key has expired | |||
i.SelfSignature == nil || // user ID has no self-signature | |||
i.SelfSignature.SigExpired(now) || // user ID self-signature has expired | |||
e.Revoked(now) || // primary key has been revoked | |||
i.Revoked(now) { // user ID has been revoked | |||
return Key{}, false | |||
} | |||
// Iterate the keys to find the newest, unexpired one | |||
candidateSubkey := -1 | |||
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) && | |||
subkey.PublicKey.PubKeyAlgo.CanSign() && | |||
!subkey.PublicKey.KeyExpired(subkey.Sig, now) && | |||
!subkey.Sig.SigExpired(now) && | |||
!subkey.Revoked(now) && | |||
(maxTime.IsZero() || subkey.Sig.CreationTime.After(maxTime)) && | |||
(id == 0 || subkey.PublicKey.KeyId == id) { | |||
candidateSubkey = idx | |||
maxTime = subkey.Sig.CreationTime | |||
} | |||
} | |||
if candidateSubkey != -1 { | |||
subkey := e.Subkeys[candidateSubkey] | |||
return Key{e, subkey.PublicKey, subkey.PrivateKey, subkey.Sig, subkey.Revocations}, true | |||
} | |||
// 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 | |||
} | |||
// No keys with a valid Signing Flag or no keys matched the id passed in | |||
return Key{}, false | |||
} | |||
func revoked(revocations []*packet.Signature, now time.Time) bool { | |||
for _, revocation := range revocations { | |||
if revocation.RevocationReason != nil && *revocation.RevocationReason == packet.KeyCompromised { | |||
// If the key is compromised, the key is considered revoked even before the revocation date. | |||
return true | |||
} | |||
if !revocation.SigExpired(now) { | |||
return true | |||
} | |||
} | |||
return false | |||
} | |||
// Revoked returns whether the entity has any direct key revocation signatures. | |||
// Note that third-party revocation signatures are not supported. | |||
// Note also that Identity and Subkey revocation should be checked separately. | |||
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 { | |||
return revoked(i.Revocations, now) | |||
} | |||
// Revoked returns whether the subkey has been revoked by a self-signature. | |||
// Note that third-party revocation signatures are not supported. | |||
func (s *Subkey) Revoked(now time.Time) bool { | |||
return revoked(s.Revocations, now) | |||
} | |||
// Revoked returns whether the key or subkey has been revoked by a self-signature. | |||
// Note that third-party revocation signatures are not supported. | |||
// Note also that Identity revocation should be checked separately. | |||
// Normally, it's not necessary to call this function, except on keys returned by | |||
// KeysById or KeysByIdUsage. | |||
func (key *Key) Revoked(now time.Time) bool { | |||
return revoked(key.Revocations, now) | |||
} | |||
// An EntityList contains one or more Entities. | |||
type EntityList []*Entity | |||
// KeysById returns the set of keys that have the given key id. | |||
func (el EntityList) KeysById(id uint64) (keys []Key) { | |||
for _, e := range el { | |||
if e.PrimaryKey.KeyId == id { | |||
ident := e.PrimaryIdentity() | |||
selfSig := ident.SelfSignature | |||
keys = append(keys, Key{e, e.PrimaryKey, e.PrivateKey, selfSig, e.Revocations}) | |||
} | |||
for _, subKey := range e.Subkeys { | |||
if subKey.PublicKey.KeyId == id { | |||
keys = append(keys, Key{e, subKey.PublicKey, subKey.PrivateKey, subKey.Sig, subKey.Revocations}) | |||
} | |||
} | |||
} | |||
return | |||
} | |||
// KeysByIdAndUsage returns the set of keys with the given id that also meet | |||
// the key usage given by requiredUsage. The requiredUsage is expressed as | |||
// the bitwise-OR of packet.KeyFlag* values. | |||
func (el EntityList) KeysByIdUsage(id uint64, requiredUsage byte) (keys []Key) { | |||
for _, key := range el.KeysById(id) { | |||
if requiredUsage != 0 { | |||
if key.SelfSignature == nil || !key.SelfSignature.FlagsValid { | |||
continue | |||
} | |||
var usage byte | |||
if key.SelfSignature.FlagCertify { | |||
usage |= packet.KeyFlagCertify | |||
} | |||
if key.SelfSignature.FlagSign { | |||
usage |= packet.KeyFlagSign | |||
} | |||
if key.SelfSignature.FlagEncryptCommunications { | |||
usage |= packet.KeyFlagEncryptCommunications | |||
} | |||
if key.SelfSignature.FlagEncryptStorage { | |||
usage |= packet.KeyFlagEncryptStorage | |||
} | |||
if usage&requiredUsage != requiredUsage { | |||
continue | |||
} | |||
} | |||
keys = append(keys, key) | |||
} | |||
return | |||
} | |||
// DecryptionKeys returns all private keys that are valid for decryption. | |||
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) { | |||
keys = append(keys, Key{e, subKey.PublicKey, subKey.PrivateKey, subKey.Sig, subKey.Revocations}) | |||
} | |||
} | |||
} | |||
return | |||
} | |||
// ReadArmoredKeyRing reads one or more public/private keys from an armor keyring file. | |||
func ReadArmoredKeyRing(r io.Reader) (EntityList, error) { | |||
block, err := armor.Decode(r) | |||
if err == io.EOF { | |||
return nil, errors.InvalidArgumentError("no armored data found") | |||
} | |||
if err != nil { | |||
return nil, err | |||
} | |||
if block.Type != PublicKeyType && block.Type != PrivateKeyType { | |||
return nil, errors.InvalidArgumentError("expected public or private key block, got: " + block.Type) | |||
} | |||
return ReadKeyRing(block.Body) | |||
} | |||
// ReadKeyRing reads one or more public/private keys. Unsupported keys are | |||
// ignored as long as at least a single valid key is found. | |||
func ReadKeyRing(r io.Reader) (el EntityList, err error) { | |||
packets := packet.NewReader(r) | |||
var lastUnsupportedError error | |||
for { | |||
var e *Entity | |||
e, err = ReadEntity(packets) | |||
if err != nil { | |||
// TODO: warn about skipped unsupported/unreadable keys | |||
if _, ok := err.(errors.UnsupportedError); ok { | |||
lastUnsupportedError = err | |||
err = readToNextPublicKey(packets) | |||
} else if _, ok := err.(errors.StructuralError); ok { | |||
// Skip unreadable, badly-formatted keys | |||
lastUnsupportedError = err | |||
err = readToNextPublicKey(packets) | |||
} | |||
if err == io.EOF { | |||
err = nil | |||
break | |||
} | |||
if err != nil { | |||
el = nil | |||
break | |||
} | |||
} else { | |||
el = append(el, e) | |||
} | |||
} | |||
if len(el) == 0 && err == nil { | |||
err = lastUnsupportedError | |||
} | |||
return | |||
} | |||
// readToNextPublicKey reads packets until the start of the entity and leaves | |||
// the first packet of the new entity in the Reader. | |||
func readToNextPublicKey(packets *packet.Reader) (err error) { | |||
var p packet.Packet | |||
for { | |||
p, err = packets.Next() | |||
if err == io.EOF { | |||
return | |||
} else if err != nil { | |||
if _, ok := err.(errors.UnsupportedError); ok { | |||
err = nil | |||
continue | |||
} | |||
return | |||
} | |||
if pk, ok := p.(*packet.PublicKey); ok && !pk.IsSubkey { | |||
packets.Unread(p) | |||
return | |||
} | |||
} | |||
} | |||
// ReadEntity reads an entity (public key, identities, subkeys etc) from the | |||
// given Reader. | |||
func ReadEntity(packets *packet.Reader) (*Entity, error) { | |||
e := new(Entity) | |||
e.Identities = make(map[string]*Identity) | |||
p, err := packets.Next() | |||
if err != nil { | |||
return nil, err | |||
} | |||
var ok bool | |||
if e.PrimaryKey, ok = p.(*packet.PublicKey); !ok { | |||
if e.PrivateKey, ok = p.(*packet.PrivateKey); !ok { | |||
packets.Unread(p) | |||
return nil, errors.StructuralError("first packet was not a public/private key") | |||
} | |||
e.PrimaryKey = &e.PrivateKey.PublicKey | |||
} | |||
if !e.PrimaryKey.PubKeyAlgo.CanSign() { | |||
return nil, errors.StructuralError("primary key cannot be used for signatures") | |||
} | |||
var revocations []*packet.Signature | |||
EachPacket: | |||
for { | |||
p, err := packets.Next() | |||
if err == io.EOF { | |||
break | |||
} else if err != nil { | |||
return nil, err | |||
} | |||
switch pkt := p.(type) { | |||
case *packet.UserId: | |||
if err := addUserID(e, packets, pkt); err != nil { | |||
return nil, err | |||
} | |||
case *packet.Signature: | |||
if pkt.SigType == packet.SigTypeKeyRevocation { | |||
revocations = append(revocations, pkt) | |||
} else if pkt.SigType == packet.SigTypeDirectSignature { | |||
// TODO: RFC4880 5.2.1 permits signatures | |||
// directly on keys (eg. to bind additional | |||
// revocation keys). | |||
} | |||
// Else, ignoring the signature as it does not follow anything | |||
// we would know to attach it to. | |||
case *packet.PrivateKey: | |||
if pkt.IsSubkey == false { | |||
packets.Unread(p) | |||
break EachPacket | |||
} | |||
err = addSubkey(e, packets, &pkt.PublicKey, pkt) | |||
if err != nil { | |||
return nil, err | |||
} | |||
case *packet.PublicKey: | |||
if pkt.IsSubkey == false { | |||
packets.Unread(p) | |||
break EachPacket | |||
} | |||
err = addSubkey(e, packets, pkt, nil) | |||
if err != nil { | |||
return nil, err | |||
} | |||
default: | |||
// we ignore unknown packets | |||
} | |||
} | |||
if len(e.Identities) == 0 { | |||
return nil, errors.StructuralError("entity without any identities") | |||
} | |||
for _, revocation := range revocations { | |||
err = e.PrimaryKey.VerifyRevocationSignature(revocation) | |||
if err == nil { | |||
e.Revocations = append(e.Revocations, revocation) | |||
} else { | |||
// TODO: RFC 4880 5.2.3.15 defines revocation keys. | |||
return nil, errors.StructuralError("revocation signature signed by alternate key") | |||
} | |||
} | |||
return e, nil | |||
} | |||
func addUserID(e *Entity, packets *packet.Reader, pkt *packet.UserId) error { | |||
// Make a new Identity object, that we might wind up throwing away. | |||
// We'll only add it if we get a valid self-signature over this | |||
// userID. | |||
identity := new(Identity) | |||
identity.Name = pkt.Id | |||
identity.UserId = pkt | |||
for { | |||
p, err := packets.Next() | |||
if err == io.EOF { | |||
break | |||
} else if err != nil { | |||
return err | |||
} | |||
sig, ok := p.(*packet.Signature) | |||
if !ok { | |||
packets.Unread(p) | |||
break | |||
} | |||
if sig.SigType != packet.SigTypeGenericCert && | |||
sig.SigType != packet.SigTypePersonaCert && | |||
sig.SigType != packet.SigTypeCasualCert && | |||
sig.SigType != packet.SigTypePositiveCert && | |||
sig.SigType != packet.SigTypeCertificationRevocation { | |||
return errors.StructuralError("user ID signature with wrong type") | |||
} | |||
if sig.CheckKeyIdOrFingerprint(e.PrimaryKey) { | |||
if err = e.PrimaryKey.VerifyUserIdSignature(pkt.Id, e.PrimaryKey, sig); err != nil { | |||
return errors.StructuralError("user ID self-signature invalid: " + err.Error()) | |||
} | |||
if sig.SigType == packet.SigTypeCertificationRevocation { | |||
identity.Revocations = append(identity.Revocations, sig) | |||
} else if identity.SelfSignature == nil || sig.CreationTime.After(identity.SelfSignature.CreationTime) { | |||
identity.SelfSignature = sig | |||
} | |||
identity.Signatures = append(identity.Signatures, sig) | |||
e.Identities[pkt.Id] = identity | |||
} else { | |||
identity.Signatures = append(identity.Signatures, sig) | |||
} | |||
} | |||
return nil | |||
} | |||
func addSubkey(e *Entity, packets *packet.Reader, pub *packet.PublicKey, priv *packet.PrivateKey) error { | |||
var subKey Subkey | |||
subKey.PublicKey = pub | |||
subKey.PrivateKey = priv | |||
for { | |||
p, err := packets.Next() | |||
if err == io.EOF { | |||
break | |||
} else if err != nil { | |||
return errors.StructuralError("subkey signature invalid: " + err.Error()) | |||
} | |||
sig, ok := p.(*packet.Signature) | |||
if !ok { | |||
packets.Unread(p) | |||
break | |||
} | |||
if sig.SigType != packet.SigTypeSubkeyBinding && sig.SigType != packet.SigTypeSubkeyRevocation { | |||
return errors.StructuralError("subkey signature with wrong type") | |||
} | |||
if err := e.PrimaryKey.VerifyKeySignature(subKey.PublicKey, sig); err != nil { | |||
return errors.StructuralError("subkey signature invalid: " + err.Error()) | |||
} | |||
switch sig.SigType { | |||
case packet.SigTypeSubkeyRevocation: | |||
subKey.Revocations = append(subKey.Revocations, sig) | |||
case packet.SigTypeSubkeyBinding: | |||
if subKey.Sig == nil || sig.CreationTime.After(subKey.Sig.CreationTime) { | |||
subKey.Sig = sig | |||
} | |||
} | |||
} | |||
if subKey.Sig == nil { | |||
return errors.StructuralError("subkey packet not followed by signature") | |||
} | |||
e.Subkeys = append(e.Subkeys, subKey) | |||
return nil | |||
} | |||
// SerializePrivate serializes an Entity, including private key material, but | |||
// excluding signatures from other entities, to the given Writer. | |||
// Identities and subkeys are re-signed in case they changed since NewEntry. | |||
// If config is nil, sensible defaults will be used. | |||
func (e *Entity) SerializePrivate(w io.Writer, config *packet.Config) (err error) { | |||
if e.PrivateKey.Dummy() { | |||
return errors.ErrDummyPrivateKey("dummy private key cannot re-sign identities") | |||
} | |||
return e.serializePrivate(w, config, true) | |||
} | |||
// SerializePrivateWithoutSigning serializes an Entity, including private key | |||
// material, but excluding signatures from other entities, to the given Writer. | |||
// Self-signatures of identities and subkeys are not re-signed. This is useful | |||
// when serializing GNU dummy keys, among other things. | |||
// If config is nil, sensible defaults will be used. | |||
func (e *Entity) SerializePrivateWithoutSigning(w io.Writer, config *packet.Config) (err error) { | |||
return e.serializePrivate(w, config, false) | |||
} | |||
func (e *Entity) serializePrivate(w io.Writer, config *packet.Config, reSign bool) (err error) { | |||
if e.PrivateKey == nil { | |||
return goerrors.New("openpgp: private key is missing") | |||
} | |||
err = e.PrivateKey.Serialize(w) | |||
if err != nil { | |||
return | |||
} | |||
for _, revocation := range e.Revocations { | |||
err := revocation.Serialize(w) | |||
if err != nil { | |||
return err | |||
} | |||
} | |||
for _, ident := range e.Identities { | |||
err = ident.UserId.Serialize(w) | |||
if err != nil { | |||
return | |||
} | |||
if reSign { | |||
if ident.SelfSignature == nil { | |||
return goerrors.New("openpgp: can't re-sign identity without valid self-signature") | |||
} | |||
err = ident.SelfSignature.SignUserId(ident.UserId.Id, e.PrimaryKey, e.PrivateKey, config) | |||
if err != nil { | |||
return | |||
} | |||
} | |||
for _, sig := range ident.Signatures { | |||
err = sig.Serialize(w) | |||
if err != nil { | |||
return err | |||
} | |||
} | |||
} | |||
for _, subkey := range e.Subkeys { | |||
err = subkey.PrivateKey.Serialize(w) | |||
if err != nil { | |||
return | |||
} | |||
if reSign { | |||
err = subkey.Sig.SignKey(subkey.PublicKey, e.PrivateKey, config) | |||
if err != nil { | |||
return | |||
} | |||
if subkey.Sig.EmbeddedSignature != nil { | |||
err = subkey.Sig.EmbeddedSignature.CrossSignKey(subkey.PublicKey, e.PrimaryKey, | |||
subkey.PrivateKey, config) | |||
if err != nil { | |||
return | |||
} | |||
} | |||
} | |||
for _, revocation := range subkey.Revocations { | |||
err := revocation.Serialize(w) | |||
if err != nil { | |||
return err | |||
} | |||
} | |||
err = subkey.Sig.Serialize(w) | |||
if err != nil { | |||
return | |||
} | |||
} | |||
return nil | |||
} | |||
// Serialize writes the public part of the given Entity to w, including | |||
// signatures from other entities. No private key material will be output. | |||
func (e *Entity) Serialize(w io.Writer) error { | |||
err := e.PrimaryKey.Serialize(w) | |||
if err != nil { | |||
return err | |||
} | |||
for _, revocation := range e.Revocations { | |||
err := revocation.Serialize(w) | |||
if err != nil { | |||
return err | |||
} | |||
} | |||
for _, ident := range e.Identities { | |||
err = ident.UserId.Serialize(w) | |||
if err != nil { | |||
return err | |||
} | |||
for _, sig := range ident.Signatures { | |||
err = sig.Serialize(w) | |||
if err != nil { | |||
return err | |||
} | |||
} | |||
} | |||
for _, subkey := range e.Subkeys { | |||
err = subkey.PublicKey.Serialize(w) | |||
if err != nil { | |||
return err | |||
} | |||
for _, revocation := range subkey.Revocations { | |||
err := revocation.Serialize(w) | |||
if err != nil { | |||
return err | |||
} | |||
} | |||
err = subkey.Sig.Serialize(w) | |||
if err != nil { | |||
return err | |||
} | |||
} | |||
return nil | |||
} | |||
// SignIdentity adds a signature to e, from signer, attesting that identity is | |||
// associated with e. The provided identity must already be an element of | |||
// e.Identities and the private key of signer must have been decrypted if | |||
// necessary. | |||
// If config is nil, sensible defaults will be used. | |||
func (e *Entity) SignIdentity(identity string, signer *Entity, config *packet.Config) error { | |||
certificationKey, ok := signer.CertificationKey(config.Now()) | |||
if !ok { | |||
return errors.InvalidArgumentError("no valid certification key found") | |||
} | |||
if certificationKey.PrivateKey.Encrypted { | |||
return errors.InvalidArgumentError("signing Entity's private key must be decrypted") | |||
} | |||
ident, ok := e.Identities[identity] | |||
if !ok { | |||
return errors.InvalidArgumentError("given identity string not found in Entity") | |||
} | |||
sig := createSignaturePacket(certificationKey.PublicKey, packet.SigTypeGenericCert, config) | |||
signingUserID := config.SigningUserId() | |||
if signingUserID != "" { | |||
if _, ok := signer.Identities[signingUserID]; !ok { | |||
return errors.InvalidArgumentError("signer identity string not found in signer Entity") | |||
} | |||
sig.SignerUserId = &signingUserID | |||
} | |||
if err := sig.SignUserId(identity, e.PrimaryKey, certificationKey.PrivateKey, config); err != nil { | |||
return err | |||
} | |||
ident.Signatures = append(ident.Signatures, sig) | |||
return nil | |||
} | |||
// RevokeKey generates a key revocation signature (packet.SigTypeKeyRevocation) with the | |||
// specified reason code and text (RFC4880 section-5.2.3.23). | |||
// If config is nil, sensible defaults will be used. | |||
func (e *Entity) RevokeKey(reason packet.ReasonForRevocation, reasonText string, config *packet.Config) error { | |||
revSig := createSignaturePacket(e.PrimaryKey, packet.SigTypeKeyRevocation, config) | |||
revSig.RevocationReason = &reason | |||
revSig.RevocationReasonText = reasonText | |||
if err := revSig.RevokeKey(e.PrimaryKey, e.PrivateKey, config); err != nil { | |||
return err | |||
} | |||
e.Revocations = append(e.Revocations, revSig) | |||
return nil | |||
} | |||
// RevokeSubkey generates a subkey revocation signature (packet.SigTypeSubkeyRevocation) for | |||
// a subkey with the specified reason code and text (RFC4880 section-5.2.3.23). | |||
// If config is nil, sensible defaults will be used. | |||
func (e *Entity) RevokeSubkey(sk *Subkey, reason packet.ReasonForRevocation, reasonText string, config *packet.Config) error { | |||
if err := e.PrimaryKey.VerifyKeySignature(sk.PublicKey, sk.Sig); err != nil { | |||
return errors.InvalidArgumentError("given subkey is not associated with this key") | |||
} | |||
revSig := createSignaturePacket(e.PrimaryKey, packet.SigTypeSubkeyRevocation, config) | |||
revSig.RevocationReason = &reason | |||
revSig.RevocationReasonText = reasonText | |||
if err := revSig.RevokeSubkey(sk.PublicKey, e.PrivateKey, config); err != nil { | |||
return err | |||
} | |||
sk.Revocations = append(sk.Revocations, revSig) | |||
return nil | |||
} |
@@ -0,0 +1,67 @@ | |||
// Copyright (C) 2019 ProtonTech AG | |||
package packet | |||
import "math/bits" | |||
// CipherSuite contains a combination of Cipher and Mode | |||
type CipherSuite struct { | |||
// The cipher function | |||
Cipher CipherFunction | |||
// The AEAD mode of operation. | |||
Mode AEADMode | |||
} | |||
// AEADConfig collects a number of AEAD parameters along with sensible defaults. | |||
// A nil AEADConfig is valid and results in all default values. | |||
type AEADConfig struct { | |||
// The AEAD mode of operation. | |||
DefaultMode AEADMode | |||
// Amount of octets in each chunk of data | |||
ChunkSize uint64 | |||
} | |||
// Mode returns the AEAD mode of operation. | |||
func (conf *AEADConfig) Mode() AEADMode { | |||
// If no preference is specified, OCB is used (which is mandatory to implement). | |||
if conf == nil || conf.DefaultMode == 0 { | |||
return AEADModeOCB | |||
} | |||
mode := conf.DefaultMode | |||
if mode != AEADModeEAX && mode != AEADModeOCB && mode != AEADModeGCM { | |||
panic("AEAD mode unsupported") | |||
} | |||
return mode | |||
} | |||
// ChunkSizeByte returns the byte indicating the chunk size. The effective | |||
// chunk size is computed with the formula uint64(1) << (chunkSizeByte + 6) | |||
// limit to 16 = 4 MiB | |||
// https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-07.html#section-5.13.2 | |||
func (conf *AEADConfig) ChunkSizeByte() byte { | |||
if conf == nil || conf.ChunkSize == 0 { | |||
return 12 // 1 << (12 + 6) == 262144 bytes | |||
} | |||
chunkSize := conf.ChunkSize | |||
exponent := bits.Len64(chunkSize) - 1 | |||
switch { | |||
case exponent < 6: | |||
exponent = 6 | |||
case exponent > 16: | |||
exponent = 16 | |||
} | |||
return byte(exponent - 6) | |||
} | |||
// decodeAEADChunkSize returns the effective chunk size. In 32-bit systems, the | |||
// maximum returned value is 1 << 30. | |||
func decodeAEADChunkSize(c byte) int { | |||
size := uint64(1 << (c + 6)) | |||
if size != uint64(int(size)) { | |||
return 1 << 30 | |||
} | |||
return int(size) | |||
} |
@@ -0,0 +1,264 @@ | |||
// Copyright (C) 2019 ProtonTech AG | |||
package packet | |||
import ( | |||
"bytes" | |||
"crypto/cipher" | |||
"encoding/binary" | |||
"io" | |||
"github.com/ProtonMail/go-crypto/openpgp/errors" | |||
) | |||
// aeadCrypter is an AEAD opener/sealer, its configuration, and data for en/decryption. | |||
type aeadCrypter struct { | |||
aead cipher.AEAD | |||
chunkSize int | |||
initialNonce []byte | |||
associatedData []byte // Chunk-independent associated data | |||
chunkIndex []byte // Chunk counter | |||
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 | |||
} | |||
// computeNonce takes the incremental index and computes an eXclusive OR with | |||
// the least significant 8 bytes of the receivers' initial nonce (see sec. | |||
// 5.16.1 and 5.16.2). It returns the resulting nonce. | |||
func (wo *aeadCrypter) computeNextNonce() (nonce []byte) { | |||
if wo.packetTag == packetTypeSymmetricallyEncryptedIntegrityProtected { | |||
return append(wo.initialNonce, wo.chunkIndex...) | |||
} | |||
nonce = make([]byte, len(wo.initialNonce)) | |||
copy(nonce, wo.initialNonce) | |||
offset := len(wo.initialNonce) - 8 | |||
for i := 0; i < 8; i++ { | |||
nonce[i+offset] ^= wo.chunkIndex[i] | |||
} | |||
return | |||
} | |||
// incrementIndex performs an integer increment by 1 of the integer represented by the | |||
// slice, modifying it accordingly. | |||
func (wo *aeadCrypter) incrementIndex() error { | |||
index := wo.chunkIndex | |||
if len(index) == 0 { | |||
return errors.AEADError("Index has length 0") | |||
} | |||
for i := len(index) - 1; i >= 0; i-- { | |||
if index[i] < 255 { | |||
index[i]++ | |||
return nil | |||
} | |||
index[i] = 0 | |||
} | |||
return errors.AEADError("cannot further increment index") | |||
} | |||
// aeadDecrypter reads and decrypts bytes. It buffers extra decrypted bytes when | |||
// necessary, similar to aeadEncrypter. | |||
type aeadDecrypter struct { | |||
aeadCrypter // Embedded ciphertext opener | |||
reader io.Reader // 'reader' is a partialLengthReader | |||
peekedBytes []byte // Used to detect last chunk | |||
eof bool | |||
} | |||
// Read decrypts bytes and reads them into dst. It decrypts when necessary and | |||
// buffers extra decrypted bytes. It returns the number of bytes copied into dst | |||
// and an error. | |||
func (ar *aeadDecrypter) Read(dst []byte) (n int, err error) { | |||
// Return buffered plaintext bytes from previous calls | |||
if ar.buffer.Len() > 0 { | |||
return ar.buffer.Read(dst) | |||
} | |||
// Return EOF if we've previously validated the final tag | |||
if ar.eof { | |||
return 0, io.EOF | |||
} | |||
// Read a chunk | |||
tagLen := ar.aead.Overhead() | |||
cipherChunkBuf := new(bytes.Buffer) | |||
_, errRead := io.CopyN(cipherChunkBuf, ar.reader, int64(ar.chunkSize+tagLen)) | |||
cipherChunk := cipherChunkBuf.Bytes() | |||
if errRead != nil && errRead != io.EOF { | |||
return 0, errRead | |||
} | |||
decrypted, errChunk := ar.openChunk(cipherChunk) | |||
if errChunk != nil { | |||
return 0, errChunk | |||
} | |||
// Return decrypted bytes, buffering if necessary | |||
if len(dst) < len(decrypted) { | |||
n = copy(dst, decrypted[:len(dst)]) | |||
ar.buffer.Write(decrypted[len(dst):]) | |||
} else { | |||
n = copy(dst, decrypted) | |||
} | |||
// Check final authentication tag | |||
if errRead == io.EOF { | |||
errChunk := ar.validateFinalTag(ar.peekedBytes) | |||
if errChunk != nil { | |||
return n, errChunk | |||
} | |||
ar.eof = true // Mark EOF for when we've returned all buffered data | |||
} | |||
return | |||
} | |||
// Close is noOp. The final authentication tag of the stream was already | |||
// checked in the last Read call. In the future, this function could be used to | |||
// wipe the reader and peeked, decrypted bytes, if necessary. | |||
func (ar *aeadDecrypter) Close() (err error) { | |||
return nil | |||
} | |||
// openChunk decrypts and checks integrity of an encrypted chunk, returning | |||
// the underlying plaintext and an error. It accesses peeked bytes from next | |||
// chunk, to identify the last chunk and decrypt/validate accordingly. | |||
func (ar *aeadDecrypter) openChunk(data []byte) ([]byte, error) { | |||
tagLen := ar.aead.Overhead() | |||
// Restore carried bytes from last call | |||
chunkExtra := append(ar.peekedBytes, data...) | |||
// 'chunk' contains encrypted bytes, followed by an authentication tag. | |||
chunk := chunkExtra[:len(chunkExtra)-tagLen] | |||
ar.peekedBytes = chunkExtra[len(chunkExtra)-tagLen:] | |||
adata := ar.associatedData | |||
if ar.aeadCrypter.packetTag == packetTypeAEADEncrypted { | |||
adata = append(ar.associatedData, ar.chunkIndex...) | |||
} | |||
nonce := ar.computeNextNonce() | |||
plainChunk, err := ar.aead.Open(nil, nonce, chunk, adata) | |||
if err != nil { | |||
return nil, err | |||
} | |||
ar.bytesProcessed += len(plainChunk) | |||
if err = ar.aeadCrypter.incrementIndex(); err != nil { | |||
return nil, err | |||
} | |||
return plainChunk, nil | |||
} | |||
// Checks the summary tag. It takes into account the total decrypted bytes into | |||
// the associated data. It returns an error, or nil if the tag is valid. | |||
func (ar *aeadDecrypter) validateFinalTag(tag []byte) error { | |||
// Associated: tag, version, cipher, aead, chunk size, ... | |||
amountBytes := make([]byte, 8) | |||
binary.BigEndian.PutUint64(amountBytes, uint64(ar.bytesProcessed)) | |||
adata := ar.associatedData | |||
if ar.aeadCrypter.packetTag == packetTypeAEADEncrypted { | |||
// ... index ... | |||
adata = append(ar.associatedData, ar.chunkIndex...) | |||
} | |||
// ... and total number of encrypted octets | |||
adata = append(adata, amountBytes...) | |||
nonce := ar.computeNextNonce() | |||
_, err := ar.aead.Open(nil, nonce, tag, adata) | |||
if err != nil { | |||
return err | |||
} | |||
return nil | |||
} | |||
// aeadEncrypter encrypts and writes bytes. It encrypts when necessary according | |||
// to the AEAD block size, and buffers the extra encrypted bytes for next write. | |||
type aeadEncrypter struct { | |||
aeadCrypter // Embedded plaintext sealer | |||
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. | |||
func (aw *aeadEncrypter) Write(plaintextBytes []byte) (n int, err error) { | |||
// Append plaintextBytes to existing buffered bytes | |||
n, err = aw.buffer.Write(plaintextBytes) | |||
if err != nil { | |||
return n, err | |||
} | |||
// Encrypt and write chunks | |||
for aw.buffer.Len() >= aw.chunkSize { | |||
plainChunk := aw.buffer.Next(aw.chunkSize) | |||
encryptedChunk, err := aw.sealChunk(plainChunk) | |||
if err != nil { | |||
return n, err | |||
} | |||
_, err = aw.writer.Write(encryptedChunk) | |||
if err != nil { | |||
return n, err | |||
} | |||
} | |||
return | |||
} | |||
// Close encrypts and writes the remaining buffered plaintext if any, appends | |||
// the final authentication tag, and closes the embedded writer. This function | |||
// MUST be called at the end of a stream. | |||
func (aw *aeadEncrypter) Close() (err error) { | |||
// Encrypt and write a chunk if there's buffered data left, or if we haven't | |||
// written any chunks yet. | |||
if aw.buffer.Len() > 0 || aw.bytesProcessed == 0 { | |||
plainChunk := aw.buffer.Bytes() | |||
lastEncryptedChunk, err := aw.sealChunk(plainChunk) | |||
if err != nil { | |||
return err | |||
} | |||
_, err = aw.writer.Write(lastEncryptedChunk) | |||
if err != nil { | |||
return err | |||
} | |||
} | |||
// Compute final tag (associated data: packet tag, version, cipher, aead, | |||
// chunk size... | |||
adata := aw.associatedData | |||
if aw.aeadCrypter.packetTag == packetTypeAEADEncrypted { | |||
// ... index ... | |||
adata = append(aw.associatedData, aw.chunkIndex...) | |||
} | |||
// ... and total number of encrypted octets | |||
amountBytes := make([]byte, 8) | |||
binary.BigEndian.PutUint64(amountBytes, uint64(aw.bytesProcessed)) | |||
adata = append(adata, amountBytes...) | |||
nonce := aw.computeNextNonce() | |||
finalTag := aw.aead.Seal(nil, nonce, nil, adata) | |||
_, err = aw.writer.Write(finalTag) | |||
if err != nil { | |||
return err | |||
} | |||
return aw.writer.Close() | |||
} | |||
// sealChunk Encrypts and authenticates the given chunk. | |||
func (aw *aeadEncrypter) sealChunk(data []byte) ([]byte, error) { | |||
if len(data) > aw.chunkSize { | |||
return nil, errors.AEADError("chunk exceeds maximum length") | |||
} | |||
if aw.associatedData == nil { | |||
return nil, errors.AEADError("can't seal without headers") | |||
} | |||
adata := aw.associatedData | |||
if aw.aeadCrypter.packetTag == packetTypeAEADEncrypted { | |||
adata = append(aw.associatedData, aw.chunkIndex...) | |||
} | |||
nonce := aw.computeNextNonce() | |||
encrypted := aw.aead.Seal(nil, nonce, data, adata) | |||
aw.bytesProcessed += len(data) | |||
if err := aw.aeadCrypter.incrementIndex(); err != nil { | |||
return nil, err | |||
} | |||
return encrypted, nil | |||
} |
@@ -0,0 +1,96 @@ | |||
// Copyright (C) 2019 ProtonTech AG | |||
package packet | |||
import ( | |||
"io" | |||
"github.com/ProtonMail/go-crypto/openpgp/errors" | |||
"github.com/ProtonMail/go-crypto/openpgp/internal/algorithm" | |||
) | |||
// AEADEncrypted represents an AEAD Encrypted Packet. | |||
// See https://www.ietf.org/archive/id/draft-koch-openpgp-2015-rfc4880bis-00.html#name-aead-encrypted-data-packet-t | |||
type AEADEncrypted struct { | |||
cipher CipherFunction | |||
mode AEADMode | |||
chunkSizeByte byte | |||
Contents io.Reader // Encrypted chunks and tags | |||
initialNonce []byte // Referred to as IV in RFC4880-bis | |||
} | |||
// Only currently defined version | |||
const aeadEncryptedVersion = 1 | |||
func (ae *AEADEncrypted) parse(buf io.Reader) error { | |||
headerData := make([]byte, 4) | |||
if n, err := io.ReadFull(buf, headerData); n < 4 { | |||
return errors.AEADError("could not read aead header:" + err.Error()) | |||
} | |||
// Read initial nonce | |||
mode := AEADMode(headerData[2]) | |||
nonceLen := mode.IvLength() | |||
// This packet supports only EAX and OCB | |||
// https://www.ietf.org/archive/id/draft-koch-openpgp-2015-rfc4880bis-00.html#name-aead-encrypted-data-packet-t | |||
if nonceLen == 0 || mode > AEADModeOCB { | |||
return errors.AEADError("unknown mode") | |||
} | |||
initialNonce := make([]byte, nonceLen) | |||
if n, err := io.ReadFull(buf, initialNonce); n < nonceLen { | |||
return errors.AEADError("could not read aead nonce:" + err.Error()) | |||
} | |||
ae.Contents = buf | |||
ae.initialNonce = initialNonce | |||
c := headerData[1] | |||
if _, ok := algorithm.CipherById[c]; !ok { | |||
return errors.UnsupportedError("unknown cipher: " + string(c)) | |||
} | |||
ae.cipher = CipherFunction(c) | |||
ae.mode = mode | |||
ae.chunkSizeByte = headerData[3] | |||
return nil | |||
} | |||
// Decrypt returns a io.ReadCloser from which decrypted bytes can be read, or | |||
// an error. | |||
func (ae *AEADEncrypted) Decrypt(ciph CipherFunction, key []byte) (io.ReadCloser, error) { | |||
return ae.decrypt(key) | |||
} | |||
// decrypt prepares an aeadCrypter and returns a ReadCloser from which | |||
// decrypted bytes can be read (see aeadDecrypter.Read()). | |||
func (ae *AEADEncrypted) decrypt(key []byte) (io.ReadCloser, error) { | |||
blockCipher := ae.cipher.new(key) | |||
aead := ae.mode.new(blockCipher) | |||
// Carry the first tagLen bytes | |||
tagLen := ae.mode.TagLength() | |||
peekedBytes := make([]byte, tagLen) | |||
n, err := io.ReadFull(ae.Contents, peekedBytes) | |||
if n < tagLen || (err != nil && err != io.EOF) { | |||
return nil, errors.AEADError("Not enough data to decrypt:" + err.Error()) | |||
} | |||
chunkSize := decodeAEADChunkSize(ae.chunkSizeByte) | |||
return &aeadDecrypter{ | |||
aeadCrypter: aeadCrypter{ | |||
aead: aead, | |||
chunkSize: chunkSize, | |||
initialNonce: ae.initialNonce, | |||
associatedData: ae.associatedData(), | |||
chunkIndex: make([]byte, 8), | |||
packetTag: packetTypeAEADEncrypted, | |||
}, | |||
reader: ae.Contents, | |||
peekedBytes: peekedBytes}, nil | |||
} | |||
// associatedData for chunks: tag, version, cipher, mode, chunk size byte | |||
func (ae *AEADEncrypted) associatedData() []byte { | |||
return []byte{ | |||
0xD4, | |||
aeadEncryptedVersion, | |||
byte(ae.cipher), | |||
byte(ae.mode), | |||
ae.chunkSizeByte} | |||
} |
@@ -0,0 +1,125 @@ | |||
// Copyright 2011 The Go Authors. All rights reserved. | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
package packet | |||
import ( | |||
"compress/bzip2" | |||
"compress/flate" | |||
"compress/zlib" | |||
"github.com/ProtonMail/go-crypto/openpgp/errors" | |||
"io" | |||
"strconv" | |||
) | |||
// Compressed represents a compressed OpenPGP packet. The decompressed contents | |||
// will contain more OpenPGP packets. See RFC 4880, section 5.6. | |||
type Compressed struct { | |||
Body io.Reader | |||
} | |||
const ( | |||
NoCompression = flate.NoCompression | |||
BestSpeed = flate.BestSpeed | |||
BestCompression = flate.BestCompression | |||
DefaultCompression = flate.DefaultCompression | |||
) | |||
// CompressionConfig contains compressor configuration settings. | |||
type CompressionConfig struct { | |||
// Level is the compression level to use. It must be set to | |||
// between -1 and 9, with -1 causing the compressor to use the | |||
// default compression level, 0 causing the compressor to use | |||
// no compression and 1 to 9 representing increasing (better, | |||
// slower) compression levels. If Level is less than -1 or | |||
// more then 9, a non-nil error will be returned during | |||
// encryption. See the constants above for convenient common | |||
// settings for Level. | |||
Level int | |||
} | |||
func (c *Compressed) parse(r io.Reader) error { | |||
var buf [1]byte | |||
_, err := readFull(r, buf[:]) | |||
if err != nil { | |||
return err | |||
} | |||
switch buf[0] { | |||
case 0: | |||
c.Body = r | |||
case 1: | |||
c.Body = flate.NewReader(r) | |||
case 2: | |||
c.Body, err = zlib.NewReader(r) | |||
case 3: | |||
c.Body = bzip2.NewReader(r) | |||
default: | |||
err = errors.UnsupportedError("unknown compression algorithm: " + strconv.Itoa(int(buf[0]))) | |||
} | |||
return err | |||
} | |||
// compressedWriterCloser represents the serialized compression stream | |||
// header and the compressor. Its Close() method ensures that both the | |||
// compressor and serialized stream header are closed. Its Write() | |||
// method writes to the compressor. | |||
type compressedWriteCloser struct { | |||
sh io.Closer // Stream Header | |||
c io.WriteCloser // Compressor | |||
} | |||
func (cwc compressedWriteCloser) Write(p []byte) (int, error) { | |||
return cwc.c.Write(p) | |||
} | |||
func (cwc compressedWriteCloser) Close() (err error) { | |||
err = cwc.c.Close() | |||
if err != nil { | |||
return err | |||
} | |||
return cwc.sh.Close() | |||
} | |||
// SerializeCompressed serializes a compressed data packet to w and | |||
// returns a WriteCloser to which the literal data packets themselves | |||
// can be written and which MUST be closed on completion. If cc is | |||
// nil, sensible defaults will be used to configure the compression | |||
// algorithm. | |||
func SerializeCompressed(w io.WriteCloser, algo CompressionAlgo, cc *CompressionConfig) (literaldata io.WriteCloser, err error) { | |||
compressed, err := serializeStreamHeader(w, packetTypeCompressed) | |||
if err != nil { | |||
return | |||
} | |||
_, err = compressed.Write([]byte{uint8(algo)}) | |||
if err != nil { | |||
return | |||
} | |||
level := DefaultCompression | |||
if cc != nil { | |||
level = cc.Level | |||
} | |||
var compressor io.WriteCloser | |||
switch algo { | |||
case CompressionZIP: | |||
compressor, err = flate.NewWriter(compressed, level) | |||
case CompressionZLIB: | |||
compressor, err = zlib.NewWriterLevel(compressed, level) | |||
default: | |||
s := strconv.Itoa(int(algo)) | |||
err = errors.UnsupportedError("Unsupported compression algorithm: " + s) | |||
} | |||
if err != nil { | |||
return | |||
} | |||
literaldata = compressedWriteCloser{compressed, compressor} | |||
return | |||
} |
@@ -0,0 +1,248 @@ | |||
// Copyright 2012 The Go Authors. All rights reserved. | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
package packet | |||
import ( | |||
"crypto" | |||
"crypto/rand" | |||
"io" | |||
"math/big" | |||
"time" | |||
"github.com/ProtonMail/go-crypto/openpgp/s2k" | |||
) | |||
// Config collects a number of parameters along with sensible defaults. | |||
// A nil *Config is valid and results in all default values. | |||
type Config struct { | |||
// Rand provides the source of entropy. | |||
// If nil, the crypto/rand Reader is used. | |||
Rand io.Reader | |||
// DefaultHash is the default hash function to be used. | |||
// If zero, SHA-256 is used. | |||
DefaultHash crypto.Hash | |||
// DefaultCipher is the cipher to be used. | |||
// If zero, AES-128 is used. | |||
DefaultCipher CipherFunction | |||
// Time returns the current time as the number of seconds since the | |||
// epoch. If Time is nil, time.Now is used. | |||
Time func() time.Time | |||
// DefaultCompressionAlgo is the compression algorithm to be | |||
// applied to the plaintext before encryption. If zero, no | |||
// compression is done. | |||
DefaultCompressionAlgo CompressionAlgo | |||
// CompressionConfig configures the compression settings. | |||
CompressionConfig *CompressionConfig | |||
// 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 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. | |||
RSABits int | |||
// The public key algorithm to use - will always create a signing primary | |||
// key and encryption subkey. | |||
Algorithm PublicKeyAlgorithm | |||
// Some known primes that are optionally prepopulated by the caller | |||
RSAPrimes []*big.Int | |||
// Curve configures the desired packet.Curve if the Algorithm is PubKeyAlgoECDSA, | |||
// PubKeyAlgoEdDSA, or PubKeyAlgoECDH. If empty Curve25519 is used. | |||
Curve Curve | |||
// AEADConfig configures the use of the new AEAD Encrypted Data Packet, | |||
// defined in the draft of the next version of the OpenPGP specification. | |||
// If a non-nil AEADConfig is passed, usage of this packet is enabled. By | |||
// default, it is disabled. See the documentation of AEADConfig for more | |||
// configuration options related to AEAD. | |||
// **Note: using this option may break compatibility with other OpenPGP | |||
// implementations, as well as future versions of this library.** | |||
AEADConfig *AEADConfig | |||
// V5Keys configures version 5 key generation. If false, this package still | |||
// supports version 5 keys, but produces version 4 keys. | |||
V5Keys bool | |||
// "The validity period of the key. This is the number of seconds after | |||
// the key creation time that the key expires. If this is not present | |||
// or has a value of zero, the key never expires. This is found only on | |||
// a self-signature."" | |||
// https://tools.ietf.org/html/rfc4880#section-5.2.3.6 | |||
KeyLifetimeSecs uint32 | |||
// "The validity period of the signature. This is the number of seconds | |||
// after the signature creation time that the signature expires. If | |||
// this is not present or has a value of zero, it never expires." | |||
// https://tools.ietf.org/html/rfc4880#section-5.2.3.10 | |||
SigLifetimeSecs uint32 | |||
// SigningKeyId is used to specify the signing key to use (by Key ID). | |||
// By default, the signing key is selected automatically, preferring | |||
// signing subkeys if available. | |||
SigningKeyId uint64 | |||
// SigningIdentity is used to specify a user ID (packet Signer's User ID, type 28) | |||
// when producing a generic certification signature onto an existing user ID. | |||
// The identity must be present in the signer Entity. | |||
SigningIdentity string | |||
// InsecureAllowUnauthenticatedMessages controls, whether it is tolerated to read | |||
// encrypted messages without Modification Detection Code (MDC). | |||
// MDC is mandated by the IETF OpenPGP Crypto Refresh draft and has long been implemented | |||
// in most OpenPGP implementations. Messages without MDC are considered unnecessarily | |||
// insecure and should be prevented whenever possible. | |||
// In case one needs to deal with messages from very old OpenPGP implementations, there | |||
// might be no other way than to tolerate the missing MDC. Setting this flag, allows this | |||
// mode of operation. It should be considered a measure of last resort. | |||
InsecureAllowUnauthenticatedMessages bool | |||
// KnownNotations is a map of Notation Data names to bools, which controls | |||
// the notation names that are allowed to be present in critical Notation Data | |||
// signature subpackets. | |||
KnownNotations map[string]bool | |||
// SignatureNotations is a list of Notations to be added to any signatures. | |||
SignatureNotations []*Notation | |||
} | |||
func (c *Config) Random() io.Reader { | |||
if c == nil || c.Rand == nil { | |||
return rand.Reader | |||
} | |||
return c.Rand | |||
} | |||
func (c *Config) Hash() crypto.Hash { | |||
if c == nil || uint(c.DefaultHash) == 0 { | |||
return crypto.SHA256 | |||
} | |||
return c.DefaultHash | |||
} | |||
func (c *Config) Cipher() CipherFunction { | |||
if c == nil || uint8(c.DefaultCipher) == 0 { | |||
return CipherAES128 | |||
} | |||
return c.DefaultCipher | |||
} | |||
func (c *Config) Now() time.Time { | |||
if c == nil || c.Time == nil { | |||
return time.Now().Truncate(time.Second) | |||
} | |||
return c.Time().Truncate(time.Second) | |||
} | |||
// KeyLifetime returns the validity period of the key. | |||
func (c *Config) KeyLifetime() uint32 { | |||
if c == nil { | |||
return 0 | |||
} | |||
return c.KeyLifetimeSecs | |||
} | |||
// SigLifetime returns the validity period of the signature. | |||
func (c *Config) SigLifetime() uint32 { | |||
if c == nil { | |||
return 0 | |||
} | |||
return c.SigLifetimeSecs | |||
} | |||
func (c *Config) Compression() CompressionAlgo { | |||
if c == nil { | |||
return CompressionNone | |||
} | |||
return c.DefaultCompressionAlgo | |||
} | |||
func (c *Config) RSAModulusBits() int { | |||
if c == nil || c.RSABits == 0 { | |||
return 2048 | |||
} | |||
return c.RSABits | |||
} | |||
func (c *Config) PublicKeyAlgorithm() PublicKeyAlgorithm { | |||
if c == nil || c.Algorithm == 0 { | |||
return PubKeyAlgoRSA | |||
} | |||
return c.Algorithm | |||
} | |||
func (c *Config) CurveName() Curve { | |||
if c == nil || c.Curve == "" { | |||
return Curve25519 | |||
} | |||
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 | |||
} | |||
return c.AEADConfig | |||
} | |||
func (c *Config) SigningKey() uint64 { | |||
if c == nil { | |||
return 0 | |||
} | |||
return c.SigningKeyId | |||
} | |||
func (c *Config) SigningUserId() string { | |||
if c == nil { | |||
return "" | |||
} | |||
return c.SigningIdentity | |||
} | |||
func (c *Config) AllowUnauthenticatedMessages() bool { | |||
if c == nil { | |||
return false | |||
} | |||
return c.InsecureAllowUnauthenticatedMessages | |||
} | |||
func (c *Config) KnownNotation(notationName string) bool { | |||
if c == nil { | |||
return false | |||
} | |||
return c.KnownNotations[notationName] | |||
} | |||
func (c *Config) Notations() []*Notation { | |||
if c == nil { | |||
return nil | |||
} | |||
return c.SignatureNotations | |||
} |
@@ -0,0 +1,286 @@ | |||
// Copyright 2011 The Go Authors. All rights reserved. | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
package packet | |||
import ( | |||
"crypto" | |||
"crypto/rsa" | |||
"encoding/binary" | |||
"io" | |||
"math/big" | |||
"strconv" | |||
"github.com/ProtonMail/go-crypto/openpgp/ecdh" | |||
"github.com/ProtonMail/go-crypto/openpgp/elgamal" | |||
"github.com/ProtonMail/go-crypto/openpgp/errors" | |||
"github.com/ProtonMail/go-crypto/openpgp/internal/encoding" | |||
) | |||
const encryptedKeyVersion = 3 | |||
// EncryptedKey represents a public-key encrypted session key. See RFC 4880, | |||
// section 5.1. | |||
type EncryptedKey struct { | |||
KeyId uint64 | |||
Algo PublicKeyAlgorithm | |||
CipherFunc CipherFunction // only valid after a successful Decrypt for a v3 packet | |||
Key []byte // only valid after a successful Decrypt | |||
encryptedMPI1, encryptedMPI2 encoding.Field | |||
} | |||
func (e *EncryptedKey) parse(r io.Reader) (err error) { | |||
var buf [10]byte | |||
_, err = readFull(r, buf[:]) | |||
if err != nil { | |||
return | |||
} | |||
if buf[0] != encryptedKeyVersion { | |||
return errors.UnsupportedError("unknown EncryptedKey version " + strconv.Itoa(int(buf[0]))) | |||
} | |||
e.KeyId = binary.BigEndian.Uint64(buf[1:9]) | |||
e.Algo = PublicKeyAlgorithm(buf[9]) | |||
switch e.Algo { | |||
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly: | |||
e.encryptedMPI1 = new(encoding.MPI) | |||
if _, err = e.encryptedMPI1.ReadFrom(r); err != nil { | |||
return | |||
} | |||
case PubKeyAlgoElGamal: | |||
e.encryptedMPI1 = new(encoding.MPI) | |||
if _, err = e.encryptedMPI1.ReadFrom(r); err != nil { | |||
return | |||
} | |||
e.encryptedMPI2 = new(encoding.MPI) | |||
if _, err = e.encryptedMPI2.ReadFrom(r); err != nil { | |||
return | |||
} | |||
case PubKeyAlgoECDH: | |||
e.encryptedMPI1 = new(encoding.MPI) | |||
if _, err = e.encryptedMPI1.ReadFrom(r); err != nil { | |||
return | |||
} | |||
e.encryptedMPI2 = new(encoding.OID) | |||
if _, err = e.encryptedMPI2.ReadFrom(r); err != nil { | |||
return | |||
} | |||
} | |||
_, err = consumeAll(r) | |||
return | |||
} | |||
func checksumKeyMaterial(key []byte) uint16 { | |||
var checksum uint16 | |||
for _, v := range key { | |||
checksum += uint16(v) | |||
} | |||
return checksum | |||
} | |||
// Decrypt decrypts an encrypted session key with the given private key. The | |||
// private key must have been decrypted first. | |||
// If config is nil, sensible defaults will be used. | |||
func (e *EncryptedKey) Decrypt(priv *PrivateKey, config *Config) error { | |||
if e.KeyId != 0 && e.KeyId != priv.KeyId { | |||
return errors.InvalidArgumentError("cannot decrypt encrypted session key for key id " + strconv.FormatUint(e.KeyId, 16) + " with private key id " + strconv.FormatUint(priv.KeyId, 16)) | |||
} | |||
if e.Algo != priv.PubKeyAlgo { | |||
return errors.InvalidArgumentError("cannot decrypt encrypted session key of type " + strconv.Itoa(int(e.Algo)) + " with private key of type " + strconv.Itoa(int(priv.PubKeyAlgo))) | |||
} | |||
if priv.Dummy() { | |||
return errors.ErrDummyPrivateKey("dummy key found") | |||
} | |||
var err error | |||
var b []byte | |||
// TODO(agl): use session key decryption routines here to avoid | |||
// padding oracle attacks. | |||
switch priv.PubKeyAlgo { | |||
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly: | |||
// Supports both *rsa.PrivateKey and crypto.Decrypter | |||
k := priv.PrivateKey.(crypto.Decrypter) | |||
b, err = k.Decrypt(config.Random(), padToKeySize(k.Public().(*rsa.PublicKey), e.encryptedMPI1.Bytes()), nil) | |||
case PubKeyAlgoElGamal: | |||
c1 := new(big.Int).SetBytes(e.encryptedMPI1.Bytes()) | |||
c2 := new(big.Int).SetBytes(e.encryptedMPI2.Bytes()) | |||
b, err = elgamal.Decrypt(priv.PrivateKey.(*elgamal.PrivateKey), c1, c2) | |||
case PubKeyAlgoECDH: | |||
vsG := e.encryptedMPI1.Bytes() | |||
m := e.encryptedMPI2.Bytes() | |||
oid := priv.PublicKey.oid.EncodedBytes() | |||
b, err = ecdh.Decrypt(priv.PrivateKey.(*ecdh.PrivateKey), vsG, m, oid, priv.PublicKey.Fingerprint[:]) | |||
default: | |||
err = errors.InvalidArgumentError("cannot decrypt encrypted session key with private key of type " + strconv.Itoa(int(priv.PubKeyAlgo))) | |||
} | |||
if err != nil { | |||
return err | |||
} | |||
e.CipherFunc = CipherFunction(b[0]) | |||
if !e.CipherFunc.IsSupported() { | |||
return errors.UnsupportedError("unsupported encryption function") | |||
} | |||
e.Key = b[1 : len(b)-2] | |||
expectedChecksum := uint16(b[len(b)-2])<<8 | uint16(b[len(b)-1]) | |||
checksum := checksumKeyMaterial(e.Key) | |||
if checksum != expectedChecksum { | |||
return errors.StructuralError("EncryptedKey checksum incorrect") | |||
} | |||
return nil | |||
} | |||
// Serialize writes the encrypted key packet, e, to w. | |||
func (e *EncryptedKey) Serialize(w io.Writer) error { | |||
var mpiLen int | |||
switch e.Algo { | |||
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly: | |||
mpiLen = int(e.encryptedMPI1.EncodedLength()) | |||
case PubKeyAlgoElGamal: | |||
mpiLen = int(e.encryptedMPI1.EncodedLength()) + int(e.encryptedMPI2.EncodedLength()) | |||
case PubKeyAlgoECDH: | |||
mpiLen = int(e.encryptedMPI1.EncodedLength()) + int(e.encryptedMPI2.EncodedLength()) | |||
default: | |||
return errors.InvalidArgumentError("don't know how to serialize encrypted key type " + strconv.Itoa(int(e.Algo))) | |||
} | |||
err := serializeHeader(w, packetTypeEncryptedKey, 1 /* version */ +8 /* key id */ +1 /* algo */ +mpiLen) | |||
if err != nil { | |||
return err | |||
} | |||
w.Write([]byte{encryptedKeyVersion}) | |||
binary.Write(w, binary.BigEndian, e.KeyId) | |||
w.Write([]byte{byte(e.Algo)}) | |||
switch e.Algo { | |||
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly: | |||
_, err := w.Write(e.encryptedMPI1.EncodedBytes()) | |||
return err | |||
case PubKeyAlgoElGamal: | |||
if _, err := w.Write(e.encryptedMPI1.EncodedBytes()); err != nil { | |||
return err | |||
} | |||
_, err := w.Write(e.encryptedMPI2.EncodedBytes()) | |||
return err | |||
case PubKeyAlgoECDH: | |||
if _, err := w.Write(e.encryptedMPI1.EncodedBytes()); err != nil { | |||
return err | |||
} | |||
_, err := w.Write(e.encryptedMPI2.EncodedBytes()) | |||
return err | |||
default: | |||
panic("internal error") | |||
} | |||
} | |||
// SerializeEncryptedKey serializes an encrypted key packet to w that contains | |||
// key, encrypted to pub. | |||
// If config is nil, sensible defaults will be used. | |||
func SerializeEncryptedKey(w io.Writer, pub *PublicKey, cipherFunc CipherFunction, key []byte, config *Config) error { | |||
var buf [10]byte | |||
buf[0] = encryptedKeyVersion | |||
binary.BigEndian.PutUint64(buf[1:9], pub.KeyId) | |||
buf[9] = byte(pub.PubKeyAlgo) | |||
keyBlock := make([]byte, 1 /* cipher type */ +len(key)+2 /* checksum */) | |||
keyBlock[0] = byte(cipherFunc) | |||
copy(keyBlock[1:], key) | |||
checksum := checksumKeyMaterial(key) | |||
keyBlock[1+len(key)] = byte(checksum >> 8) | |||
keyBlock[1+len(key)+1] = byte(checksum) | |||
switch pub.PubKeyAlgo { | |||
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly: | |||
return serializeEncryptedKeyRSA(w, config.Random(), buf, pub.PublicKey.(*rsa.PublicKey), keyBlock) | |||
case PubKeyAlgoElGamal: | |||
return serializeEncryptedKeyElGamal(w, config.Random(), buf, pub.PublicKey.(*elgamal.PublicKey), keyBlock) | |||
case PubKeyAlgoECDH: | |||
return serializeEncryptedKeyECDH(w, config.Random(), buf, pub.PublicKey.(*ecdh.PublicKey), keyBlock, pub.oid, pub.Fingerprint) | |||
case PubKeyAlgoDSA, PubKeyAlgoRSASignOnly: | |||
return errors.InvalidArgumentError("cannot encrypt to public key of type " + strconv.Itoa(int(pub.PubKeyAlgo))) | |||
} | |||
return errors.UnsupportedError("encrypting a key to public key of type " + strconv.Itoa(int(pub.PubKeyAlgo))) | |||
} | |||
func serializeEncryptedKeyRSA(w io.Writer, rand io.Reader, header [10]byte, pub *rsa.PublicKey, keyBlock []byte) error { | |||
cipherText, err := rsa.EncryptPKCS1v15(rand, pub, keyBlock) | |||
if err != nil { | |||
return errors.InvalidArgumentError("RSA encryption failed: " + err.Error()) | |||
} | |||
cipherMPI := encoding.NewMPI(cipherText) | |||
packetLen := 10 /* header length */ + int(cipherMPI.EncodedLength()) | |||
err = serializeHeader(w, packetTypeEncryptedKey, packetLen) | |||
if err != nil { | |||
return err | |||
} | |||
_, err = w.Write(header[:]) | |||
if err != nil { | |||
return err | |||
} | |||
_, err = w.Write(cipherMPI.EncodedBytes()) | |||
return err | |||
} | |||
func serializeEncryptedKeyElGamal(w io.Writer, rand io.Reader, header [10]byte, pub *elgamal.PublicKey, keyBlock []byte) error { | |||
c1, c2, err := elgamal.Encrypt(rand, pub, keyBlock) | |||
if err != nil { | |||
return errors.InvalidArgumentError("ElGamal encryption failed: " + err.Error()) | |||
} | |||
packetLen := 10 /* header length */ | |||
packetLen += 2 /* mpi size */ + (c1.BitLen()+7)/8 | |||
packetLen += 2 /* mpi size */ + (c2.BitLen()+7)/8 | |||
err = serializeHeader(w, packetTypeEncryptedKey, packetLen) | |||
if err != nil { | |||
return err | |||
} | |||
_, err = w.Write(header[:]) | |||
if err != nil { | |||
return err | |||
} | |||
if _, err = w.Write(new(encoding.MPI).SetBig(c1).EncodedBytes()); err != nil { | |||
return err | |||
} | |||
_, err = w.Write(new(encoding.MPI).SetBig(c2).EncodedBytes()) | |||
return err | |||
} | |||
func serializeEncryptedKeyECDH(w io.Writer, rand io.Reader, header [10]byte, pub *ecdh.PublicKey, keyBlock []byte, oid encoding.Field, fingerprint []byte) error { | |||
vsG, c, err := ecdh.Encrypt(rand, pub, keyBlock, oid.EncodedBytes(), fingerprint) | |||
if err != nil { | |||
return errors.InvalidArgumentError("ECDH encryption failed: " + err.Error()) | |||
} | |||
g := encoding.NewMPI(vsG) | |||
m := encoding.NewOID(c) | |||
packetLen := 10 /* header length */ | |||
packetLen += int(g.EncodedLength()) + int(m.EncodedLength()) | |||
err = serializeHeader(w, packetTypeEncryptedKey, packetLen) | |||
if err != nil { | |||
return err | |||
} | |||
_, err = w.Write(header[:]) | |||
if err != nil { | |||
return err | |||
} | |||
if _, err = w.Write(g.EncodedBytes()); err != nil { | |||
return err | |||
} | |||
_, err = w.Write(m.EncodedBytes()) | |||
return err | |||
} |
@@ -0,0 +1,91 @@ | |||
// Copyright 2011 The Go Authors. All rights reserved. | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
package packet | |||
import ( | |||
"encoding/binary" | |||
"io" | |||
) | |||
// LiteralData represents an encrypted file. See RFC 4880, section 5.9. | |||
type LiteralData struct { | |||
Format uint8 | |||
IsBinary bool | |||
FileName string | |||
Time uint32 // Unix epoch time. Either creation time or modification time. 0 means undefined. | |||
Body io.Reader | |||
} | |||
// ForEyesOnly returns whether the contents of the LiteralData have been marked | |||
// as especially sensitive. | |||
func (l *LiteralData) ForEyesOnly() bool { | |||
return l.FileName == "_CONSOLE" | |||
} | |||
func (l *LiteralData) parse(r io.Reader) (err error) { | |||
var buf [256]byte | |||
_, err = readFull(r, buf[:2]) | |||
if err != nil { | |||
return | |||
} | |||
l.Format = buf[0] | |||
l.IsBinary = l.Format == 'b' | |||
fileNameLen := int(buf[1]) | |||
_, err = readFull(r, buf[:fileNameLen]) | |||
if err != nil { | |||
return | |||
} | |||
l.FileName = string(buf[:fileNameLen]) | |||
_, err = readFull(r, buf[:4]) | |||
if err != nil { | |||
return | |||
} | |||
l.Time = binary.BigEndian.Uint32(buf[:4]) | |||
l.Body = r | |||
return | |||
} | |||
// SerializeLiteral serializes a literal data packet to w and returns a | |||
// WriteCloser to which the data itself can be written and which MUST be closed | |||
// on completion. The fileName is truncated to 255 bytes. | |||
func SerializeLiteral(w io.WriteCloser, isBinary bool, fileName string, time uint32) (plaintext io.WriteCloser, err error) { | |||
var buf [4]byte | |||
buf[0] = 't' | |||
if isBinary { | |||
buf[0] = 'b' | |||
} | |||
if len(fileName) > 255 { | |||
fileName = fileName[:255] | |||
} | |||
buf[1] = byte(len(fileName)) | |||
inner, err := serializeStreamHeader(w, packetTypeLiteralData) | |||
if err != nil { | |||
return | |||
} | |||
_, err = inner.Write(buf[:2]) | |||
if err != nil { | |||
return | |||
} | |||
_, err = inner.Write([]byte(fileName)) | |||
if err != nil { | |||
return | |||
} | |||
binary.BigEndian.PutUint32(buf[:], time) | |||
_, err = inner.Write(buf[:]) | |||
if err != nil { | |||
return | |||
} | |||
plaintext = inner | |||
return | |||
} |
@@ -0,0 +1,29 @@ | |||
package packet | |||
// Notation type represents a Notation Data subpacket | |||
// see https://tools.ietf.org/html/rfc4880#section-5.2.3.16 | |||
type Notation struct { | |||
Name string | |||
Value []byte | |||
IsCritical bool | |||
IsHumanReadable bool | |||
} | |||
func (notation *Notation) getData() []byte { | |||
nameData := []byte(notation.Name) | |||
nameLen := len(nameData) | |||
valueLen := len(notation.Value) | |||
data := make([]byte, 8+nameLen+valueLen) | |||
if notation.IsHumanReadable { | |||
data[0] = 0x80 | |||
} | |||
data[4] = byte(nameLen >> 8) | |||
data[5] = byte(nameLen) | |||
data[6] = byte(valueLen >> 8) | |||
data[7] = byte(valueLen) | |||
copy(data[8:8+nameLen], nameData) | |||
copy(data[8+nameLen:], notation.Value) | |||
return data | |||
} |
@@ -0,0 +1,137 @@ | |||
// Copyright 2010 The Go Authors. All rights reserved. | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
// OpenPGP CFB Mode. http://tools.ietf.org/html/rfc4880#section-13.9 | |||
package packet | |||
import ( | |||
"crypto/cipher" | |||
) | |||
type ocfbEncrypter struct { | |||
b cipher.Block | |||
fre []byte | |||
outUsed int | |||
} | |||
// An OCFBResyncOption determines if the "resynchronization step" of OCFB is | |||
// performed. | |||
type OCFBResyncOption bool | |||
const ( | |||
OCFBResync OCFBResyncOption = true | |||
OCFBNoResync OCFBResyncOption = false | |||
) | |||
// NewOCFBEncrypter returns a cipher.Stream which encrypts data with OpenPGP's | |||
// cipher feedback mode using the given cipher.Block, and an initial amount of | |||
// ciphertext. randData must be random bytes and be the same length as the | |||
// cipher.Block's block size. Resync determines if the "resynchronization step" | |||
// from RFC 4880, 13.9 step 7 is performed. Different parts of OpenPGP vary on | |||
// this point. | |||
func NewOCFBEncrypter(block cipher.Block, randData []byte, resync OCFBResyncOption) (cipher.Stream, []byte) { | |||
blockSize := block.BlockSize() | |||
if len(randData) != blockSize { | |||
return nil, nil | |||
} | |||
x := &ocfbEncrypter{ | |||
b: block, | |||
fre: make([]byte, blockSize), | |||
outUsed: 0, | |||
} | |||
prefix := make([]byte, blockSize+2) | |||
block.Encrypt(x.fre, x.fre) | |||
for i := 0; i < blockSize; i++ { | |||
prefix[i] = randData[i] ^ x.fre[i] | |||
} | |||
block.Encrypt(x.fre, prefix[:blockSize]) | |||
prefix[blockSize] = x.fre[0] ^ randData[blockSize-2] | |||
prefix[blockSize+1] = x.fre[1] ^ randData[blockSize-1] | |||
if resync { | |||
block.Encrypt(x.fre, prefix[2:]) | |||
} else { | |||
x.fre[0] = prefix[blockSize] | |||
x.fre[1] = prefix[blockSize+1] | |||
x.outUsed = 2 | |||
} | |||
return x, prefix | |||
} | |||
func (x *ocfbEncrypter) XORKeyStream(dst, src []byte) { | |||
for i := 0; i < len(src); i++ { | |||
if x.outUsed == len(x.fre) { | |||
x.b.Encrypt(x.fre, x.fre) | |||
x.outUsed = 0 | |||
} | |||
x.fre[x.outUsed] ^= src[i] | |||
dst[i] = x.fre[x.outUsed] | |||
x.outUsed++ | |||
} | |||
} | |||
type ocfbDecrypter struct { | |||
b cipher.Block | |||
fre []byte | |||
outUsed int | |||
} | |||
// NewOCFBDecrypter returns a cipher.Stream which decrypts data with OpenPGP's | |||
// cipher feedback mode using the given cipher.Block. Prefix must be the first | |||
// blockSize + 2 bytes of the ciphertext, where blockSize is the cipher.Block's | |||
// block size. On successful exit, blockSize+2 bytes of decrypted data are written into | |||
// prefix. Resync determines if the "resynchronization step" from RFC 4880, | |||
// 13.9 step 7 is performed. Different parts of OpenPGP vary on this point. | |||
func NewOCFBDecrypter(block cipher.Block, prefix []byte, resync OCFBResyncOption) cipher.Stream { | |||
blockSize := block.BlockSize() | |||
if len(prefix) != blockSize+2 { | |||
return nil | |||
} | |||
x := &ocfbDecrypter{ | |||
b: block, | |||
fre: make([]byte, blockSize), | |||
outUsed: 0, | |||
} | |||
prefixCopy := make([]byte, len(prefix)) | |||
copy(prefixCopy, prefix) | |||
block.Encrypt(x.fre, x.fre) | |||
for i := 0; i < blockSize; i++ { | |||
prefixCopy[i] ^= x.fre[i] | |||
} | |||
block.Encrypt(x.fre, prefix[:blockSize]) | |||
prefixCopy[blockSize] ^= x.fre[0] | |||
prefixCopy[blockSize+1] ^= x.fre[1] | |||
if resync { | |||
block.Encrypt(x.fre, prefix[2:]) | |||
} else { | |||
x.fre[0] = prefix[blockSize] | |||
x.fre[1] = prefix[blockSize+1] | |||
x.outUsed = 2 | |||
} | |||
copy(prefix, prefixCopy) | |||
return x | |||
} | |||
func (x *ocfbDecrypter) XORKeyStream(dst, src []byte) { | |||
for i := 0; i < len(src); i++ { | |||
if x.outUsed == len(x.fre) { | |||
x.b.Encrypt(x.fre, x.fre) | |||
x.outUsed = 0 | |||
} | |||
c := src[i] | |||
dst[i] = x.fre[x.outUsed] ^ src[i] | |||
x.fre[x.outUsed] = c | |||
x.outUsed++ | |||
} | |||
} |
@@ -0,0 +1,73 @@ | |||
// Copyright 2011 The Go Authors. All rights reserved. | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
package packet | |||
import ( | |||
"crypto" | |||
"encoding/binary" | |||
"github.com/ProtonMail/go-crypto/openpgp/errors" | |||
"github.com/ProtonMail/go-crypto/openpgp/internal/algorithm" | |||
"io" | |||
"strconv" | |||
) | |||
// OnePassSignature represents a one-pass signature packet. See RFC 4880, | |||
// section 5.4. | |||
type OnePassSignature struct { | |||
SigType SignatureType | |||
Hash crypto.Hash | |||
PubKeyAlgo PublicKeyAlgorithm | |||
KeyId uint64 | |||
IsLast bool | |||
} | |||
const onePassSignatureVersion = 3 | |||
func (ops *OnePassSignature) parse(r io.Reader) (err error) { | |||
var buf [13]byte | |||
_, err = readFull(r, buf[:]) | |||
if err != nil { | |||
return | |||
} | |||
if buf[0] != onePassSignatureVersion { | |||
err = errors.UnsupportedError("one-pass-signature packet version " + strconv.Itoa(int(buf[0]))) | |||
} | |||
var ok bool | |||
ops.Hash, ok = algorithm.HashIdToHashWithSha1(buf[2]) | |||
if !ok { | |||
return errors.UnsupportedError("hash function: " + strconv.Itoa(int(buf[2]))) | |||
} | |||
ops.SigType = SignatureType(buf[1]) | |||
ops.PubKeyAlgo = PublicKeyAlgorithm(buf[3]) | |||
ops.KeyId = binary.BigEndian.Uint64(buf[4:12]) | |||
ops.IsLast = buf[12] != 0 | |||
return | |||
} | |||
// Serialize marshals the given OnePassSignature to w. | |||
func (ops *OnePassSignature) Serialize(w io.Writer) error { | |||
var buf [13]byte | |||
buf[0] = onePassSignatureVersion | |||
buf[1] = uint8(ops.SigType) | |||
var ok bool | |||
buf[2], ok = algorithm.HashToHashIdWithSha1(ops.Hash) | |||
if !ok { | |||
return errors.UnsupportedError("hash type: " + strconv.Itoa(int(ops.Hash))) | |||
} | |||
buf[3] = uint8(ops.PubKeyAlgo) | |||
binary.BigEndian.PutUint64(buf[4:12], ops.KeyId) | |||
if ops.IsLast { | |||
buf[12] = 1 | |||
} | |||
if err := serializeHeader(w, packetTypeOnePassSignature, len(buf)); err != nil { | |||
return err | |||
} | |||
_, err := w.Write(buf[:]) | |||
return err | |||
} |
Dear OpenI User
Thank you for your continuous support to the Openl Qizhi Community AI Collaboration Platform. In order to protect your usage rights and ensure network security, we updated the Openl Qizhi Community AI Collaboration Platform Usage Agreement in January 2024. The updated agreement specifies that users are prohibited from using intranet penetration tools. After you click "Agree and continue", you can continue to use our services. Thank you for your cooperation and understanding.
For more agreement content, please refer to the《Openl Qizhi Community AI Collaboration Platform Usage Agreement》