Vendor Update (#16121)
* update github.com/PuerkitoBio/goquery * update github.com/alecthomas/chroma * update github.com/blevesearch/bleve/v2 * update github.com/caddyserver/certmagic * update github.com/go-enry/go-enry/v2 * update github.com/go-git/go-billy/v5 * update github.com/go-git/go-git/v5 * update github.com/go-redis/redis/v8 * update github.com/go-testfixtures/testfixtures/v3 * update github.com/jaytaylor/html2text * update github.com/json-iterator/go * update github.com/klauspost/compress * update github.com/markbates/goth * update github.com/mattn/go-isatty * update github.com/mholt/archiver/v3 * update github.com/microcosm-cc/bluemonday * update github.com/minio/minio-go/v7 * update github.com/prometheus/client_golang * update github.com/unrolled/render * update github.com/xanzy/go-gitlab * update github.com/yuin/goldmark * update github.com/yuin/goldmark-highlighting Co-authored-by: techknowlogick <techknowlogick@gitea.io>
This commit is contained in:
		
							parent
							
								
									f088dc4ea1
								
							
						
					
					
						commit
						86e2789960
					
				
							
								
								
									
										73
									
								
								go.mod
								
								
								
								
							
							
						
						
									
										73
									
								
								go.mod
								
								
								
								
							|  | @ -11,24 +11,25 @@ require ( | |||
| 	gitea.com/go-chi/captcha v0.0.0-20210110083842-e7696c336a1e | ||||
| 	gitea.com/go-chi/session v0.0.0-20210108030337-0cb48c5ba8ee | ||||
| 	gitea.com/lunny/levelqueue v0.3.0 | ||||
| 	github.com/Microsoft/go-winio v0.4.18 // indirect | ||||
| 	github.com/Microsoft/go-winio v0.5.0 // indirect | ||||
| 	github.com/NYTimes/gziphandler v1.1.1 | ||||
| 	github.com/PuerkitoBio/goquery v1.5.1 | ||||
| 	github.com/RoaringBitmap/roaring v0.6.0 // indirect | ||||
| 	github.com/alecthomas/chroma v0.8.2 | ||||
| 	github.com/andybalholm/brotli v1.0.1 // indirect | ||||
| 	github.com/ProtonMail/go-crypto v0.0.0-20210512092938-c05353c2d58c // indirect | ||||
| 	github.com/PuerkitoBio/goquery v1.6.1 | ||||
| 	github.com/RoaringBitmap/roaring v0.7.3 // indirect | ||||
| 	github.com/alecthomas/chroma v0.9.1 | ||||
| 	github.com/andybalholm/brotli v1.0.3 // indirect | ||||
| 	github.com/andybalholm/cascadia v1.2.0 // indirect | ||||
| 	github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect | ||||
| 	github.com/blevesearch/bleve/v2 v2.0.3 | ||||
| 	github.com/blevesearch/bleve/v2 v2.0.5 | ||||
| 	github.com/boombuler/barcode v1.0.1 // indirect | ||||
| 	github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b // indirect | ||||
| 	github.com/caddyserver/certmagic v0.13.0 | ||||
| 	github.com/caddyserver/certmagic v0.13.1 | ||||
| 	github.com/chi-middleware/proxy v1.1.1 | ||||
| 	github.com/couchbase/go-couchbase v0.0.0-20210224140812-5740cd35f448 // indirect | ||||
| 	github.com/couchbase/gomemcached v0.1.2 // indirect | ||||
| 	github.com/couchbase/goutils v0.0.0-20210118111533-e33d3ffb5401 // indirect | ||||
| 	github.com/denisenkom/go-mssqldb v0.10.0 | ||||
| 	github.com/dgrijalva/jwt-go v3.2.0+incompatible | ||||
| 	github.com/dlclark/regexp2 v1.4.0 // indirect | ||||
| 	github.com/dustin/go-humanize v1.0.0 | ||||
| 	github.com/editorconfig/editorconfig-core-go/v2 v2.4.2 | ||||
| 	github.com/emirpasic/gods v1.12.0 | ||||
|  | @ -37,14 +38,14 @@ require ( | |||
| 	github.com/go-asn1-ber/asn1-ber v1.5.3 // indirect | ||||
| 	github.com/go-chi/chi v1.5.4 | ||||
| 	github.com/go-chi/cors v1.2.0 | ||||
| 	github.com/go-enry/go-enry/v2 v2.6.1 | ||||
| 	github.com/go-git/go-billy/v5 v5.1.0 | ||||
| 	github.com/go-git/go-git/v5 v5.3.0 | ||||
| 	github.com/go-enry/go-enry/v2 v2.7.0 | ||||
| 	github.com/go-git/go-billy/v5 v5.3.1 | ||||
| 	github.com/go-git/go-git/v5 v5.4.2 | ||||
| 	github.com/go-ldap/ldap/v3 v3.3.0 | ||||
| 	github.com/go-redis/redis/v8 v8.8.2 | ||||
| 	github.com/go-redis/redis/v8 v8.10.0 | ||||
| 	github.com/go-sql-driver/mysql v1.6.0 | ||||
| 	github.com/go-swagger/go-swagger v0.27.0 | ||||
| 	github.com/go-testfixtures/testfixtures/v3 v3.6.0 | ||||
| 	github.com/go-testfixtures/testfixtures/v3 v3.6.1 | ||||
| 	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 | ||||
|  | @ -56,26 +57,28 @@ require ( | |||
| 	github.com/gorilla/mux v1.8.0 // indirect | ||||
| 	github.com/gorilla/sessions v1.2.1 // indirect | ||||
| 	github.com/hashicorp/go-cleanhttp v0.5.2 // indirect | ||||
| 	github.com/hashicorp/go-retryablehttp v0.7.0 // indirect | ||||
| 	github.com/hashicorp/go-version v1.3.1 | ||||
| 	github.com/huandu/xstrings v1.3.2 | ||||
| 	github.com/issue9/identicon v1.2.0 | ||||
| 	github.com/jaytaylor/html2text v0.0.0-20200412013138-3577fbdbcff7 | ||||
| 	github.com/json-iterator/go v1.1.10 | ||||
| 	github.com/json-iterator/go v1.1.11 | ||||
| 	github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 | ||||
| 	github.com/kevinburke/ssh_config v1.1.0 // indirect | ||||
| 	github.com/keybase/go-crypto v0.0.0-20200123153347-de78d2cb44f4 | ||||
| 	github.com/klauspost/compress v1.12.1 | ||||
| 	github.com/klauspost/compress v1.13.0 | ||||
| 	github.com/klauspost/pgzip v1.2.5 // indirect | ||||
| 	github.com/lafriks/xormstore v1.4.0 | ||||
| 	github.com/lib/pq v1.10.1 | ||||
| 	github.com/lib/pq v1.10.2 | ||||
| 	github.com/libdns/libdns v0.2.1 // indirect | ||||
| 	github.com/lunny/dingtalk_webhook v0.0.0-20171025031554-e3534c89ef96 | ||||
| 	github.com/markbates/goth v1.67.1 | ||||
| 	github.com/mattn/go-isatty v0.0.12 | ||||
| 	github.com/mattn/go-runewidth v0.0.12 // indirect | ||||
| 	github.com/mattn/go-isatty v0.0.13 | ||||
| 	github.com/mattn/go-runewidth v0.0.13 // indirect | ||||
| 	github.com/mattn/go-sqlite3 v1.14.7 | ||||
| 	github.com/mholt/archiver/v3 v3.5.0 | ||||
| 	github.com/microcosm-cc/bluemonday v1.0.8 | ||||
| 	github.com/miekg/dns v1.1.40 // indirect | ||||
| 	github.com/microcosm-cc/bluemonday v1.0.9 | ||||
| 	github.com/miekg/dns v1.1.42 // indirect | ||||
| 	github.com/minio/md5-simd v1.1.2 // indirect | ||||
| 	github.com/minio/minio-go/v7 v7.0.10 | ||||
| 	github.com/minio/sha256-simd v1.0.0 // indirect | ||||
|  | @ -87,12 +90,12 @@ require ( | |||
| 	github.com/oliamb/cutter v0.2.2 | ||||
| 	github.com/olivere/elastic/v7 v7.0.24 | ||||
| 	github.com/pelletier/go-toml v1.9.0 // indirect | ||||
| 	github.com/pierrec/lz4/v4 v4.1.3 // indirect | ||||
| 	github.com/pierrec/lz4/v4 v4.1.7 // indirect | ||||
| 	github.com/pkg/errors v0.9.1 | ||||
| 	github.com/pquerna/otp v1.3.0 | ||||
| 	github.com/prometheus/client_golang v1.10.0 | ||||
| 	github.com/prometheus/client_golang v1.11.0 | ||||
| 	github.com/quasoft/websspi v1.0.0 | ||||
| 	github.com/rivo/uniseg v0.2.0 // indirect | ||||
| 	github.com/rs/xid v1.3.0 // indirect | ||||
| 	github.com/russross/blackfriday/v2 v2.1.0 // indirect | ||||
| 	github.com/sergi/go-diff v1.2.0 | ||||
| 	github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 // indirect | ||||
|  | @ -105,24 +108,24 @@ require ( | |||
| 	github.com/unknwon/com v1.0.1 | ||||
| 	github.com/unknwon/i18n v0.0.0-20210321134014-0ebbf2df1c44 | ||||
| 	github.com/unknwon/paginater v0.0.0-20200328080006-042474bd0eae | ||||
| 	github.com/unrolled/render v1.1.1 | ||||
| 	github.com/unrolled/render v1.4.0 | ||||
| 	github.com/urfave/cli v1.22.5 | ||||
| 	github.com/willf/bitset v1.1.11 // indirect | ||||
| 	github.com/xanzy/go-gitlab v0.48.0 | ||||
| 	github.com/xanzy/go-gitlab v0.50.0 | ||||
| 	github.com/yohcop/openid-go v1.0.0 | ||||
| 	github.com/yuin/goldmark v1.3.5 | ||||
| 	github.com/yuin/goldmark-highlighting v0.0.0-20200307114337-60d527fdb691 | ||||
| 	github.com/yuin/goldmark v1.3.7 | ||||
| 	github.com/yuin/goldmark-highlighting v0.0.0-20210516132338-9216f9c5aa01 | ||||
| 	github.com/yuin/goldmark-meta v1.0.0 | ||||
| 	go.etcd.io/bbolt v1.3.6 // indirect | ||||
| 	go.jolheiser.com/hcaptcha v0.0.4 | ||||
| 	go.jolheiser.com/pwn v0.0.3 | ||||
| 	go.uber.org/multierr v1.6.0 // indirect | ||||
| 	go.uber.org/zap v1.16.0 // indirect | ||||
| 	golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b | ||||
| 	golang.org/x/net v0.0.0-20210421230115-4e50805a0758 | ||||
| 	golang.org/x/oauth2 v0.0.0-20210413134643-5e61552d6c78 | ||||
| 	golang.org/x/sys v0.0.0-20210421221651-33663a62ff08 | ||||
| 	go.uber.org/multierr v1.7.0 // indirect | ||||
| 	go.uber.org/zap v1.17.0 // indirect | ||||
| 	golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a | ||||
| 	golang.org/x/net v0.0.0-20210525063256-abc453219eb5 | ||||
| 	golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c | ||||
| 	golang.org/x/sys v0.0.0-20210608053332-aa57babbf139 | ||||
| 	golang.org/x/text v0.3.6 | ||||
| 	golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba // indirect | ||||
| 	golang.org/x/time v0.0.0-20210608053304-ed9ce3a009e4 // indirect | ||||
| 	golang.org/x/tools v0.1.0 | ||||
| 	gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect | ||||
| 	gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df | ||||
|  |  | |||
							
								
								
									
										339
									
								
								go.sum
								
								
								
								
							
							
						
						
									
										339
									
								
								go.sum
								
								
								
								
							|  | @ -57,48 +57,44 @@ github.com/6543/go-version v1.3.1 h1:HvOp+Telns7HWJ2Xo/05YXQSB2bE0WmVgbHqwMPZT4U | |||
| github.com/6543/go-version v1.3.1/go.mod h1:oqFAHCwtLVUTLdhQmVZWYvaHXTdsbB4SY85at64SQEo= | ||||
| github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c h1:/IBSNwUN8+eKzUzbJPqhK839ygXJ82sde8x3ogr6R28= | ||||
| github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= | ||||
| 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/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0= | ||||
| github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0= | ||||
| github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= | ||||
| github.com/Julusian/godocdown v0.0.0-20170816220326-6d19f8ff2df8/go.mod h1:INZr5t32rG59/5xeltqoCJoNY7e5x/3xoY9WSWVWg74= | ||||
| github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= | ||||
| github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= | ||||
| github.com/Microsoft/go-winio v0.4.18 h1:yjwCO1nhWEShaA5qsmPOBzAOjRCa2PRLsDNZ5yBWXpg= | ||||
| github.com/Microsoft/go-winio v0.4.18/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= | ||||
| github.com/Microsoft/go-winio v0.5.0 h1:Elr9Wn+sGKPlkaBvwu4mTrxtmOp3F3yV9qhaHbXGjwU= | ||||
| github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= | ||||
| github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= | ||||
| github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= | ||||
| github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= | ||||
| github.com/PuerkitoBio/goquery v1.5.1 h1:PSPBGne8NIUWw+/7vFBV+kG2J/5MOjbzc7154OaKCSE= | ||||
| github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= | ||||
| github.com/ProtonMail/go-crypto v0.0.0-20210512092938-c05353c2d58c h1:bNpaLLv2Y4kslsdkdCwAYu8Bak1aGVtxwi8Z/wy4Yuo= | ||||
| github.com/ProtonMail/go-crypto v0.0.0-20210512092938-c05353c2d58c/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= | ||||
| github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc= | ||||
| github.com/PuerkitoBio/goquery v1.6.1 h1:FgjbQZKl5HTmcn4sKBgvx8vv63nhyhIpv7lJpFGCWpk= | ||||
| github.com/PuerkitoBio/goquery v1.6.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc= | ||||
| github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= | ||||
| github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= | ||||
| github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= | ||||
| github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= | ||||
| github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= | ||||
| github.com/RoaringBitmap/roaring v0.4.23/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06Mq5mKs52e1TwOo= | ||||
| github.com/RoaringBitmap/roaring v0.6.0 h1:tZcn2nJpUrZf+xQY8x+9QY7BxSETMjkdNG4Ts5zahyU= | ||||
| github.com/RoaringBitmap/roaring v0.6.0/go.mod h1:WZ83fjBF/7uBHi6QoFyfGL4+xuV4Qn+xFkm4+vSzrhE= | ||||
| 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/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= | ||||
| github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= | ||||
| github.com/RoaringBitmap/roaring v0.7.1/go.mod h1:jdT9ykXwHFNdJbEtxePexlFYH9LXucApeS0/+/g+p1I= | ||||
| github.com/RoaringBitmap/roaring v0.7.3 h1:RwirWpvFONt2EwHHEHhER7S4BHZkyj3qL5LXLlnQPZ4= | ||||
| github.com/RoaringBitmap/roaring v0.7.3/go.mod h1:jdT9ykXwHFNdJbEtxePexlFYH9LXucApeS0/+/g+p1I= | ||||
| github.com/acomagu/bufpipe v1.0.3 h1:fxAGrHZTgQ9w5QqVItgzwj235/uYZYgbXitB+dLupOk= | ||||
| github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= | ||||
| github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= | ||||
| github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= | ||||
| 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/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38 h1:smF2tmSOzy2Mm+0dGI2AIUHY+w0BUc+4tn40djz7+6U= | ||||
| github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38/go.mod h1:r7bzyVFMNntcxPZXK3/+KdruV1H5KSlyVY0gc+NgInI= | ||||
| github.com/alecthomas/chroma v0.7.2-0.20200305040604-4f3623dce67a/go.mod h1:fv5SzZPFJbwp2NXJWpFIX7DZS4HgV1K4ew4Pc2OZD9s= | ||||
| github.com/alecthomas/chroma v0.8.2 h1:x3zkuE2lUk/RIekyAJ3XRqSCP4zwWDfcw/YJCuCAACg= | ||||
| github.com/alecthomas/chroma v0.8.2/go.mod h1:sko8vR34/90zvl5QdcUdvzL3J8NKjAUx9va9jPuFNoM= | ||||
| github.com/alecthomas/chroma v0.9.1 h1:cBmvQqRImzR5aWqdMxYZByND4S7BCS/g0svZb28h0Dc= | ||||
| github.com/alecthomas/chroma v0.9.1/go.mod h1:eMuEnpA18XbG/WhOWtCzJHS7WqEtDAI+HxdwoW0nVSk= | ||||
| github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721 h1:JHZL0hZKJ1VENNfmXvHbgYlbUOvpzYzvy2aZU5gXVeo= | ||||
| github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721/go.mod h1:QO9JBoKquHd+jz9nshCh40fOfO+JzsoXy8qTHF68zU0= | ||||
| github.com/alecthomas/kong v0.1.17-0.20190424132513-439c674f7ae0/go.mod h1:+inYUSluD+p4L8KdviBSgzcqEjUQOfC5fQDRFuc36lI= | ||||
| github.com/alecthomas/kong v0.2.1-0.20190708041108-0548c6b1afae/go.mod h1:+inYUSluD+p4L8KdviBSgzcqEjUQOfC5fQDRFuc36lI= | ||||
| github.com/alecthomas/kong v0.2.4/go.mod h1:kQOmtJgV+Lb4aj+I2LEn40cbtawdWJ9Y8QLq+lElKxE= | ||||
| github.com/alecthomas/kong-hcl v0.1.8-0.20190615233001-b21fea9723c8/go.mod h1:MRgZdU3vrFd05IQ89AxUZ0aYdF39BYoNFa324SodPCA= | ||||
| github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897 h1:p9Sln00KOTlrYkxI1zYWl1QLnEqAqEARBEYa8FQnQcY= | ||||
| github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ= | ||||
| github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= | ||||
|  | @ -108,22 +104,20 @@ github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRF | |||
| github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= | ||||
| github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= | ||||
| github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= | ||||
| github.com/andybalholm/brotli v1.0.1 h1:KqhlKozYbRtJvsPrrEeXcO+N2l6NYT5A2QAFmSULpEc= | ||||
| github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= | ||||
| github.com/andybalholm/cascadia v1.1.0 h1:BuuO6sSfQNFRu1LppgbD25Hr2vLYW25JvxHs5zzsLTo= | ||||
| github.com/andybalholm/brotli v1.0.3 h1:fpcw+r1N1h0Poc1F/pHbW40cUm/lMEQslZtCkBQ0UnM= | ||||
| github.com/andybalholm/brotli v1.0.3/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= | ||||
| github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= | ||||
| github.com/andybalholm/cascadia v1.2.0 h1:vuRCkM5Ozh/BfmsaTm26kbjm0mIOM3yS5Ek/F5h18aE= | ||||
| github.com/andybalholm/cascadia v1.2.0/go.mod h1:YCyR8vOZT9aZ1CHEd8ap0gMVm2aFgxBp0T0eFw1RUQY= | ||||
| 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/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= | ||||
| github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= | ||||
| github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= | ||||
| github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= | ||||
| github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= | ||||
| 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/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= | ||||
| github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= | ||||
| github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= | ||||
| github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= | ||||
|  | @ -131,11 +125,8 @@ github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535/go.mod h1:o | |||
| github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= | ||||
| github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl3/e6D5CLfI0j/7hiIEtvGVFPCZ7Ei2oq8iQ= | ||||
| github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= | ||||
| github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= | ||||
| github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= | ||||
| github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48= | ||||
| github.com/aws/aws-sdk-go v1.38.3/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= | ||||
| github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= | ||||
| github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= | ||||
| github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= | ||||
| github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= | ||||
|  | @ -144,10 +135,13 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= | |||
| github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= | ||||
| github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= | ||||
| github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= | ||||
| github.com/bits-and-blooms/bitset v1.1.10/go.mod h1:w0XsmFg8qg6cmpTtJ0z3pKgjTDBMMnI/+I2syrE6XBE= | ||||
| github.com/bits-and-blooms/bitset v1.2.0 h1:Kn4yilvwNtMACtf1eYDlG8H77R07mZSPbMjLyS07ChA= | ||||
| github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= | ||||
| github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= | ||||
| github.com/blevesearch/bleve/v2 v2.0.1/go.mod h1:OBP2Pktqik8vEiUlGhuWjYx7KiO4zD542+DHqICwM5w= | ||||
| github.com/blevesearch/bleve/v2 v2.0.3 h1:mDrwrsRIA4PDYkfUNjoh5zGECvquuJIA3MJU5ivaO8E= | ||||
| github.com/blevesearch/bleve/v2 v2.0.3/go.mod h1:ip+4iafiEq2gCY5rJXe87bT6LkF/OJMCjQEYIfTBfW8= | ||||
| github.com/blevesearch/bleve/v2 v2.0.5 h1:184yM7uei4Cmw2SdKSdMWYg46OFRKsr+s8hBYc2FbuU= | ||||
| github.com/blevesearch/bleve/v2 v2.0.5/go.mod h1:ZjWibgnbRX33c+vBRgla9QhPb4QOjD6fdVJ+R1Bk8LM= | ||||
| github.com/blevesearch/bleve_index_api v1.0.0 h1:Ds3XeuTxjXCkG6pgIwWDRyooJKNIuOKemnN0N0IkhTU= | ||||
| github.com/blevesearch/bleve_index_api v1.0.0/go.mod h1:fiwKS0xLEm+gBRgv5mumf0dhgFr2mDgZah1pqv1c1M4= | ||||
| github.com/blevesearch/go-porterstemmer v1.0.3 h1:GtmsqID0aZdCSNiY8SkuPJ12pD4jI+DdXTAn4YRcHCo= | ||||
|  | @ -164,8 +158,9 @@ github.com/blevesearch/snowballstem v0.9.0 h1:lMQ189YspGP6sXvZQ4WZ+MLawfV8wOmPoD | |||
| github.com/blevesearch/snowballstem v0.9.0/go.mod h1:PivSj3JMc8WuaFkTSRDW2SlrulNWPl4ABg1tC/hlgLs= | ||||
| github.com/blevesearch/upsidedown_store_api v1.0.1 h1:1SYRwyoFLwG3sj0ed89RLtM15amfX2pXlYbFOnF8zNU= | ||||
| github.com/blevesearch/upsidedown_store_api v1.0.1/go.mod h1:MQDVGpHZrpe3Uy26zJBf/a8h0FZY6xJbthIMm8myH2Q= | ||||
| github.com/blevesearch/vellum v1.0.3 h1:U86G41A7CtXNzzpIJHM8lSTUqz1Mp8U870TkcdCzZc8= | ||||
| github.com/blevesearch/vellum v1.0.3/go.mod h1:2u5ax02KeDuNWu4/C+hVQMD6uLN4txH1JbtpaDNLJRo= | ||||
| github.com/blevesearch/vellum v1.0.4 h1:o6t7NxTnThp1es52uQvOJJx+9yK/nKXlWC5xl4LCz1U= | ||||
| github.com/blevesearch/vellum v1.0.4/go.mod h1:cMhywHI0de50f7Nj42YgvyD6bFJ2WkNRvNBlNMrEVgY= | ||||
| github.com/blevesearch/zapx/v11 v11.1.10/go.mod h1:DTjbcBqrr/Uo82UBilDC8lEew42gN/OcIyiTNFtSijc= | ||||
| github.com/blevesearch/zapx/v11 v11.2.0 h1:GBkCJYsyj3eIU4+aiLPxoMz1PYvDbQZl/oXHIBZIP60= | ||||
| github.com/blevesearch/zapx/v11 v11.2.0/go.mod h1:gN/a0alGw1FZt/YGTo1G6Z6XpDkeOfujX5exY9sCQQM= | ||||
|  | @ -187,10 +182,8 @@ github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl | |||
| github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= | ||||
| github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b h1:L/QXpzIa3pOvUGt1D1lA5KjYhPBAN/3iWdP7xeFS9F0= | ||||
| github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= | ||||
| github.com/caddyserver/certmagic v0.13.0 h1:ky0rntZvIFiUKFdIikYxj31WN+Ts0Od6Wjz83iTzxfc= | ||||
| github.com/caddyserver/certmagic v0.13.0/go.mod h1:dNOzF4iOB7H9E51xTooMB90vs+2XNVtpnx0liQNsQY4= | ||||
| github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= | ||||
| github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= | ||||
| github.com/caddyserver/certmagic v0.13.1 h1:A5qLxh9J6/CYWEOHaj135IWAjCY0193ONxEy8jbOlPw= | ||||
| github.com/caddyserver/certmagic v0.13.1/go.mod h1:+zhQtEgLOyXRA/KRduHXNhGGdTeqRM4ePj8eBGD/2CQ= | ||||
| github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= | ||||
| github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= | ||||
| github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= | ||||
|  | @ -201,15 +194,12 @@ github.com/chi-middleware/proxy v1.1.1/go.mod h1:jQwMEJct2tz9VmtCELxvnXoMfa+SOdi | |||
| github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= | ||||
| github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= | ||||
| github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= | ||||
| github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= | ||||
| github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= | ||||
| github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= | ||||
| github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= | ||||
| github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= | ||||
| github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= | ||||
| github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= | ||||
| github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= | ||||
| github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= | ||||
| github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= | ||||
| github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= | ||||
| github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= | ||||
|  | @ -217,10 +207,8 @@ github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8Nz | |||
| github.com/coreos/go-oidc v2.2.1+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= | ||||
| github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= | ||||
| github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= | ||||
| github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= | ||||
| github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= | ||||
| github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= | ||||
| github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= | ||||
| github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= | ||||
| github.com/couchbase/ghistogram v0.1.0/go.mod h1:s1Jhy76zqfEecpNWJfWUiKZookAFaiGOEoyzgHt9i7k= | ||||
| github.com/couchbase/go-couchbase v0.0.0-20201026062457-7b3be89bbd89/go.mod h1:+/bddYDxXsf9qt0xpDUtRR47A2GjaXmGGAqQ/k3GJ8A= | ||||
|  | @ -242,13 +230,11 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsr | |||
| github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= | ||||
| 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/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E= | ||||
| github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 h1:y5HC9v93H5EPKqaS1UYVg1uYah5Xf51mBfIoWehClUQ= | ||||
| github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964/go.mod h1:Xd9hchkHSWYkEqJwUGisez3G1QY8Ryz0sdWrLPMGjLk= | ||||
| 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/denisenkom/go-mssqldb v0.0.0-20191128021309-1d7a30a10f73/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= | ||||
| github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= | ||||
| github.com/denisenkom/go-mssqldb v0.9.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= | ||||
| github.com/denisenkom/go-mssqldb v0.10.0 h1:QykgLZBorFE95+gO3u9esLd0BmbvpWp0/waNNZfHBM8= | ||||
|  | @ -267,20 +253,15 @@ github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDD | |||
| github.com/dsnet/compress v0.0.1 h1:PlZu0n3Tuv04TzpfPbrnI0HW/YwodEXDS+oPKahKF0Q= | ||||
| github.com/dsnet/compress v0.0.1/go.mod h1:Aw8dCMJ7RioblQeTqt88akK31OvO8Dhf5JflhBbQEHo= | ||||
| github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY= | ||||
| github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= | ||||
| github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= | ||||
| github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= | ||||
| github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= | ||||
| github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= | ||||
| github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= | ||||
| github.com/dvyukov/go-fuzz v0.0.0-20210429054444-fca39067bc72/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw= | ||||
| github.com/editorconfig/editorconfig-core-go/v2 v2.4.2 h1:1lkDpSoAaFLrgYTVJ/eNCV+lkDSv/j9Wm0jcvDfVVEo= | ||||
| github.com/editorconfig/editorconfig-core-go/v2 v2.4.2/go.mod h1:IXeWRVO4LZRoNunhHh/oP6BQvTs94nB2pNvbw32l8tQ= | ||||
| github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= | ||||
| github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385 h1:clC1lXBpe2kTj2VHdaIu9ajZQe4kcEY9j0NsnDDBZ3o= | ||||
| github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= | ||||
| github.com/elazarl/go-bindata-assetfs v1.0.1/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4= | ||||
| 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/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= | ||||
| github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= | ||||
| github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= | ||||
| github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= | ||||
|  | @ -295,8 +276,6 @@ github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSw | |||
| 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= | ||||
| github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= | ||||
| github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= | ||||
| github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= | ||||
| github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= | ||||
| github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= | ||||
|  | @ -318,25 +297,25 @@ github.com/go-chi/chi/v5 v5.0.1 h1:ALxjCrTf1aflOlkhMnCUP86MubbWFrzB3gkRPReLpTo= | |||
| github.com/go-chi/chi/v5 v5.0.1/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= | ||||
| github.com/go-chi/cors v1.2.0 h1:tV1g1XENQ8ku4Bq3K9ub2AtgG+p16SmzeMSGTwrOKdE= | ||||
| github.com/go-chi/cors v1.2.0/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58= | ||||
| github.com/go-enry/go-enry/v2 v2.6.1 h1:ckFkMVj2NeHpaQDFDiSjanVjNy2IiuMNivhXDB4c5Q0= | ||||
| github.com/go-enry/go-enry/v2 v2.6.1/go.mod h1:GVzIiAytiS5uT/QiuakK7TF1u4xDab87Y8V5EJRpsIQ= | ||||
| github.com/go-enry/go-enry/v2 v2.7.0 h1:bcAZfvX0LmAEMl8OEd8MPsfJCN2Io4mNU1an1Hh48VA= | ||||
| github.com/go-enry/go-enry/v2 v2.7.0/go.mod h1:GVzIiAytiS5uT/QiuakK7TF1u4xDab87Y8V5EJRpsIQ= | ||||
| github.com/go-enry/go-oniguruma v1.2.1 h1:k8aAMuJfMrqm/56SG2lV9Cfti6tC4x8673aHCcBk+eo= | ||||
| github.com/go-enry/go-oniguruma v1.2.1/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/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= | ||||
| github.com/go-git/go-billy/v5 v5.1.0 h1:4pl5BV4o7ZG/lterP4S6WzJ6xr49Ba5ET9ygheTYahk= | ||||
| github.com/go-git/go-billy/v5 v5.1.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= | ||||
| github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12 h1:PbKy9zOy4aAKrJ5pibIRpVO2BXnK1Tlcg+caKI7Ox5M= | ||||
| github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw= | ||||
| github.com/go-git/go-git/v5 v5.3.0 h1:8WKMtJR2j8RntEXR/uvTKagfEt4GYlwQ7mntE4+0GWc= | ||||
| github.com/go-git/go-git/v5 v5.3.0/go.mod h1:xdX4bWJ48aOrdhnl2XqHYstHbbp6+LFS4r4X+lNVprw= | ||||
| github.com/go-git/go-billy/v5 v5.2.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= | ||||
| github.com/go-git/go-billy/v5 v5.3.1 h1:CPiOUAzKtMRvolEKw+bG1PLRpT7D3LIs3/3ey4Aiu34= | ||||
| github.com/go-git/go-billy/v5 v5.3.1/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= | ||||
| github.com/go-git/go-git-fixtures/v4 v4.2.1 h1:n9gGL1Ct/yIw+nfsfr8s4+sbhT+Ncu2SubfXjIWgci8= | ||||
| github.com/go-git/go-git-fixtures/v4 v4.2.1/go.mod h1:K8zd3kDUAykwTdDCr+I0per6Y6vMiRR/nnVTBtavnB0= | ||||
| github.com/go-git/go-git/v5 v5.4.2 h1:BXyZu9t0VkbiHtqrsvdq39UDhGJTl1h55VW6CSC4aY4= | ||||
| github.com/go-git/go-git/v5 v5.4.2/go.mod h1:gQ1kArt6d+n+BGd+/B/I74HwRTLhth2+zti4ihgckDc= | ||||
| github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= | ||||
| github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= | ||||
| github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= | ||||
| github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= | ||||
| github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= | ||||
| github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= | ||||
| github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= | ||||
| github.com/go-ldap/ldap/v3 v3.3.0 h1:lwx+SJpgOHd8tG6SumBQZXCmNX51zM8B1cfxJ5gv4tQ= | ||||
| github.com/go-ldap/ldap/v3 v3.3.0/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg= | ||||
| github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= | ||||
|  | @ -440,9 +419,8 @@ github.com/go-openapi/validate v0.20.2/go.mod h1:e7OJoKNgd0twXZwIn0A43tHbvIcr/rZ | |||
| 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-redis/redis/v8 v8.4.0/go.mod h1:A1tbYoHSa1fXwN+//ljcCYYJeLmVrwL9hbQN45Jdy0M= | ||||
| github.com/go-redis/redis/v8 v8.8.2 h1:O/NcHqobw7SEptA0yA6up6spZVFtwE06SXM8rgLtsP8= | ||||
| github.com/go-redis/redis/v8 v8.8.2/go.mod h1:F7resOH5Kdug49Otu24RjHWwgK7u9AmtqWMnCV1iP5Y= | ||||
| github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= | ||||
| github.com/go-redis/redis/v8 v8.10.0 h1:OZwrQKuZqdJ4QIM8wn8rnuz868Li91xA3J2DEq+TPGA= | ||||
| github.com/go-redis/redis/v8 v8.10.0/go.mod h1:vXLTvigok0VtUX0znvbcEW1SOt4OA9CU1ZfnOtKOaiM= | ||||
| github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= | ||||
| github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= | ||||
| github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= | ||||
|  | @ -453,8 +431,8 @@ github.com/go-swagger/go-swagger v0.27.0 h1:K7+nkBuf4oS1jTBrdvWqYFpqD69V5CN8HamZ | |||
| github.com/go-swagger/go-swagger v0.27.0/go.mod h1:WodZVysInJilkW7e6IRw+dZGp5yW6rlMFZ4cb+THl9A= | ||||
| github.com/go-swagger/scan-repo-boundary v0.0.0-20180623220736-973b3573c013 h1:l9rI6sNaZgNC0LnF3MiE+qTmyBA/tZAg1rtyrGbUMK0= | ||||
| github.com/go-swagger/scan-repo-boundary v0.0.0-20180623220736-973b3573c013/go.mod h1:b65mBPzqzZWxOZGxSWrqs4GInLIn+u99Q9q7p+GKni0= | ||||
| github.com/go-testfixtures/testfixtures/v3 v3.6.0 h1:fHrJWcZ0TOHA0UcExV0Nwx+5MR9QXVDWYdVfwe4DfmM= | ||||
| github.com/go-testfixtures/testfixtures/v3 v3.6.0/go.mod h1:YUBpgqvleDRhkx4MQbzdA7A3G5ca2wLtf9bHbDqNaRQ= | ||||
| github.com/go-testfixtures/testfixtures/v3 v3.6.1 h1:n4Fv95Exp0D05G6l6CAZv22Ck1EJK0pa0TfPqE4ncSs= | ||||
| github.com/go-testfixtures/testfixtures/v3 v3.6.1/go.mod h1:Bsb2MoHAfHnNsPpSwAjtOs102mqDuM+1u3nE2OCi0N0= | ||||
| github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= | ||||
| github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY= | ||||
| github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg= | ||||
|  | @ -483,9 +461,7 @@ github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= | |||
| github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= | ||||
| github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE= | ||||
| github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= | ||||
| github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= | ||||
| github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= | ||||
| github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= | ||||
| github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= | ||||
| github.com/gogs/chardet v0.0.0-20191104214054-4b6791f73a28 h1:gBeyun7mySAKWg7Fb0GOcv0upX9bdaZScs8QcRo8mEY= | ||||
| github.com/gogs/chardet v0.0.0-20191104214054-4b6791f73a28/go.mod h1:Pcatq5tYkCW2Q6yrR2VRHlbHpZ/R4/7qyL1TCF7vl14= | ||||
|  | @ -496,7 +472,6 @@ github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85/go.mod h1:fR6z | |||
| github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= | ||||
| github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= | ||||
| github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= | ||||
| github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= | ||||
| github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= | ||||
| github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= | ||||
| github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= | ||||
|  | @ -578,14 +553,11 @@ github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99 h1:twflg0XRTjwKp | |||
| github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= | ||||
| github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8= | ||||
| github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= | ||||
| github.com/gorilla/csrf v1.6.0/go.mod h1:7tSf8kmjNYr7IWDCYhd3U8Ck34iQ/Yw5CJu7bAkHEGI= | ||||
| github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= | ||||
| github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= | ||||
| github.com/gorilla/handlers v1.4.1/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= | ||||
| github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= | ||||
| github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= | ||||
| github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= | ||||
| github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= | ||||
| github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= | ||||
| github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= | ||||
| github.com/gorilla/pat v0.0.0-20180118222023-199c85a7f6d1 h1:LqbZZ9sNMWVjeXS4NN5oVvhMjDyLhmA1LG86oSo+IqY= | ||||
|  | @ -596,17 +568,12 @@ github.com/gorilla/sessions v1.1.1/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE | |||
| github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= | ||||
| github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI= | ||||
| github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= | ||||
| github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= | ||||
| github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= | ||||
| github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= | ||||
| github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= | ||||
| github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= | ||||
| github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= | ||||
| github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= | ||||
| github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= | ||||
| github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= | ||||
| github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= | ||||
| github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= | ||||
| github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= | ||||
| github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= | ||||
| github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= | ||||
|  | @ -616,8 +583,9 @@ github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrj | |||
| github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= | ||||
| github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= | ||||
| github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= | ||||
| github.com/hashicorp/go-retryablehttp v0.6.8 h1:92lWxgpa+fF3FozM4B3UZtHZMJX8T5XT+TFdCxsPyWs= | ||||
| github.com/hashicorp/go-retryablehttp v0.6.8/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= | ||||
| github.com/hashicorp/go-retryablehttp v0.7.0 h1:eu1EI/mbirUgP5C8hVsTNaGZreBDlYiwC1FZWkvQPQ4= | ||||
| github.com/hashicorp/go-retryablehttp v0.7.0/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= | ||||
| github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= | ||||
| github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= | ||||
| github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= | ||||
|  | @ -635,13 +603,11 @@ github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/J | |||
| github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= | ||||
| github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw= | ||||
| github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= | ||||
| github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= | ||||
| github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= | ||||
| github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= | ||||
| github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= | ||||
| github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= | ||||
| github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= | ||||
| github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= | ||||
| github.com/issue9/assert v1.4.1 h1:gUtOpMTeaE4JTe9kACma5foOHBvVt1p5XTFrULDwdXI= | ||||
| github.com/issue9/assert v1.4.1/go.mod h1:Yktk83hAVl1SPSYtd9kjhBizuiBIqUQyj+D5SE2yjVY= | ||||
| github.com/issue9/identicon v1.2.0 h1:ek+UcTTyMW/G0iNbLOAlrPC13eSzXTWhbJSs8PHhHGQ= | ||||
|  | @ -692,10 +658,8 @@ github.com/jaytaylor/html2text v0.0.0-20200412013138-3577fbdbcff7 h1:g0fAGBisHaE | |||
| github.com/jaytaylor/html2text v0.0.0-20200412013138-3577fbdbcff7/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk= | ||||
| 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/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/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= | ||||
| github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= | ||||
| github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= | ||||
| github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= | ||||
|  | @ -705,10 +669,9 @@ github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8Hm | |||
| github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= | ||||
| github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= | ||||
| github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= | ||||
| github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= | ||||
| github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= | ||||
| github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= | ||||
| github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= | ||||
| github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ= | ||||
| github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= | ||||
| github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= | ||||
| github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= | ||||
| github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= | ||||
|  | @ -731,16 +694,16 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o | |||
| github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= | ||||
| github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= | ||||
| github.com/klauspost/compress v1.10.10/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= | ||||
| github.com/klauspost/compress v1.12.1 h1:/+xsCsk06wE38cyiqOR/o7U2fSftcH72xD+BQXmja/g= | ||||
| github.com/klauspost/compress v1.12.1/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= | ||||
| github.com/klauspost/compress v1.13.0 h1:2T7tUoQrQT+fQWdaY5rjWztFGAFwbGD04iPJg90ZiOs= | ||||
| github.com/klauspost/compress v1.13.0/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= | ||||
| github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= | ||||
| github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= | ||||
| github.com/klauspost/cpuid v1.2.5/go.mod h1:bYW4mA6ZgKPob1/Dlai2LviZJO7KGI3uoWLd42rAQw4= | ||||
| github.com/klauspost/cpuid v1.3.1 h1:5JNjFYYQrZeKRJ0734q51WCEEn2huer72Dc7K+R/b6s= | ||||
| github.com/klauspost/cpuid v1.3.1/go.mod h1:bYW4mA6ZgKPob1/Dlai2LviZJO7KGI3uoWLd42rAQw4= | ||||
| github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= | ||||
| github.com/klauspost/cpuid/v2 v2.0.4 h1:g0I61F2K2DjRHz1cnxlkNSBIaePVoJIjjnHui8QHbiw= | ||||
| github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= | ||||
| github.com/klauspost/cpuid/v2 v2.0.6 h1:dQ5ueTiftKxp0gyjKSx5+8BtPWkyQbd95m8Gys/RarI= | ||||
| github.com/klauspost/cpuid/v2 v2.0.6/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= | ||||
| github.com/klauspost/pgzip v1.2.4/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= | ||||
| github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE= | ||||
| github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= | ||||
|  | @ -766,18 +729,15 @@ github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= | |||
| github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= | ||||
| github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= | ||||
| github.com/lib/pq v1.7.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= | ||||
| github.com/lib/pq v1.10.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= | ||||
| github.com/lib/pq v1.10.1 h1:6VXZrLU0jHBYyAqrSPa+MgPfnSvTPuMgK+k0o5kVFWo= | ||||
| github.com/lib/pq v1.10.1/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= | ||||
| github.com/libdns/libdns v0.2.0 h1:ewg3ByWrdUrxrje8ChPVMBNcotg7H9LQYg+u5De2RzI= | ||||
| github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8= | ||||
| github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= | ||||
| github.com/libdns/libdns v0.2.0/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40= | ||||
| github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= | ||||
| github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= | ||||
| github.com/libdns/libdns v0.2.1 h1:Wu59T7wSHRgtA0cfxC+n1c/e+O3upJGWytknkmFEDis= | ||||
| github.com/libdns/libdns v0.2.1/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40= | ||||
| github.com/lunny/dingtalk_webhook v0.0.0-20171025031554-e3534c89ef96 h1:uNwtsDp7ci48vBTTxDuwcoTXz4lwtDTe7TjCQ0noaWY= | ||||
| github.com/lunny/dingtalk_webhook v0.0.0-20171025031554-e3534c89ef96/go.mod h1:mmIfjCSQlGYXmJ95jFN84AkQFnVABtKuJL8IrzwvUKQ= | ||||
| 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/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= | ||||
| github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= | ||||
| github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= | ||||
| github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls= | ||||
|  | @ -795,6 +755,8 @@ github.com/markbates/goth v1.67.1 h1:gU5B0pzHVyhnJPwGynfFnkfvaQ39C1Sy+ewdl+bhAOw | |||
| github.com/markbates/goth v1.67.1/go.mod h1:EyLFHGU5ySr2GXRDyJH5nu2dA7parbC8QwIYW/rGcWg= | ||||
| github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= | ||||
| github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= | ||||
| 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.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= | ||||
| github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= | ||||
| github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= | ||||
|  | @ -805,12 +767,12 @@ github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd | |||
| github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= | ||||
| github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= | ||||
| github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= | ||||
| github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= | ||||
| github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= | ||||
| github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= | ||||
| github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1yA= | ||||
| github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= | ||||
| github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= | ||||
| github.com/mattn/go-runewidth v0.0.12 h1:Y41i/hVW3Pgwr8gV+J23B9YEY0zxjptBuCWEaxmAOow= | ||||
| github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= | ||||
| github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= | ||||
| github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= | ||||
| github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= | ||||
| github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus= | ||||
| github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= | ||||
|  | @ -822,12 +784,12 @@ github.com/mholt/acmez v0.1.3 h1:J7MmNIk4Qf9b8mAGqAh4XkNeowv3f1zW816yf4zt7Qk= | |||
| github.com/mholt/acmez v0.1.3/go.mod h1:8qnn8QA/Ewx8E3ZSsmscqsIjhhpxuy9vqdgbX2ceceM= | ||||
| github.com/mholt/archiver/v3 v3.5.0 h1:nE8gZIrw66cu4osS/U7UW7YDuGMHssxKutU8IfWxwWE= | ||||
| github.com/mholt/archiver/v3 v3.5.0/go.mod h1:qqTTPUK/HZPFgFQ/TJ3BzvTpF/dPtFVJXdQbCmeMxwc= | ||||
| github.com/microcosm-cc/bluemonday v1.0.8 h1:JGc6zQRHqlp+UlLrsbUbbp0mOaJLV44vvQmBSU0Sfj0= | ||||
| github.com/microcosm-cc/bluemonday v1.0.8/go.mod h1:HOT/6NaBlR0f9XlxD3zolN6Z3N8Lp4pvhp+jLS5ihnI= | ||||
| github.com/microcosm-cc/bluemonday v1.0.9 h1:dpCwruVKoyrULicJwhuY76jB+nIxRVKv/e248Vx/BXg= | ||||
| github.com/microcosm-cc/bluemonday v1.0.9/go.mod h1:B2riunDr9benLHghZB7hjIgdwSUzzs0pjCxFrWYEZFU= | ||||
| github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= | ||||
| github.com/miekg/dns v1.1.30/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= | ||||
| github.com/miekg/dns v1.1.40 h1:pyyPFfGMnciYUk/mXpKkVmeMQjfXqt3FAJ2hy7tPiLA= | ||||
| github.com/miekg/dns v1.1.40/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= | ||||
| github.com/miekg/dns v1.1.42 h1:gWGe42RGaIqXQZ+r3WUGEKBEtvPHY2SXo4dqixDNxuY= | ||||
| github.com/miekg/dns v1.1.42/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= | ||||
| github.com/minio/md5-simd v1.1.0/go.mod h1:XpBqgZULrMYD3R+M28PcmP0CkI7PEMzB3U77ZrKZ0Gw= | ||||
| github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34= | ||||
| github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM= | ||||
|  | @ -867,28 +829,17 @@ github.com/msteinert/pam v0.0.0-20201130170657-e61372126161 h1:XQ1+fYPzaWZCVdu1x | |||
| github.com/msteinert/pam v0.0.0-20201130170657-e61372126161/go.mod h1:np1wUFZ6tyoke22qDJZY40URn9Ae51gX7ljIWXN5TJs= | ||||
| github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= | ||||
| github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= | ||||
| github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= | ||||
| github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= | ||||
| github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= | ||||
| github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= | ||||
| github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= | ||||
| github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= | ||||
| github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= | ||||
| github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= | ||||
| github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= | ||||
| github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= | ||||
| github.com/niklasfasching/go-org v1.5.0 h1:V8IwoSPm/d61bceyWFxxnQLtlvNT+CjiYIhtZLdnMF0= | ||||
| github.com/niklasfasching/go-org v1.5.0/go.mod h1:sSb8ylwnAG+h8MGFDB3R1D5bxf8wA08REfhjShg3kjA= | ||||
| github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYXnNPJ8l7uZxf45rWW1a/uME32OF0rhiYGNQ2oF2E= | ||||
| github.com/nwaples/rardecode v1.1.0 h1:vSxaY8vQhOcVr4mm5e8XllHWTiM4JF507A0Katqw7MQ= | ||||
| github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= | ||||
| github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= | ||||
| github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= | ||||
| github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= | ||||
| github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= | ||||
| github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= | ||||
| github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= | ||||
| github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= | ||||
| github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= | ||||
| github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= | ||||
| github.com/oliamb/cutter v0.2.2 h1:Lfwkya0HHNU1YLnGv2hTkzHfasrSMkgv4Dn+5rmlk3k= | ||||
|  | @ -909,17 +860,7 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y | |||
| github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= | ||||
| github.com/onsi/gomega v1.10.5 h1:7n6FEkpFmfCoo2t+YYqXH0evK+a9ICQz0xcAy9dYcaQ= | ||||
| github.com/onsi/gomega v1.10.5/go.mod h1:gza4q3jKQJijlu05nKWRCW/GavJumGt8aNRxWg7mt48= | ||||
| github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= | ||||
| github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= | ||||
| github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= | ||||
| github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= | ||||
| github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= | ||||
| github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= | ||||
| github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA= | ||||
| github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= | ||||
| github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= | ||||
| github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= | ||||
| github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= | ||||
| github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= | ||||
| github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= | ||||
| github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= | ||||
|  | @ -928,19 +869,14 @@ github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAv | |||
| github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= | ||||
| github.com/pelletier/go-toml v1.9.0 h1:NOd0BRdOKpPf0SxkL3HxSQOG7rNh+4kl6PHcBPFs7Q0= | ||||
| github.com/pelletier/go-toml v1.9.0/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= | ||||
| github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= | ||||
| github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= | ||||
| github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= | ||||
| github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM8aXeqhl0I= | ||||
| github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= | ||||
| github.com/pierrec/lz4/v4 v4.0.3/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= | ||||
| github.com/pierrec/lz4/v4 v4.1.3 h1:/dvQpkb0o1pVlSgKNQqfkavlnXaIK+hJ0LXsKRUN9D4= | ||||
| github.com/pierrec/lz4/v4 v4.1.3/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= | ||||
| github.com/pierrec/lz4/v4 v4.1.7 h1:UDV9geJWhFIufAliH7HQlz9wP3JA0t748w+RwbWMLow= | ||||
| github.com/pierrec/lz4/v4 v4.1.7/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= | ||||
| 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= | ||||
| github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= | ||||
| github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= | ||||
| github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= | ||||
| github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||||
| github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||||
|  | @ -949,53 +885,45 @@ github.com/pquerna/cachecontrol v0.0.0-20201205024021-ac21108117ac/go.mod h1:hoL | |||
| github.com/pquerna/otp v1.3.0 h1:oJV/SkzR33anKXwQU3Of42rL4wbrffP4uvUf1SvS5Xs= | ||||
| github.com/pquerna/otp v1.3.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= | ||||
| github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= | ||||
| github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= | ||||
| github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= | ||||
| github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= | ||||
| github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= | ||||
| github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= | ||||
| github.com/prometheus/client_golang v1.10.0 h1:/o0BDeWzLWXNZ+4q5gXltUvaMpJqckTa+jTNoB+z4cg= | ||||
| github.com/prometheus/client_golang v1.10.0/go.mod h1:WJM3cc3yu7XKBKa/I8WeZm+V3eltZnBwfENSU7mdogU= | ||||
| github.com/prometheus/client_golang v1.11.0 h1:HNkLOAEQMIDv/K+04rukrLx6ch7msSRwf3/SASFAGtQ= | ||||
| github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= | ||||
| github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= | ||||
| github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= | ||||
| github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= | ||||
| github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= | ||||
| github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= | ||||
| github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= | ||||
| github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= | ||||
| github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= | ||||
| github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= | ||||
| github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= | ||||
| github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= | ||||
| github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= | ||||
| github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= | ||||
| github.com/prometheus/common v0.18.0 h1:WCVKW7aL6LEe1uryfI9dnEc2ZqNB1Fn0ok930v0iL1Y= | ||||
| github.com/prometheus/common v0.18.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= | ||||
| github.com/prometheus/common v0.26.0 h1:iMAkS2TDoNWnKM+Kopnx/8tnEStIfpYA0ur0xQzzhMQ= | ||||
| github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= | ||||
| github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= | ||||
| github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= | ||||
| github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= | ||||
| github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= | ||||
| github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= | ||||
| github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= | ||||
| github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= | ||||
| github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= | ||||
| github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= | ||||
| 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-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk= | ||||
| github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= | ||||
| github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= | ||||
| github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= | ||||
| github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= | ||||
| github.com/robertkrimen/godocdown v0.0.0-20130622164427-0bfa04905481/go.mod h1:C9WhFzY47SzYBIvzFqSvHIR6ROgDo4TtdTuRaOMjF/s= | ||||
| github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= | ||||
| github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= | ||||
| github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= | ||||
| github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= | ||||
| github.com/rogpeppe/go-internal v1.5.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= | ||||
| github.com/rs/xid v1.2.1 h1:mhH9Nq+C1fY2l1XIpgxIiUOfNpRBYH1kKcr+qfKgjRc= | ||||
| github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= | ||||
| github.com/rs/xid v1.3.0 h1:6NjYksEUlhurdVehpc7S7dk6DAmcKv8V9gG0FsVN2U4= | ||||
| github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= | ||||
| github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= | ||||
| github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= | ||||
| github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= | ||||
|  | @ -1004,7 +932,6 @@ github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD | |||
| github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= | ||||
| github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= | ||||
| github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= | ||||
| github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= | ||||
| github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= | ||||
| github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= | ||||
| github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= | ||||
|  | @ -1039,7 +966,6 @@ github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIK | |||
| github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= | ||||
| github.com/smartystreets/gunit v1.4.2/go.mod h1:ZjM1ozSIMJlAz/ay4SG8PeKF00ckUp+zMHZXV9/bvak= | ||||
| github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= | ||||
| github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= | ||||
| github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= | ||||
| github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= | ||||
| github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY= | ||||
|  | @ -1053,7 +979,6 @@ github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSW | |||
| github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= | ||||
| github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= | ||||
| github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= | ||||
| github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= | ||||
| github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= | ||||
| github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= | ||||
| github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= | ||||
|  | @ -1063,11 +988,9 @@ github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk= | |||
| github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= | ||||
| github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf h1:pvbZ0lM0XWPBqUKqFU8cmavspvIl9nulOYwdy6IFRRo= | ||||
| github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf/go.mod h1:RJID2RhlZKId02nZ62WenDCkgHFerpIOmW0iT7GKmXM= | ||||
| github.com/stephens2424/writerset v1.0.2/go.mod h1:aS2JhsMn6eA7e82oNmW4rfsgAOp9COBTTl8mzkwADnc= | ||||
| github.com/steveyen/gtreap v0.1.0 h1:CjhzTa274PyJLJuMZwIzCO1PfC00oRa8d1Kc78bFXJM= | ||||
| github.com/steveyen/gtreap v0.1.0/go.mod h1:kl/5J7XbrOmlIbYIXdRHDDE5QxHqpk0cmkT7Z4dM9/Y= | ||||
| github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= | ||||
| github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= | ||||
| github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= | ||||
| github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||||
| github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||||
| github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= | ||||
|  | @ -1085,7 +1008,6 @@ github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpP | |||
| github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= | ||||
| github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= | ||||
| github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= | ||||
| github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= | ||||
| github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= | ||||
| github.com/toqueteos/webbrowser v1.2.0 h1:tVP/gpK69Fx+qMJKsLE7TD8LuGWPnEV71wBN9rrstGQ= | ||||
| github.com/toqueteos/webbrowser v1.2.0/go.mod h1:XWoZq4cyp9WeUeak7w7LXRUQf1F1ATJMir8RTqb4ayM= | ||||
|  | @ -1103,20 +1025,14 @@ github.com/unknwon/i18n v0.0.0-20210321134014-0ebbf2df1c44 h1:7bSo/vjZKVYUoZfxpY | |||
| github.com/unknwon/i18n v0.0.0-20210321134014-0ebbf2df1c44/go.mod h1:+5rDk6sDGpl3azws3O+f+GpFSyN9GVr0K8cvQLQM2ZQ= | ||||
| github.com/unknwon/paginater v0.0.0-20200328080006-042474bd0eae h1:ihaXiJkaca54IaCSnEXtE/uSZOmPxKZhDfVLrzZLFDs= | ||||
| github.com/unknwon/paginater v0.0.0-20200328080006-042474bd0eae/go.mod h1:1fdkY6xxl6ExVs2QFv7R0F5IRZHKA8RahhB9fMC9RvM= | ||||
| github.com/unrolled/render v1.1.1 h1:FpzNzkvlJQIlVdVaqeVBGWiCS8gpbmjtrKpDmCn6p64= | ||||
| github.com/unrolled/render v1.1.1/go.mod h1:gN9T0NhL4Bfbwu8ann7Ry/TGHYfosul+J0obPf6NBdM= | ||||
| github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= | ||||
| github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= | ||||
| github.com/unrolled/render v1.4.0 h1:p73obhpsXuE3paXOtcuXTBKgBJpLCfmABnsUiO35x+Q= | ||||
| github.com/unrolled/render v1.4.0/go.mod h1:cK4RSTTVdND5j9EYEc0LAMOvdG11JeiKjyjfyZRvV2w= | ||||
| github.com/urfave/cli v1.22.5 h1:lNq9sAHXK2qfdI8W+GRItjCEkI+2oR4d+MEHy1CKXoU= | ||||
| github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= | ||||
| github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= | ||||
| github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= | ||||
| github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= | ||||
| github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= | ||||
| github.com/willf/bitset v1.1.11 h1:N7Z7E9UvjW+sGsEl7k/SJrvY2reP1A07MrGuCjIOjRE= | ||||
| github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI= | ||||
| github.com/xanzy/go-gitlab v0.48.0 h1:RP9r4pMDIwE2fbtc+QYiC1euDsPGHcAjPkhje4X3QPU= | ||||
| github.com/xanzy/go-gitlab v0.48.0/go.mod h1:UW8JJbyBbqtOyBYNHRo261IRdHUFJr2m0y0z1xUiu+E= | ||||
| github.com/xanzy/go-gitlab v0.50.0 h1:t7IoYTrnLSbdEZN7d8X/5zcr+ZM4TZQ2mXa8MqWlAZQ= | ||||
| github.com/xanzy/go-gitlab v0.50.0/go.mod h1:Q+hQhV508bDPoBijv7YjK/Lvlb4PhVhJdKqXVQrUoAE= | ||||
| github.com/xanzy/ssh-agent v0.3.0 h1:wUMzuKtKilRgBAD1sUb8gOwwRr2FGoBVumcjoOACClI= | ||||
| github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0= | ||||
| github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= | ||||
|  | @ -1131,24 +1047,23 @@ github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1: | |||
| github.com/yohcop/openid-go v1.0.0 h1:EciJ7ZLETHR3wOtxBvKXx9RV6eyHZpCaSZ1inbBaUXE= | ||||
| github.com/yohcop/openid-go v1.0.0/go.mod h1:/408xiwkeItSPJZSTPF7+VtZxPkPrRRpRNK2vjGh6yI= | ||||
| github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= | ||||
| github.com/yuin/goldmark v1.1.22/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= | ||||
| 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.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= | ||||
| github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= | ||||
| github.com/yuin/goldmark v1.3.5 h1:dPmz1Snjq0kmkz159iL7S6WzdahUTHnHB5M56WFVifs= | ||||
| github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= | ||||
| github.com/yuin/goldmark-highlighting v0.0.0-20200307114337-60d527fdb691 h1:VWSxtAiQNh3zgHJpdpkpVYjTPqRE3P6UZCOPa1nRDio= | ||||
| github.com/yuin/goldmark-highlighting v0.0.0-20200307114337-60d527fdb691/go.mod h1:YLF3kDffRfUH/bTxOxHhV6lxwIB3Vfj91rEwNMS9MXo= | ||||
| github.com/yuin/goldmark v1.3.6/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= | ||||
| github.com/yuin/goldmark v1.3.7 h1:NSaHgaeJFCtWXCBkBKXw0rhgMuJ0VoE9FB5mWldcrQ4= | ||||
| github.com/yuin/goldmark v1.3.7/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= | ||||
| github.com/yuin/goldmark-highlighting v0.0.0-20210516132338-9216f9c5aa01 h1:0SJnXjE4jDClMW6grE0xpNhwpqbPwkBTn8zpVw5C0SI= | ||||
| github.com/yuin/goldmark-highlighting v0.0.0-20210516132338-9216f9c5aa01/go.mod h1:TwKQPa5XkCCRC2GRZ5wtfNUTQ2+9/i19mGRijFeJ4BE= | ||||
| github.com/yuin/goldmark-meta v1.0.0 h1:ScsatUIT2gFS6azqzLGUjgOnELsBOxMXerM3ogdJhAM= | ||||
| github.com/yuin/goldmark-meta v1.0.0/go.mod h1:zsNNOrZ4nLuyHAJeLQEZcQat8dm70SmB2kHbls092Gc= | ||||
| github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= | ||||
| github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= | ||||
| go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= | ||||
| go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= | ||||
| go.etcd.io/bbolt v1.3.5 h1:XAzx9gjCb0Rxj7EoqcClPD1d5ZBxZJk0jbuoPHenBt0= | ||||
| go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= | ||||
| go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= | ||||
| go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= | ||||
| go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= | ||||
| go.jolheiser.com/hcaptcha v0.0.4 h1:RrDERcr/Tz/kWyJenjVtI+V09RtLinXxlAemiwN5F+I= | ||||
| go.jolheiser.com/hcaptcha v0.0.4/go.mod h1:aw32WQOxnQZ6E06C0LypCf+sxNxPACyOnq+ZGnrIYho= | ||||
| go.jolheiser.com/pwn v0.0.3 h1:MQowb3QvCL5r5NmHmCPxw93SdjfgJ0q6rAwYn4i1Hjg= | ||||
|  | @ -1162,8 +1077,6 @@ go.mongodb.org/mongo-driver v1.4.4/go.mod h1:WcMNYLx/IlOxLe6JRJiv2uXuCz6zBLndR4S | |||
| go.mongodb.org/mongo-driver v1.4.6/go.mod h1:WcMNYLx/IlOxLe6JRJiv2uXuCz6zBLndR4SoGjYphSc= | ||||
| go.mongodb.org/mongo-driver v1.5.1 h1:9nOVLGDfOaZ9R0tBumx/BcuqkbFpyTCU2r/Po7A2azI= | ||||
| go.mongodb.org/mongo-driver v1.5.1/go.mod h1:gRXCHX4Jo7J0IJ1oDQyUxF7jfy19UfxniMS4xxMmUqw= | ||||
| go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= | ||||
| go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= | ||||
| go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= | ||||
| go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= | ||||
| go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= | ||||
|  | @ -1172,32 +1085,30 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= | |||
| go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= | ||||
| go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= | ||||
| go.opentelemetry.io/otel v0.14.0/go.mod h1:vH5xEuwy7Rts0GNtsCW3HYQoZDY+OmBJ6t1bFGGlxgw= | ||||
| go.opentelemetry.io/otel v0.19.0 h1:Lenfy7QHRXPZVsw/12CWpxX6d/JkrX8wrx2vO8G80Ng= | ||||
| go.opentelemetry.io/otel v0.19.0/go.mod h1:j9bF567N9EfomkSidSfmMwIwIBuP37AMAIzVW85OxSg= | ||||
| go.opentelemetry.io/otel/metric v0.19.0 h1:dtZ1Ju44gkJkYvo+3qGqVXmf88tc+a42edOywypengg= | ||||
| go.opentelemetry.io/otel/metric v0.19.0/go.mod h1:8f9fglJPRnXuskQmKpnad31lcLJ2VmNNqIsx/uIwBSc= | ||||
| go.opentelemetry.io/otel/oteltest v0.19.0 h1:YVfA0ByROYqTwOxqHVZYZExzEpfZor+MU1rU+ip2v9Q= | ||||
| go.opentelemetry.io/otel/oteltest v0.19.0/go.mod h1:tI4yxwh8U21v7JD6R3BcA/2+RBoTKFexE/PJ/nSO7IA= | ||||
| go.opentelemetry.io/otel/trace v0.19.0 h1:1ucYlenXIDA1OlHVLDZKX0ObXV5RLaq06DtUKz5e5zc= | ||||
| go.opentelemetry.io/otel/trace v0.19.0/go.mod h1:4IXiNextNOpPnRlI4ryK69mn5iC84bjBWZQA5DXz/qg= | ||||
| go.opentelemetry.io/otel v0.20.0 h1:eaP0Fqu7SXHwvjiqDq83zImeehOHX8doTvU9AwXON8g= | ||||
| go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo= | ||||
| go.opentelemetry.io/otel/metric v0.20.0 h1:4kzhXFP+btKm4jwxpjIqjs41A7MakRFUS86bqLHTIw8= | ||||
| go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU= | ||||
| go.opentelemetry.io/otel/oteltest v0.20.0 h1:HiITxCawalo5vQzdHfKeZurV8x7ljcqAgiWzF6Vaeaw= | ||||
| go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw= | ||||
| go.opentelemetry.io/otel/trace v0.20.0 h1:1DL6EXUdcg95gukhuRRvLDO/4X5THh/5dIV52lqtnbw= | ||||
| go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw= | ||||
| go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= | ||||
| go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= | ||||
| go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= | ||||
| go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= | ||||
| go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= | ||||
| go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= | ||||
| go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= | ||||
| go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= | ||||
| go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= | ||||
| go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= | ||||
| go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= | ||||
| go.uber.org/multierr v1.7.0 h1:zaiO/rmgFjbmCXdSYJWQcdvOCsthmdaHfr3Gm2Kx4Ec= | ||||
| go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= | ||||
| go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= | ||||
| go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= | ||||
| go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= | ||||
| go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= | ||||
| go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= | ||||
| go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM= | ||||
| go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= | ||||
| go.uber.org/zap v1.17.0 h1:MTjgFu6ZLKvY6Pvaqk97GlxNBuMpV4Hy/3P6tRGlI2U= | ||||
| go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= | ||||
| golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= | ||||
| golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= | ||||
| golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= | ||||
|  | @ -1212,7 +1123,6 @@ golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8U | |||
| golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | ||||
| golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | ||||
| golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | ||||
| golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | ||||
| golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | ||||
| 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= | ||||
|  | @ -1223,8 +1133,9 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh | |||
| golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= | ||||
| golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= | ||||
| golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= | ||||
| golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b h1:7mWr3k41Qtv8XlltBkDkl8LoP3mpSgBW8BUoxtEdbXg= | ||||
| golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= | ||||
| golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a h1:kr2P4QFmQr29mSLA43kwrOcgcReGTfbE9N577tCTuBc= | ||||
| golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= | ||||
| golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= | ||||
| golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= | ||||
| golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= | ||||
|  | @ -1247,7 +1158,6 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl | |||
| golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= | ||||
| golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= | ||||
| golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= | ||||
| golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5 h1:2M3HP5CCK1Si9FQhwnzYhXdG6DXeebvUHFpre8QvbyI= | ||||
| golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= | ||||
| golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= | ||||
| golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= | ||||
|  | @ -1267,12 +1177,10 @@ golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73r | |||
| golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | ||||
| golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | ||||
| golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | ||||
| golang.org/x/net v0.0.0-20181108082009-03003ca0c849/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | ||||
| golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | ||||
| golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | ||||
| golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | ||||
| golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | ||||
| golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | ||||
| golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/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-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | ||||
|  | @ -1317,9 +1225,9 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v | |||
| golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= | ||||
| golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k= | ||||
| golang.org/x/net v0.0.0-20210331060903-cb1fcc7394e5/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= | ||||
| golang.org/x/net v0.0.0-20210331212208-0fccb6fa2b5c/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= | ||||
| golang.org/x/net v0.0.0-20210421230115-4e50805a0758 h1:aEpZnXcAmXkd6AvLb2OPt+EN1Zu/8Ne3pCqPjja5PXY= | ||||
| golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= | ||||
| golang.org/x/net v0.0.0-20210525063256-abc453219eb5 h1:wjuX4b5yYQnEQHzd+CBcrcC6OVR2J1CN6mUy0oSxIPo= | ||||
| golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= | ||||
| golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= | ||||
| golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= | ||||
| golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= | ||||
|  | @ -1331,8 +1239,8 @@ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ | |||
| golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= | ||||
| golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= | ||||
| golang.org/x/oauth2 v0.0.0-20210323180902-22b0adad7558/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= | ||||
| golang.org/x/oauth2 v0.0.0-20210413134643-5e61552d6c78 h1:rPRtHfUb0UKZeZ6GH4K4Nt4YRbE9V1u+QZX5upZXqJQ= | ||||
| golang.org/x/oauth2 v0.0.0-20210413134643-5e61552d6c78/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= | ||||
| golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c h1:pkQiBZBvdos9qq4wBAHqlzuZHEXo07pqV06ef90u1WI= | ||||
| golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= | ||||
| golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||
| golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||
| golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||
|  | @ -1343,8 +1251,9 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ | |||
| golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||
| golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||
| golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||
| golang.org/x/sync v0.0.0-20201207232520-09787c993a3a h1:DcqTD9SDLc+1P/r1EmRBwnVsrOwW+kk2vWf9n+1sGhs= | ||||
| golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/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/sys v0.0.0-20180823144017-11551d06cbcc/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= | ||||
|  | @ -1352,7 +1261,6 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h | |||
| golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||
| golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||
| golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||
| golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||
| golang.org/x/sys v0.0.0-20181128092732-4ed8d59d0b35/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||
| golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||
| golang.org/x/sys v0.0.0-20181221143128-b4a75ba826a6/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||
|  | @ -1383,7 +1291,6 @@ golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7w | |||
| golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
|  | @ -1405,6 +1312,7 @@ golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7w | |||
| golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/sys v0.0.0-20201126233918-771906719818/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
|  | @ -1414,13 +1322,17 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w | |||
| golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/sys v0.0.0-20210421221651-33663a62ff08 h1:qyN5bV+96OX8pL78eXDuz6YlDPzCYgdW74H5yE9BoSU= | ||||
| golang.org/x/sys v0.0.0-20210421221651-33663a62ff08/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/sys v0.0.0-20210502180810-71e4cd670f79/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||
| golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||
| golang.org/x/sys v0.0.0-20210608053332-aa57babbf139 h1:C+AwYEtBp/VQwoLntUmQ/yx3MS9vmZaKNdw5eOpoQe8= | ||||
| golang.org/x/sys v0.0.0-20210608053332-aa57babbf139/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||
| golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= | ||||
| golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= | ||||
| golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | ||||
|  | @ -1432,14 +1344,12 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | |||
| golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | ||||
| golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= | ||||
| golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | ||||
| 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= | ||||
| golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= | ||||
| golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE= | ||||
| golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= | ||||
| golang.org/x/time v0.0.0-20210608053304-ed9ce3a009e4 h1:1asO3s7vR+9MvZSNRwUBBTjecxbGtfvmxjy2VWbFR5g= | ||||
| golang.org/x/time v0.0.0-20210608053304-ed9ce3a009e4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= | ||||
| golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | ||||
| golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | ||||
| golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | ||||
| golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | ||||
| golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | ||||
|  | @ -1477,7 +1387,6 @@ golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtn | |||
| golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= | ||||
| golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= | ||||
| golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= | ||||
| golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= | ||||
| golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= | ||||
| golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= | ||||
| golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= | ||||
|  | @ -1515,7 +1424,6 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T | |||
| 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.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= | ||||
| google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= | ||||
| google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= | ||||
| google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= | ||||
|  | @ -1537,7 +1445,6 @@ google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ | |||
| google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= | ||||
| google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= | ||||
| google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= | ||||
| google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= | ||||
| google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= | ||||
| google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= | ||||
| google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= | ||||
|  | @ -1551,7 +1458,6 @@ google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRn | |||
| google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= | ||||
| google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= | ||||
| google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= | ||||
| google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= | ||||
| google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= | ||||
| google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= | ||||
| google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= | ||||
|  | @ -1583,15 +1489,10 @@ google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6D | |||
| google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= | ||||
| google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= | ||||
| google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= | ||||
| google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= | ||||
| google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= | ||||
| google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= | ||||
| google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= | ||||
| google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= | ||||
| google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= | ||||
| google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= | ||||
| google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= | ||||
| google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= | ||||
| google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= | ||||
| google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= | ||||
| google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= | ||||
|  | @ -1627,10 +1528,8 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8 | |||
| 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/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= | ||||
| gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= | ||||
| gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= | ||||
| gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= | ||||
| gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= | ||||
| gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE= | ||||
| gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw= | ||||
| gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= | ||||
|  | @ -1660,14 +1559,12 @@ gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C | |||
| gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||||
| gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= | ||||
| gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||||
| honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= | ||||
| honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= | ||||
| honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= | ||||
| honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= | ||||
| honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= | ||||
| honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= | ||||
| honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= | ||||
| honnef.co/go/tools v0.0.1-2020.1.4 h1:UoveltGrhghAA7ePc+e+QYDHXrBps2PqFZiHkGR/xK8= | ||||
| honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= | ||||
| modernc.org/cc/v3 v3.31.5-0.20210308123301-7a3e9dab9009 h1:u0oCo5b9wyLr++HF3AN9JicGhkUxJhMz51+8TIZH9N0= | ||||
| modernc.org/cc/v3 v3.31.5-0.20210308123301-7a3e9dab9009/go.mod h1:0R6jl1aZlIl2avnYfbfHBS1QB6/f+16mihBObaBC878= | ||||
|  | @ -1701,8 +1598,6 @@ mvdan.cc/xurls/v2 v2.2.0/go.mod h1:EV1RMtya9D6G5DMYPGD8zTQzaHet6Jh8gFlRgGRJeO8= | |||
| rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= | ||||
| rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= | ||||
| rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= | ||||
| sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= | ||||
| sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= | ||||
| strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251 h1:mUcz5b3FJbP5Cvdq7Khzn6J9OCUQJaBwgBkCR+MOwSs= | ||||
| strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251/go.mod h1:FJGmPh3vz9jSos1L/F91iAgnC/aejc0wIIrF2ZwJxdY= | ||||
| xorm.io/builder v0.3.7/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE= | ||||
|  |  | |||
|  | @ -1,4 +1,4 @@ | |||
| # go-winio | ||||
| # go-winio [](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 | ||||
|  |  | |||
|  | @ -0,0 +1,3 @@ | |||
| # This source code refers to The Go Authors for copyright purposes. | ||||
| # The master list of authors is in the main Go distribution, | ||||
| # visible at https://tip.golang.org/AUTHORS. | ||||
|  | @ -0,0 +1,3 @@ | |||
| # This source code was written by the Go contributors. | ||||
| # The master list of contributors is in the main Go distribution, | ||||
| # visible at https://tip.golang.org/CONTRIBUTORS. | ||||
|  | @ -0,0 +1,27 @@ | |||
| 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 | ||||
| met: | ||||
| 
 | ||||
|    * Redistributions of source code must retain the above copyright | ||||
| notice, this list of conditions and the following disclaimer. | ||||
|    * 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. | ||||
|    * Neither the name of Google Inc. nor the names of its | ||||
| contributors may be used to endorse or promote products derived from | ||||
| this software without specific prior written permission. | ||||
| 
 | ||||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||||
| "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 COPYRIGHT | ||||
| OWNER OR CONTRIBUTORS 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. | ||||
|  | @ -0,0 +1,22 @@ | |||
| Additional IP Rights Grant (Patents) | ||||
| 
 | ||||
| "This implementation" means the copyrightable works distributed by | ||||
| Google as part of the Go project. | ||||
| 
 | ||||
| Google hereby grants to You a perpetual, worldwide, non-exclusive, | ||||
| no-charge, royalty-free, irrevocable (except as stated in this section) | ||||
| patent license to make, have made, use, offer to sell, sell, import, | ||||
| transfer and otherwise run, modify and propagate the contents of this | ||||
| implementation of Go, where such license applies only to those patent | ||||
| claims, both currently owned or controlled by Google and acquired in | ||||
| the future, licensable by Google that are necessarily infringed by this | ||||
| implementation of Go.  This grant does not include claims that would be | ||||
| infringed only as a consequence of further modification of this | ||||
| implementation.  If you or your agent or exclusive licensee institute or | ||||
| order or agree to the institution of patent litigation against any | ||||
| entity (including a cross-claim or counterclaim in a lawsuit) alleging | ||||
| that this implementation of Go or any code incorporated within this | ||||
| implementation of Go constitutes direct or contributory patent | ||||
| infringement, or inducement of patent infringement, then any patent | ||||
| rights granted to you under this License for this implementation of Go | ||||
| shall terminate as of the date such litigation is filed. | ||||
|  | @ -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 enviroments 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"}, | ||||
| } | ||||
							
								
								
									
										92
									
								
								vendor/github.com/ProtonMail/go-crypto/internal/byteutil/byteutil.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										92
									
								
								vendor/github.com/ProtonMail/go-crypto/internal/byteutil/byteutil.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							|  | @ -0,0 +1,92 @@ | |||
| // 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"}, | ||||
| } | ||||
							
								
								
									
										78
									
								
								vendor/github.com/ProtonMail/go-crypto/ocb/rfc7253_test_vectors_suite_a.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										78
									
								
								vendor/github.com/ProtonMail/go-crypto/ocb/rfc7253_test_vectors_suite_a.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							|  | @ -0,0 +1,78 @@ | |||
| package ocb | ||||
| 
 | ||||
| import ( | ||||
| 	"encoding/hex" | ||||
| ) | ||||
| 
 | ||||
| // Test vectors from https://tools.ietf.org/html/rfc7253. Note that key is
 | ||||
| // shared accross 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"}, | ||||
| } | ||||
							
								
								
									
										24
									
								
								vendor/github.com/ProtonMail/go-crypto/ocb/rfc7253_test_vectors_suite_b.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										24
									
								
								vendor/github.com/ProtonMail/go-crypto/ocb/rfc7253_test_vectors_suite_b.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							|  | @ -0,0 +1,24 @@ | |||
| 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"}, | ||||
| 	} | ||||
							
								
								
									
										153
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/aes/keywrap/keywrap.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										153
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/aes/keywrap/keywrap.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							|  | @ -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,224 @@ | |||
| // 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,160 @@ | |||
| // 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,165 @@ | |||
| // 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" | ||||
| 	"crypto/elliptic" | ||||
| 	"errors" | ||||
| 	"io" | ||||
| 	"math/big" | ||||
| 
 | ||||
| 	"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 { | ||||
| 	ecc.CurveType | ||||
| 	elliptic.Curve | ||||
| 	X, Y *big.Int | ||||
| 	KDF | ||||
| } | ||||
| 
 | ||||
| type PrivateKey struct { | ||||
| 	PublicKey | ||||
| 	D []byte | ||||
| } | ||||
| 
 | ||||
| func GenerateKey(c elliptic.Curve, kdf KDF, rand io.Reader) (priv *PrivateKey, err error) { | ||||
| 	priv = new(PrivateKey) | ||||
| 	priv.PublicKey.Curve = c | ||||
| 	priv.PublicKey.KDF = kdf | ||||
| 	priv.D, priv.PublicKey.X, priv.PublicKey.Y, err = elliptic.GenerateKey(c, 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...) | ||||
| 
 | ||||
| 	if pub.CurveType == ecc.Curve25519 { | ||||
| 		return X25519Encrypt(random, pub, m, curveOID, fingerprint) | ||||
| 	} | ||||
| 
 | ||||
| 	d, x, y, err := elliptic.GenerateKey(pub.Curve, random) | ||||
| 	if err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	vsG = elliptic.Marshal(pub.Curve, x, y) | ||||
| 	zbBig, _ := pub.Curve.ScalarMult(pub.X, pub.Y, d) | ||||
| 
 | ||||
| 	byteLen := (pub.Curve.Params().BitSize + 7) >> 3 | ||||
| 	zb := make([]byte, byteLen) | ||||
| 	zbBytes := zbBig.Bytes() | ||||
| 	copy(zb[byteLen-len(zbBytes):], zbBytes) | ||||
| 
 | ||||
| 	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, m, curveOID, fingerprint []byte) (msg []byte, err error) { | ||||
| 	if priv.PublicKey.CurveType == ecc.Curve25519 { | ||||
| 		return X25519Decrypt(priv, vsG, m, curveOID, fingerprint) | ||||
| 	} | ||||
| 	x, y := elliptic.Unmarshal(priv.Curve, vsG) | ||||
| 	zbBig, _ := priv.Curve.ScalarMult(x, y, priv.D) | ||||
| 
 | ||||
| 	byteLen := (priv.Curve.Params().BitSize + 7) >> 3 | ||||
| 	zb := make([]byte, byteLen) | ||||
| 	zbBytes := zbBig.Bytes() | ||||
| 	copy(zb[byteLen-len(zbBytes):], zbBytes) | ||||
| 
 | ||||
| 	z, err := buildKey(&priv.PublicKey, zb, curveOID, fingerprint, false, false) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	c, err := keywrap.Unwrap(z, m) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	return c[:len(c)-int(c[len(c)-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.
 | ||||
| 
 | ||||
| } | ||||
|  | @ -0,0 +1,157 @@ | |||
| // 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 ( | ||||
| 	"errors" | ||||
| 	"io" | ||||
| 	"math/big" | ||||
| 
 | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/aes/keywrap" | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/internal/ecc" | ||||
| 	"golang.org/x/crypto/curve25519" | ||||
| ) | ||||
| 
 | ||||
| // Generates a private-public key-pair.
 | ||||
| // 'priv' is a private key; a 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 x25519GenerateKeyPairBytes(rand io.Reader) (priv [32]byte, pub [32]byte, err error) { | ||||
| 	var n, helper = new(big.Int), new(big.Int) | ||||
| 	n.SetUint64(1) | ||||
| 	n.Lsh(n, 252) | ||||
| 	helper.SetString("27742317777372353535851937790883648493", 10) | ||||
| 	n.Add(n, helper) | ||||
| 
 | ||||
| 	for true { | ||||
| 		_, err = io.ReadFull(rand, priv[:]) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		// 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
 | ||||
| 		// of the curve.
 | ||||
| 		priv[0] &= 248 | ||||
| 		priv[31] &= 127 | ||||
| 		priv[31] |= 64 | ||||
| 
 | ||||
| 		// If the scalar is out of range, sample another random number.
 | ||||
| 		if new(big.Int).SetBytes(priv[:]).Cmp(n) >= 0 { | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		curve25519.ScalarBaseMult(&pub, &priv) | ||||
| 		return | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // X25519GenerateKey samples the key pair according to the correct distribution.
 | ||||
| // It also sets the given key-derivation function and returns the *PrivateKey
 | ||||
| // object along with an error.
 | ||||
| func X25519GenerateKey(rand io.Reader, kdf KDF) (priv *PrivateKey, err error) { | ||||
| 	ci := ecc.FindByName("Curve25519") | ||||
| 	priv = new(PrivateKey) | ||||
| 	priv.PublicKey.Curve = ci.Curve | ||||
| 	d, pubKey, err := x25519GenerateKeyPairBytes(rand) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	priv.PublicKey.KDF = kdf | ||||
| 	priv.D = make([]byte, 32) | ||||
| 	copyReversed(priv.D, d[:]) | ||||
| 	priv.PublicKey.CurveType = ci.CurveType | ||||
| 	priv.PublicKey.Curve = ci.Curve | ||||
| 	/* | ||||
| 	 * Note that ECPoint.point 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 TLS, and (2) there | ||||
| 	 * is an additional length byte (so ECpoint.point is actually 33 bytes), | ||||
| 	 * again for uniformity (and extensibility). | ||||
| 	 */ | ||||
| 	var encodedKey = make([]byte, 33) | ||||
| 	encodedKey[0] = 0x40 | ||||
| 	copy(encodedKey[1:], pubKey[:]) | ||||
| 	priv.PublicKey.X = new(big.Int).SetBytes(encodedKey[:]) | ||||
| 	priv.PublicKey.Y = new(big.Int) | ||||
| 	return priv, nil | ||||
| } | ||||
| 
 | ||||
| func X25519Encrypt(random io.Reader, pub *PublicKey, msg, curveOID, fingerprint []byte) (vsG, c []byte, err error) { | ||||
| 	d, ephemeralKey, err := x25519GenerateKeyPairBytes(random) | ||||
| 	if err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
| 	var pubKey [32]byte | ||||
| 
 | ||||
| 	if pub.X.BitLen() > 33*264 { | ||||
| 		return nil, nil, errors.New("ecdh: invalid key") | ||||
| 	} | ||||
| 	copy(pubKey[:], pub.X.Bytes()[1:]) | ||||
| 
 | ||||
| 	var zb [32]byte | ||||
| 	curve25519.ScalarBaseMult(&zb, &d) | ||||
| 	curve25519.ScalarMult(&zb, &d, &pubKey) | ||||
| 	z, err := buildKey(pub, zb[:], curveOID, fingerprint, false, false) | ||||
| 
 | ||||
| 	if err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	if c, err = keywrap.Wrap(z, msg); err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	var vsg [33]byte | ||||
| 	vsg[0] = 0x40 | ||||
| 	copy(vsg[1:], ephemeralKey[:]) | ||||
| 
 | ||||
| 	return vsg[:], c, nil | ||||
| } | ||||
| 
 | ||||
| func X25519Decrypt(priv *PrivateKey, vsG, m, curveOID, fingerprint []byte) (msg []byte, err error) { | ||||
| 	var zb, d, ephemeralKey [32]byte | ||||
| 	if len(vsG) != 33 || vsG[0] != 0x40 { | ||||
| 		return nil, errors.New("ecdh: invalid key") | ||||
| 	} | ||||
| 	copy(ephemeralKey[:], vsG[1:33]) | ||||
| 
 | ||||
| 	copyReversed(d[:], priv.D) | ||||
| 	curve25519.ScalarBaseMult(&zb, &d) | ||||
| 	curve25519.ScalarMult(&zb, &d, &ephemeralKey) | ||||
| 
 | ||||
| 	var c []byte | ||||
| 
 | ||||
| 	for i := 0; i < 3; i++ { | ||||
| 		// Try buildKey three times for compat, see comments in buildKey.
 | ||||
| 		z, err := buildKey(&priv.PublicKey, zb[:], curveOID, fingerprint, i == 1, i == 2) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 
 | ||||
| 		res, err := keywrap.Unwrap(z, m) | ||||
| 		if i == 2 && err != nil { | ||||
| 			// Only return an error after we've tried all variants of buildKey.
 | ||||
| 			return nil, err | ||||
| 		} | ||||
| 
 | ||||
| 		c = res | ||||
| 		if err == nil { | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return c[:len(c)-int(c[len(c)-1])], nil | ||||
| } | ||||
| 
 | ||||
| func copyReversed(out []byte, in []byte) { | ||||
| 	l := len(in) | ||||
| 	for i := 0; i < l; i++ { | ||||
| 		out[i] = in[l-i-1] | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										124
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/elgamal/elgamal.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										124
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/elgamal/elgamal.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							|  | @ -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) | ||||
| } | ||||
							
								
								
									
										65
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/internal/algorithm/aead.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										65
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/internal/algorithm/aead.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							|  | @ -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(100) | ||||
| ) | ||||
| 
 | ||||
| // 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 | ||||
| } | ||||
							
								
								
									
										107
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/internal/algorithm/cipher.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										107
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/internal/algorithm/cipher.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							|  | @ -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 | ||||
| } | ||||
							
								
								
									
										86
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/internal/algorithm/hash.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										86
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/internal/algorithm/hash.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							|  | @ -0,0 +1,86 @@ | |||
| // 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 ( | ||||
| 	MD5       Hash = cryptoHash{1, crypto.MD5} | ||||
| 	SHA1      Hash = cryptoHash{2, crypto.SHA1} | ||||
| 	RIPEMD160 Hash = cryptoHash{3, crypto.RIPEMD160} | ||||
| 	SHA256    Hash = cryptoHash{8, crypto.SHA256} | ||||
| 	SHA384    Hash = cryptoHash{9, crypto.SHA384} | ||||
| 	SHA512    Hash = cryptoHash{10, crypto.SHA512} | ||||
| 	SHA224    Hash = cryptoHash{11, crypto.SHA224} | ||||
| ) | ||||
| 
 | ||||
| // 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{ | ||||
| 		MD5.Id():       MD5, | ||||
| 		SHA1.Id():      SHA1, | ||||
| 		RIPEMD160.Id(): RIPEMD160, | ||||
| 		SHA256.Id():    SHA256, | ||||
| 		SHA384.Id():    SHA384, | ||||
| 		SHA512.Id():    SHA512, | ||||
| 		SHA224.Id():    SHA224, | ||||
| 	} | ||||
| ) | ||||
| 
 | ||||
| // 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{ | ||||
| 	MD5.Id():       "MD5", | ||||
| 	SHA1.Id():      "SHA1", | ||||
| 	RIPEMD160.Id(): "RIPEMD160", | ||||
| 	SHA256.Id():    "SHA256", | ||||
| 	SHA384.Id():    "SHA384", | ||||
| 	SHA512.Id():    "SHA512", | ||||
| 	SHA224.Id():    "SHA224", | ||||
| } | ||||
| 
 | ||||
| func (h cryptoHash) String() string { | ||||
| 	s, ok := hashNames[h.id] | ||||
| 	if !ok { | ||||
| 		panic(fmt.Sprintf("Unsupported hash function %d", h.id)) | ||||
| 	} | ||||
| 	return s | ||||
| } | ||||
							
								
								
									
										118
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/curveInfo.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										118
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/curveInfo.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							|  | @ -0,0 +1,118 @@ | |||
| package ecc | ||||
| 
 | ||||
| import ( | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/internal/encoding" | ||||
| 	"crypto/elliptic" | ||||
| 	"bytes" | ||||
| 	"github.com/ProtonMail/go-crypto/bitcurves" | ||||
| 	"github.com/ProtonMail/go-crypto/brainpool" | ||||
| ) | ||||
| 
 | ||||
| type SignatureAlgorithm uint8 | ||||
| 
 | ||||
| const ( | ||||
| 	ECDSA SignatureAlgorithm = 1 | ||||
| 	EdDSA SignatureAlgorithm = 2 | ||||
| ) | ||||
| 
 | ||||
| type CurveInfo struct { | ||||
| 	Name string | ||||
| 	Oid *encoding.OID | ||||
| 	Curve elliptic.Curve | ||||
| 	SigAlgorithm SignatureAlgorithm | ||||
| 	CurveType CurveType | ||||
| } | ||||
| 
 | ||||
| var curves = []CurveInfo{ | ||||
| 	{ | ||||
| 		Name: "NIST curve P-256", | ||||
| 		Oid: encoding.NewOID([]byte{0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07}), | ||||
| 		Curve: elliptic.P256(), | ||||
| 		CurveType: NISTCurve, | ||||
| 		SigAlgorithm: ECDSA, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name: "NIST curve P-384", | ||||
| 		Oid: encoding.NewOID([]byte{0x2B, 0x81, 0x04, 0x00, 0x22}), | ||||
| 		Curve: elliptic.P384(), | ||||
| 		CurveType: NISTCurve, | ||||
| 		SigAlgorithm: ECDSA, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name: "NIST curve P-521", | ||||
| 		Oid: encoding.NewOID([]byte{0x2B, 0x81, 0x04, 0x00, 0x23}), | ||||
| 		Curve: elliptic.P521(), | ||||
| 		CurveType: NISTCurve, | ||||
| 		SigAlgorithm: ECDSA, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name: "SecP256k1", | ||||
| 		Oid: encoding.NewOID([]byte{0x2B, 0x81, 0x04, 0x00, 0x0A}), | ||||
| 		Curve: bitcurves.S256(), | ||||
| 		CurveType: BitCurve, | ||||
| 		SigAlgorithm: ECDSA, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name: "Curve25519", | ||||
| 		Oid: encoding.NewOID([]byte{0x2B, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01}), | ||||
| 		Curve: elliptic.P256(),// filler
 | ||||
| 		CurveType: Curve25519, | ||||
| 		SigAlgorithm: ECDSA, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name: "Ed25519", | ||||
| 		Oid: encoding.NewOID([]byte{0x2B, 0x06, 0x01, 0x04, 0x01, 0xDA, 0x47, 0x0F, 0x01}), | ||||
| 		Curve: elliptic.P256(), // filler
 | ||||
| 		CurveType: NISTCurve, | ||||
| 		SigAlgorithm: EdDSA, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name: "Brainpool P256r1", | ||||
| 		Oid: encoding.NewOID([]byte{0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x07}), | ||||
| 		Curve: brainpool.P256r1(), | ||||
| 		CurveType: BrainpoolCurve, | ||||
| 		SigAlgorithm: ECDSA, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name: "BrainpoolP384r1", | ||||
| 		Oid: encoding.NewOID([]byte{0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0B}), | ||||
| 		Curve: brainpool.P384r1(), | ||||
| 		CurveType: BrainpoolCurve, | ||||
| 		SigAlgorithm: ECDSA, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name: "BrainpoolP512r1", | ||||
| 		Oid: encoding.NewOID([]byte{0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0D}), | ||||
| 		Curve: brainpool.P512r1(), | ||||
| 		CurveType: BrainpoolCurve, | ||||
| 		SigAlgorithm: ECDSA, | ||||
| 	}, | ||||
| } | ||||
| 
 | ||||
| func FindByCurve(curve elliptic.Curve) *CurveInfo { | ||||
| 	for _, curveInfo := range curves { | ||||
| 		if curveInfo.Curve == curve { | ||||
| 			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 FindByName(name string) *CurveInfo { | ||||
| 	for _, curveInfo := range curves { | ||||
| 		if curveInfo.Name == name { | ||||
| 			return &curveInfo | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										10
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/curveType.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										10
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/curveType.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							|  | @ -0,0 +1,10 @@ | |||
| package ecc | ||||
| 
 | ||||
| type CurveType uint8 | ||||
| 
 | ||||
| const ( | ||||
|     NISTCurve CurveType = 1 | ||||
| 	Curve25519 CurveType = 2 | ||||
| 	BitCurve CurveType = 3 | ||||
| 	BrainpoolCurve CurveType = 4 | ||||
| ) | ||||
							
								
								
									
										27
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/internal/encoding/encoding.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										27
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/internal/encoding/encoding.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							|  | @ -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) | ||||
| } | ||||
							
								
								
									
										91
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/internal/encoding/mpi.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										91
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/internal/encoding/mpi.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							|  | @ -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 | ||||
| } | ||||
							
								
								
									
										88
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/internal/encoding/oid.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										88
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/internal/encoding/oid.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							|  | @ -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 argment 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,375 @@ | |||
| // 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" | ||||
| 
 | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/ecdh" | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/errors" | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/internal/algorithm" | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/packet" | ||||
| 	"golang.org/x/crypto/ed25519" | ||||
| ) | ||||
| 
 | ||||
| // 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() | ||||
| 
 | ||||
| 	uid := packet.NewUserId(name, comment, email) | ||||
| 	if uid == nil { | ||||
| 		return nil, errors.InvalidArgumentError("user id field contained invalid characters") | ||||
| 	} | ||||
| 
 | ||||
| 	// 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() | ||||
| 	} | ||||
| 
 | ||||
| 	isPrimaryId := true | ||||
| 	selfSignature := &packet.Signature{ | ||||
| 		Version:           primary.PublicKey.Version, | ||||
| 		SigType:           packet.SigTypePositiveCert, | ||||
| 		PubKeyAlgo:        primary.PublicKey.PubKeyAlgo, | ||||
| 		Hash:              config.Hash(), | ||||
| 		CreationTime:      creationTime, | ||||
| 		KeyLifetimeSecs:   &keyLifetimeSecs, | ||||
| 		IssuerKeyId:       &primary.PublicKey.KeyId, | ||||
| 		IssuerFingerprint: primary.PublicKey.Fingerprint, | ||||
| 		IsPrimaryId:       &isPrimaryId, | ||||
| 		FlagsValid:        true, | ||||
| 		FlagSign:          true, | ||||
| 		FlagCertify:       true, | ||||
| 		MDC:               true, // true by default, see 5.8 vs. 5.14
 | ||||
| 		AEAD:              config.AEAD() != nil, | ||||
| 		V5Keys:            config != nil && config.V5Keys, | ||||
| 	} | ||||
| 
 | ||||
| 	// Set the PreferredHash for the SelfSignature from the packet.Config.
 | ||||
| 	// If it is not the must-implement algorithm from rfc4880bis, append that.
 | ||||
| 	selfSignature.PreferredHash = []uint8{hashToHashId(config.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)) | ||||
| 	} | ||||
| 
 | ||||
| 	// And for DefaultMode.
 | ||||
| 	selfSignature.PreferredAEAD = []uint8{uint8(config.AEAD().Mode())} | ||||
| 	if config.AEAD().Mode() != packet.AEADModeEAX { | ||||
| 		selfSignature.PreferredAEAD = append(selfSignature.PreferredAEAD, uint8(packet.AEADModeEAX)) | ||||
| 	} | ||||
| 
 | ||||
| 	// User ID binding signature
 | ||||
| 	err = selfSignature.SignUserId(uid.Id, &primary.PublicKey, primary, config) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	// Generate an encryption subkey
 | ||||
| 	subPrivRaw, err := newDecrypter(config) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	sub := packet.NewDecrypterPrivateKey(creationTime, subPrivRaw) | ||||
| 	sub.IsSubkey = true | ||||
| 	sub.PublicKey.IsSubkey = true | ||||
| 	if config != nil && config.V5Keys { | ||||
| 		sub.UpgradeToV5() | ||||
| 	} | ||||
| 
 | ||||
| 	// NOTE: No KeyLifetimeSecs here, but we will not return this subkey in EncryptionKey()
 | ||||
| 	// if the primary/master key has expired.
 | ||||
| 	subKey := Subkey{ | ||||
| 		PublicKey:  &sub.PublicKey, | ||||
| 		PrivateKey: sub, | ||||
| 		Sig: &packet.Signature{ | ||||
| 			Version:                   primary.PublicKey.Version, | ||||
| 			CreationTime:              creationTime, | ||||
| 			SigType:                   packet.SigTypeSubkeyBinding, | ||||
| 			PubKeyAlgo:                primary.PublicKey.PubKeyAlgo, | ||||
| 			Hash:                      config.Hash(), | ||||
| 			FlagsValid:                true, | ||||
| 			FlagEncryptStorage:        true, | ||||
| 			FlagEncryptCommunications: true, | ||||
| 			IssuerKeyId:               &primary.PublicKey.KeyId, | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	// Subkey binding signature
 | ||||
| 	err = subKey.Sig.SignKey(subKey.PublicKey, primary, config) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	return &Entity{ | ||||
| 		PrimaryKey: &primary.PublicKey, | ||||
| 		PrivateKey: primary, | ||||
| 		Identities: map[string]*Identity{ | ||||
| 			uid.Id: &Identity{ | ||||
| 				Name:          uid.Id, | ||||
| 				UserId:        uid, | ||||
| 				SelfSignature: selfSignature, | ||||
| 				Signatures:    []*packet.Signature{selfSignature}, | ||||
| 			}, | ||||
| 		}, | ||||
| 		Subkeys: []Subkey{subKey}, | ||||
| 	}, 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) | ||||
| 
 | ||||
| 	subkey := Subkey{ | ||||
| 		PublicKey:  &sub.PublicKey, | ||||
| 		PrivateKey: sub, | ||||
| 		Sig: &packet.Signature{ | ||||
| 			Version:         e.PrimaryKey.Version, | ||||
| 			CreationTime:    creationTime, | ||||
| 			KeyLifetimeSecs: &keyLifetimeSecs, | ||||
| 			SigType:         packet.SigTypeSubkeyBinding, | ||||
| 			PubKeyAlgo:      e.PrimaryKey.PubKeyAlgo, | ||||
| 			Hash:            config.Hash(), | ||||
| 			FlagsValid:      true, | ||||
| 			FlagSign:        true, | ||||
| 			IssuerKeyId:     &e.PrimaryKey.KeyId, | ||||
| 			EmbeddedSignature: &packet.Signature{ | ||||
| 				Version:      e.PrimaryKey.Version, | ||||
| 				CreationTime: creationTime, | ||||
| 				SigType:      packet.SigTypePrimaryKeyBinding, | ||||
| 				PubKeyAlgo:   sub.PublicKey.PubKeyAlgo, | ||||
| 				Hash:         config.Hash(), | ||||
| 				IssuerKeyId:  &e.PrimaryKey.KeyId, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| 	if config != nil && config.V5Keys { | ||||
| 		subkey.PublicKey.UpgradeToV5() | ||||
| 	} | ||||
| 
 | ||||
| 	err = subkey.Sig.EmbeddedSignature.CrossSignKey(subkey.PublicKey, e.PrimaryKey, subkey.PrivateKey, config) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	subkey.PublicKey.IsSubkey = true | ||||
| 	subkey.PrivateKey.IsSubkey = true | ||||
| 	if err = subkey.Sig.SignKey(subkey.PublicKey, e.PrivateKey, config); 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() | ||||
| 
 | ||||
| 	subPrivRaw, err := newDecrypter(config) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	sub := packet.NewDecrypterPrivateKey(creationTime, subPrivRaw) | ||||
| 
 | ||||
| 	subkey := Subkey{ | ||||
| 		PublicKey:  &sub.PublicKey, | ||||
| 		PrivateKey: sub, | ||||
| 		Sig: &packet.Signature{ | ||||
| 			Version:                   e.PrimaryKey.Version, | ||||
| 			CreationTime:              creationTime, | ||||
| 			KeyLifetimeSecs:           &keyLifetimeSecs, | ||||
| 			SigType:                   packet.SigTypeSubkeyBinding, | ||||
| 			PubKeyAlgo:                e.PrimaryKey.PubKeyAlgo, | ||||
| 			Hash:                      config.Hash(), | ||||
| 			FlagsValid:                true, | ||||
| 			FlagEncryptStorage:        true, | ||||
| 			FlagEncryptCommunications: true, | ||||
| 			IssuerKeyId:               &e.PrimaryKey.KeyId, | ||||
| 		}, | ||||
| 	} | ||||
| 	if config != nil && config.V5Keys { | ||||
| 		subkey.PublicKey.UpgradeToV5() | ||||
| 	} | ||||
| 
 | ||||
| 	subkey.PublicKey.IsSubkey = true | ||||
| 	subkey.PrivateKey.IsSubkey = true | ||||
| 	if err = subkey.Sig.SignKey(subkey.PublicKey, e.PrivateKey, config); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	e.Subkeys = append(e.Subkeys, subkey) | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // Generates a signing key
 | ||||
| func newSigner(config *packet.Config) (signer crypto.Signer, 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: | ||||
| 		_, priv, err := ed25519.GenerateKey(config.Random()) | ||||
| 		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: | ||||
| 		fallthrough // When passing EdDSA, we generate an ECDH subkey
 | ||||
| 	case packet.PubKeyAlgoECDH: | ||||
| 		var kdf = ecdh.KDF{ | ||||
| 			Hash:   algorithm.SHA512, | ||||
| 			Cipher: algorithm.AES256, | ||||
| 		} | ||||
| 		return ecdh.X25519GenerateKey(config.Random(), 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,707 @@ | |||
| // 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 | ||||
| 	Signatures    []*packet.Signature | ||||
| } | ||||
| 
 | ||||
| // 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 | ||||
| } | ||||
| 
 | ||||
| // 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 | ||||
| } | ||||
| 
 | ||||
| // 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 the Identity marked as primary or the first identity
 | ||||
| // if none are so marked.
 | ||||
| func (e *Entity) PrimaryIdentity() *Identity { | ||||
| 	var firstIdentity *Identity | ||||
| 	for _, ident := range e.Identities { | ||||
| 		if firstIdentity == nil { | ||||
| 			firstIdentity = ident | ||||
| 		} | ||||
| 		if ident.SelfSignature.IsPrimaryId != nil && *ident.SelfSignature.IsPrimaryId { | ||||
| 			return ident | ||||
| 		} | ||||
| 	} | ||||
| 	return firstIdentity | ||||
| } | ||||
| 
 | ||||
| // 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 primary key has expired.
 | ||||
| 	i := e.PrimaryIdentity() | ||||
| 	primaryKeyExpired := e.PrimaryKey.KeyExpired(i.SelfSignature, now) | ||||
| 	if primaryKeyExpired { | ||||
| 		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) && | ||||
| 			(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}, true | ||||
| 	} | ||||
| 
 | ||||
| 	// If we don't have any candidate subkeys for encryption and
 | ||||
| 	// the primary key doesn't have any usage metadata then we
 | ||||
| 	// assume that the primary key is ok. Or, if the primary key is
 | ||||
| 	// marked as ok to encrypt with, then we can obviously use it.
 | ||||
| 	// Also, check expiry again just to be safe.
 | ||||
| 	if !i.SelfSignature.FlagsValid || i.SelfSignature.FlagEncryptCommunications && | ||||
| 		e.PrimaryKey.PubKeyAlgo.CanEncrypt() && !primaryKeyExpired { | ||||
| 		return Key{e, e.PrimaryKey, e.PrivateKey, i.SelfSignature}, true | ||||
| 	} | ||||
| 
 | ||||
| 	return Key{}, false | ||||
| } | ||||
| 
 | ||||
| // 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) { | ||||
| 	// Fail to find any signing key if the primary key has expired.
 | ||||
| 	i := e.PrimaryIdentity() | ||||
| 	primaryKeyExpired := e.PrimaryKey.KeyExpired(i.SelfSignature, now) | ||||
| 	if primaryKeyExpired { | ||||
| 		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 && | ||||
| 			subkey.Sig.FlagSign && | ||||
| 			subkey.PublicKey.PubKeyAlgo.CanSign() && | ||||
| 			!subkey.PublicKey.KeyExpired(subkey.Sig, now) && | ||||
| 			(maxTime.IsZero() || subkey.Sig.CreationTime.After(maxTime)) && | ||||
| 			(id == 0 || subkey.PrivateKey.KeyId == id) { | ||||
| 			candidateSubkey = idx | ||||
| 			maxTime = subkey.Sig.CreationTime | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if candidateSubkey != -1 { | ||||
| 		subkey := e.Subkeys[candidateSubkey] | ||||
| 		return Key{e, subkey.PublicKey, subkey.PrivateKey, subkey.Sig}, true | ||||
| 	} | ||||
| 
 | ||||
| 	// If we have no candidate subkey then we assume that it's ok to sign
 | ||||
| 	// with the primary key.  Or, if the primary key is marked as ok to
 | ||||
| 	// sign with, then we can use it. Also, check expiry again just to be safe.
 | ||||
| 	if !i.SelfSignature.FlagsValid || i.SelfSignature.FlagSign && | ||||
| 		e.PrimaryKey.PubKeyAlgo.CanSign() && !primaryKeyExpired && | ||||
| 		(id == 0 || e.PrivateKey.KeyId == id) { | ||||
| 		return Key{e, e.PrimaryKey, e.PrivateKey, i.SelfSignature}, true | ||||
| 	} | ||||
| 
 | ||||
| 	// No keys with a valid Signing Flag or no keys matched the id passed in
 | ||||
| 	return Key{}, false | ||||
| } | ||||
| 
 | ||||
| // 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 { | ||||
| 			var selfSig *packet.Signature | ||||
| 			for _, ident := range e.Identities { | ||||
| 				if selfSig == nil { | ||||
| 					selfSig = ident.SelfSignature | ||||
| 				} else if ident.SelfSignature.IsPrimaryId != nil && *ident.SelfSignature.IsPrimaryId { | ||||
| 					selfSig = ident.SelfSignature | ||||
| 					break | ||||
| 				} | ||||
| 			} | ||||
| 			keys = append(keys, Key{e, e.PrimaryKey, e.PrivateKey, selfSig}) | ||||
| 		} | ||||
| 
 | ||||
| 		for _, subKey := range e.Subkeys { | ||||
| 			if subKey.PublicKey.KeyId == id { | ||||
| 				keys = append(keys, Key{e, subKey.PublicKey, subKey.PrivateKey, subKey.Sig}) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	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 len(key.Entity.Revocations) > 0 { | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		if key.SelfSignature.RevocationReason != nil { | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		if key.SelfSignature.FlagsValid && requiredUsage != 0 { | ||||
| 			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}) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	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.SigTypePositiveCert || sig.SigType == packet.SigTypeGenericCert) && 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 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.Sig = sig | ||||
| 		case packet.SigTypeSubkeyBinding: | ||||
| 			if shouldReplaceSubkeySig(subKey.Sig, sig) { | ||||
| 				subKey.Sig = sig | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if subKey.Sig == nil { | ||||
| 		return errors.StructuralError("subkey packet not followed by signature") | ||||
| 	} | ||||
| 
 | ||||
| 	e.Subkeys = append(e.Subkeys, subKey) | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func shouldReplaceSubkeySig(existingSig, potentialNewSig *packet.Signature) bool { | ||||
| 	if potentialNewSig == nil { | ||||
| 		return false | ||||
| 	} | ||||
| 
 | ||||
| 	if existingSig == nil { | ||||
| 		return true | ||||
| 	} | ||||
| 
 | ||||
| 	if existingSig.SigType == packet.SigTypeSubkeyRevocation { | ||||
| 		return false // never override a revocation signature
 | ||||
| 	} | ||||
| 
 | ||||
| 	return potentialNewSig.CreationTime.After(existingSig.CreationTime) | ||||
| } | ||||
| 
 | ||||
| // 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 _, ident := range e.Identities { | ||||
| 		err = ident.UserId.Serialize(w) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		if reSign { | ||||
| 			err = ident.SelfSignature.SignUserId(ident.UserId.Id, e.PrimaryKey, e.PrivateKey, config) | ||||
| 			if err != nil { | ||||
| 				return | ||||
| 			} | ||||
| 		} | ||||
| 		err = ident.SelfSignature.Serialize(w) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 	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 | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		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 _, 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 | ||||
| 		} | ||||
| 		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 { | ||||
| 	if signer.PrivateKey == nil { | ||||
| 		return errors.InvalidArgumentError("signing Entity must have a private key") | ||||
| 	} | ||||
| 	if signer.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 := &packet.Signature{ | ||||
| 		Version:      signer.PrivateKey.Version, | ||||
| 		SigType:      packet.SigTypeGenericCert, | ||||
| 		PubKeyAlgo:   signer.PrivateKey.PubKeyAlgo, | ||||
| 		Hash:         config.Hash(), | ||||
| 		CreationTime: config.Now(), | ||||
| 		IssuerKeyId:  &signer.PrivateKey.KeyId, | ||||
| 	} | ||||
| 	if err := sig.SignUserId(identity, e.PrimaryKey, signer.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 { | ||||
| 	reasonCode := uint8(reason) | ||||
| 	revSig := &packet.Signature{ | ||||
| 		Version:              e.PrimaryKey.Version, | ||||
| 		CreationTime:         config.Now(), | ||||
| 		SigType:              packet.SigTypeKeyRevocation, | ||||
| 		PubKeyAlgo:           packet.PubKeyAlgoRSA, | ||||
| 		Hash:                 config.Hash(), | ||||
| 		RevocationReason:     &reasonCode, | ||||
| 		RevocationReasonText: reasonText, | ||||
| 		IssuerKeyId:          &e.PrimaryKey.KeyId, | ||||
| 	} | ||||
| 
 | ||||
| 	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") | ||||
| 	} | ||||
| 
 | ||||
| 	reasonCode := uint8(reason) | ||||
| 	revSig := &packet.Signature{ | ||||
| 		Version:              e.PrimaryKey.Version, | ||||
| 		CreationTime:         config.Now(), | ||||
| 		SigType:              packet.SigTypeSubkeyRevocation, | ||||
| 		PubKeyAlgo:           packet.PubKeyAlgoRSA, | ||||
| 		Hash:                 config.Hash(), | ||||
| 		RevocationReason:     &reasonCode, | ||||
| 		RevocationReasonText: reasonText, | ||||
| 		IssuerKeyId:          &e.PrimaryKey.KeyId, | ||||
| 	} | ||||
| 
 | ||||
| 	if err := revSig.RevokeKey(sk.PublicKey, e.PrivateKey, config); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	sk.Sig = revSig | ||||
| 	return nil | ||||
| } | ||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										56
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/aead_config.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										56
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/aead_config.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							|  | @ -0,0 +1,56 @@ | |||
| // Copyright (C) 2019 ProtonTech AG
 | ||||
| 
 | ||||
| package packet | ||||
| 
 | ||||
| import "math/bits" | ||||
| 
 | ||||
| // 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 conf == nil || conf.DefaultMode == 0 { | ||||
| 		return AEADModeEAX | ||||
| 	} | ||||
| 	mode := conf.DefaultMode | ||||
| 	if mode != AEADModeEAX && mode != AEADModeOCB && | ||||
| 		mode != AEADModeExperimentalGCM { | ||||
| 		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)
 | ||||
| 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 > 27: | ||||
| 		exponent = 27 | ||||
| 	} | ||||
| 
 | ||||
| 	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) | ||||
| } | ||||
							
								
								
									
										364
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/aead_encrypted.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										364
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/aead_encrypted.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							|  | @ -0,0 +1,364 @@ | |||
| // Copyright (C) 2019 ProtonTech AG
 | ||||
| 
 | ||||
| package packet | ||||
| 
 | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"crypto/cipher" | ||||
| 	"crypto/rand" | ||||
| 	"encoding/binary" | ||||
| 	"io" | ||||
| 
 | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/errors" | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/internal/algorithm" | ||||
| ) | ||||
| 
 | ||||
| // AEADEncrypted represents an AEAD Encrypted Packet (tag 20, RFC4880bis-5.16).
 | ||||
| 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 | ||||
| 
 | ||||
| // 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
 | ||||
| 	bytesProcessed int          // Amount of plaintext bytes encrypted/decrypted
 | ||||
| 	buffer         bytes.Buffer // Buffered bytes accross chunks
 | ||||
| } | ||||
| 
 | ||||
| // 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
 | ||||
| } | ||||
| 
 | ||||
| // 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 | ||||
| } | ||||
| 
 | ||||
| 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.NonceLength() | ||||
| 	if nonceLen == 0 { | ||||
| 		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 = byte(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), | ||||
| 		}, | ||||
| 		reader:      ae.Contents, | ||||
| 		peekedBytes: peekedBytes}, nil | ||||
| } | ||||
| 
 | ||||
| // 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 | ||||
| } | ||||
| 
 | ||||
| // SerializeAEADEncrypted initializes the aeadCrypter and returns a writer.
 | ||||
| // This writer encrypts and writes bytes (see aeadEncrypter.Write()).
 | ||||
| func SerializeAEADEncrypted(w io.Writer, key []byte, cipher CipherFunction, mode AEADMode, config *Config) (io.WriteCloser, error) { | ||||
| 	writeCloser := noOpCloser{w} | ||||
| 	writer, err := serializeStreamHeader(writeCloser, packetTypeAEADEncrypted) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	// Data for en/decryption: tag, version, cipher, aead mode, chunk size
 | ||||
| 	aeadConf := config.AEAD() | ||||
| 	prefix := []byte{ | ||||
| 		0xD4, | ||||
| 		aeadEncryptedVersion, | ||||
| 		byte(config.Cipher()), | ||||
| 		byte(aeadConf.Mode()), | ||||
| 		aeadConf.ChunkSizeByte(), | ||||
| 	} | ||||
| 	n, err := writer.Write(prefix[1:]) | ||||
| 	if err != nil || n < 4 { | ||||
| 		return nil, errors.AEADError("could not write AEAD headers") | ||||
| 	} | ||||
| 	// Sample nonce
 | ||||
| 	nonceLen := aeadConf.Mode().NonceLength() | ||||
| 	nonce := make([]byte, nonceLen) | ||||
| 	n, err = rand.Read(nonce) | ||||
| 	if err != nil { | ||||
| 		panic("Could not sample random nonce") | ||||
| 	} | ||||
| 	_, err = writer.Write(nonce) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	blockCipher := CipherFunction(config.Cipher()).new(key) | ||||
| 	alg := AEADMode(aeadConf.Mode()).new(blockCipher) | ||||
| 
 | ||||
| 	chunkSize := decodeAEADChunkSize(aeadConf.ChunkSizeByte()) | ||||
| 	return &aeadEncrypter{ | ||||
| 		aeadCrypter: aeadCrypter{ | ||||
| 			aead:           alg, | ||||
| 			chunkSize:      chunkSize, | ||||
| 			associatedData: prefix, | ||||
| 			chunkIndex:     make([]byte, 8), | ||||
| 			initialNonce:   nonce, | ||||
| 		}, | ||||
| 		writer: writer}, nil | ||||
| } | ||||
| 
 | ||||
| // 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, index, total number of encrypted octets).
 | ||||
| 	adata := append(aw.associatedData[:], aw.chunkIndex[:]...) | ||||
| 	adata = append(adata, make([]byte, 8)...) | ||||
| 	binary.BigEndian.PutUint64(adata[13:], uint64(aw.bytesProcessed)) | ||||
| 	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 := 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 | ||||
| } | ||||
| 
 | ||||
| // openChunk decrypts and checks integrity of an encrypted chunk, returning
 | ||||
| // the underlying plaintext and an error. It access 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 := 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, index, and octets
 | ||||
| 	amountBytes := make([]byte, 8) | ||||
| 	binary.BigEndian.PutUint64(amountBytes, uint64(ar.bytesProcessed)) | ||||
| 	adata := append(ar.associatedData, ar.chunkIndex...) | ||||
| 	adata = append(adata, amountBytes...) | ||||
| 	nonce := ar.computeNextNonce() | ||||
| 	_, err := ar.aead.Open(nil, nonce, tag, adata) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // Associated data 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} | ||||
| } | ||||
| 
 | ||||
| // 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) { | ||||
| 	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 perfoms 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") | ||||
| } | ||||
							
								
								
									
										123
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/compressed.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										123
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/compressed.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							|  | @ -0,0 +1,123 @@ | |||
| // 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 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,167 @@ | |||
| // 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" | ||||
| ) | ||||
| 
 | ||||
| // 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 | ||||
| 	// S2KCount is only used for symmetric encryption. It
 | ||||
| 	// determines the strength of the passphrase stretching when
 | ||||
| 	// the said passphrase is hashed to produce a key. S2KCount
 | ||||
| 	// should be between 1024 and 65011712, inclusive. If Config
 | ||||
| 	// is nil or S2KCount is 0, the value 65536 used. Not all
 | ||||
| 	// values in the above range can be represented. S2KCount will
 | ||||
| 	// be rounded up to the next representable value if it cannot
 | ||||
| 	// be encoded exactly. When set, it is strongly encrouraged to
 | ||||
| 	// use a value that is at least 65536. See RFC 4880 Section
 | ||||
| 	// 3.7.1.3.
 | ||||
| 	S2KCount int | ||||
| 	// 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 | ||||
| 	// 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 | ||||
| } | ||||
| 
 | ||||
| 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() | ||||
| 	} | ||||
| 	return c.Time() | ||||
| } | ||||
| 
 | ||||
| // 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) PasswordHashIterations() int { | ||||
| 	if c == nil || c.S2KCount == 0 { | ||||
| 		return 0 | ||||
| 	} | ||||
| 	return c.S2KCount | ||||
| } | ||||
| 
 | ||||
| func (c *Config) RSAModulusBits() int { | ||||
| 	if c == nil || c.RSABits == 0 { | ||||
| 		return 2048 | ||||
| 	} | ||||
| 	return c.RSABits | ||||
| } | ||||
| 
 | ||||
| func (c *Config) PublicKeyAlgorithm() PublicKeyAlgorithm { | ||||
| 	if c == nil || c.Algorithm == 0 { | ||||
| 		return PubKeyAlgoRSA | ||||
| 	} | ||||
| 	return c.Algorithm | ||||
| } | ||||
| 
 | ||||
| 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 | ||||
| } | ||||
							
								
								
									
										282
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/encrypted_key.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										282
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/encrypted_key.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							|  | @ -0,0 +1,282 @@ | |||
| // 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
 | ||||
| 	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]) | ||||
| 	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,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++ | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										73
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/one_pass_signature.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										73
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/one_pass_signature.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							|  | @ -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/s2k" | ||||
| 	"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 = s2k.HashIdToHash(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 = s2k.HashToHashId(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 | ||||
| } | ||||
|  | @ -0,0 +1,162 @@ | |||
| // 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 ( | ||||
| 	"bytes" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 
 | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/errors" | ||||
| ) | ||||
| 
 | ||||
| // OpaquePacket represents an OpenPGP packet as raw, unparsed data. This is
 | ||||
| // useful for splitting and storing the original packet contents separately,
 | ||||
| // handling unsupported packet types or accessing parts of the packet not yet
 | ||||
| // implemented by this package.
 | ||||
| type OpaquePacket struct { | ||||
| 	// Packet type
 | ||||
| 	Tag uint8 | ||||
| 	// Reason why the packet was parsed opaquely
 | ||||
| 	Reason error | ||||
| 	// Binary contents of the packet data
 | ||||
| 	Contents []byte | ||||
| } | ||||
| 
 | ||||
| func (op *OpaquePacket) parse(r io.Reader) (err error) { | ||||
| 	op.Contents, err = ioutil.ReadAll(r) | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // Serialize marshals the packet to a writer in its original form, including
 | ||||
| // the packet header.
 | ||||
| func (op *OpaquePacket) Serialize(w io.Writer) (err error) { | ||||
| 	err = serializeHeader(w, packetType(op.Tag), len(op.Contents)) | ||||
| 	if err == nil { | ||||
| 		_, err = w.Write(op.Contents) | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // Parse attempts to parse the opaque contents into a structure supported by
 | ||||
| // this package. If the packet is not known then the result will be another
 | ||||
| // OpaquePacket.
 | ||||
| func (op *OpaquePacket) Parse() (p Packet, err error) { | ||||
| 	hdr := bytes.NewBuffer(nil) | ||||
| 	err = serializeHeader(hdr, packetType(op.Tag), len(op.Contents)) | ||||
| 	if err != nil { | ||||
| 		op.Reason = err | ||||
| 		return op, err | ||||
| 	} | ||||
| 	p, err = Read(io.MultiReader(hdr, bytes.NewBuffer(op.Contents))) | ||||
| 	if err != nil { | ||||
| 		op.Reason = err | ||||
| 		p = op | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // OpaqueReader reads OpaquePackets from an io.Reader.
 | ||||
| type OpaqueReader struct { | ||||
| 	r io.Reader | ||||
| } | ||||
| 
 | ||||
| func NewOpaqueReader(r io.Reader) *OpaqueReader { | ||||
| 	return &OpaqueReader{r: r} | ||||
| } | ||||
| 
 | ||||
| // Read the next OpaquePacket.
 | ||||
| func (or *OpaqueReader) Next() (op *OpaquePacket, err error) { | ||||
| 	tag, _, contents, err := readHeader(or.r) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	op = &OpaquePacket{Tag: uint8(tag), Reason: err} | ||||
| 	err = op.parse(contents) | ||||
| 	if err != nil { | ||||
| 		consumeAll(contents) | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // OpaqueSubpacket represents an unparsed OpenPGP subpacket,
 | ||||
| // as found in signature and user attribute packets.
 | ||||
| type OpaqueSubpacket struct { | ||||
| 	SubType  uint8 | ||||
| 	Contents []byte | ||||
| } | ||||
| 
 | ||||
| // OpaqueSubpackets extracts opaque, unparsed OpenPGP subpackets from
 | ||||
| // their byte representation.
 | ||||
| func OpaqueSubpackets(contents []byte) (result []*OpaqueSubpacket, err error) { | ||||
| 	var ( | ||||
| 		subHeaderLen int | ||||
| 		subPacket    *OpaqueSubpacket | ||||
| 	) | ||||
| 	for len(contents) > 0 { | ||||
| 		subHeaderLen, subPacket, err = nextSubpacket(contents) | ||||
| 		if err != nil { | ||||
| 			break | ||||
| 		} | ||||
| 		result = append(result, subPacket) | ||||
| 		contents = contents[subHeaderLen+len(subPacket.Contents):] | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| func nextSubpacket(contents []byte) (subHeaderLen int, subPacket *OpaqueSubpacket, err error) { | ||||
| 	// RFC 4880, section 5.2.3.1
 | ||||
| 	var subLen uint32 | ||||
| 	if len(contents) < 1 { | ||||
| 		goto Truncated | ||||
| 	} | ||||
| 	subPacket = &OpaqueSubpacket{} | ||||
| 	switch { | ||||
| 	case contents[0] < 192: | ||||
| 		subHeaderLen = 2 // 1 length byte, 1 subtype byte
 | ||||
| 		if len(contents) < subHeaderLen { | ||||
| 			goto Truncated | ||||
| 		} | ||||
| 		subLen = uint32(contents[0]) | ||||
| 		contents = contents[1:] | ||||
| 	case contents[0] < 255: | ||||
| 		subHeaderLen = 3 // 2 length bytes, 1 subtype
 | ||||
| 		if len(contents) < subHeaderLen { | ||||
| 			goto Truncated | ||||
| 		} | ||||
| 		subLen = uint32(contents[0]-192)<<8 + uint32(contents[1]) + 192 | ||||
| 		contents = contents[2:] | ||||
| 	default: | ||||
| 		subHeaderLen = 6 // 5 length bytes, 1 subtype
 | ||||
| 		if len(contents) < subHeaderLen { | ||||
| 			goto Truncated | ||||
| 		} | ||||
| 		subLen = uint32(contents[1])<<24 | | ||||
| 			uint32(contents[2])<<16 | | ||||
| 			uint32(contents[3])<<8 | | ||||
| 			uint32(contents[4]) | ||||
| 		contents = contents[5:] | ||||
| 	} | ||||
| 	if subLen > uint32(len(contents)) || subLen == 0 { | ||||
| 		goto Truncated | ||||
| 	} | ||||
| 	subPacket.SubType = contents[0] | ||||
| 	subPacket.Contents = contents[1:subLen] | ||||
| 	return | ||||
| Truncated: | ||||
| 	err = errors.StructuralError("subpacket truncated") | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| func (osp *OpaqueSubpacket) Serialize(w io.Writer) (err error) { | ||||
| 	buf := make([]byte, 6) | ||||
| 	n := serializeSubpacketLength(buf, len(osp.Contents)+1) | ||||
| 	buf[n] = osp.SubType | ||||
| 	if _, err = w.Write(buf[:n+1]); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	_, err = w.Write(osp.Contents) | ||||
| 	return | ||||
| } | ||||
|  | @ -0,0 +1,522 @@ | |||
| // 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 implements parsing and serialization of OpenPGP packets, as
 | ||||
| // specified in RFC 4880.
 | ||||
| package packet // import "github.com/ProtonMail/go-crypto/openpgp/packet"
 | ||||
| 
 | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"crypto/cipher" | ||||
| 	"crypto/rsa" | ||||
| 	"io" | ||||
| 
 | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/errors" | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/internal/algorithm" | ||||
| ) | ||||
| 
 | ||||
| // readFull is the same as io.ReadFull except that reading zero bytes returns
 | ||||
| // ErrUnexpectedEOF rather than EOF.
 | ||||
| func readFull(r io.Reader, buf []byte) (n int, err error) { | ||||
| 	n, err = io.ReadFull(r, buf) | ||||
| 	if err == io.EOF { | ||||
| 		err = io.ErrUnexpectedEOF | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // readLength reads an OpenPGP length from r. See RFC 4880, section 4.2.2.
 | ||||
| func readLength(r io.Reader) (length int64, isPartial bool, err error) { | ||||
| 	var buf [4]byte | ||||
| 	_, err = readFull(r, buf[:1]) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	switch { | ||||
| 	case buf[0] < 192: | ||||
| 		length = int64(buf[0]) | ||||
| 	case buf[0] < 224: | ||||
| 		length = int64(buf[0]-192) << 8 | ||||
| 		_, err = readFull(r, buf[0:1]) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		length += int64(buf[0]) + 192 | ||||
| 	case buf[0] < 255: | ||||
| 		length = int64(1) << (buf[0] & 0x1f) | ||||
| 		isPartial = true | ||||
| 	default: | ||||
| 		_, err = readFull(r, buf[0:4]) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		length = int64(buf[0])<<24 | | ||||
| 			int64(buf[1])<<16 | | ||||
| 			int64(buf[2])<<8 | | ||||
| 			int64(buf[3]) | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // partialLengthReader wraps an io.Reader and handles OpenPGP partial lengths.
 | ||||
| // The continuation lengths are parsed and removed from the stream and EOF is
 | ||||
| // returned at the end of the packet. See RFC 4880, section 4.2.2.4.
 | ||||
| type partialLengthReader struct { | ||||
| 	r         io.Reader | ||||
| 	remaining int64 | ||||
| 	isPartial bool | ||||
| } | ||||
| 
 | ||||
| func (r *partialLengthReader) Read(p []byte) (n int, err error) { | ||||
| 	for r.remaining == 0 { | ||||
| 		if !r.isPartial { | ||||
| 			return 0, io.EOF | ||||
| 		} | ||||
| 		r.remaining, r.isPartial, err = readLength(r.r) | ||||
| 		if err != nil { | ||||
| 			return 0, err | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	toRead := int64(len(p)) | ||||
| 	if toRead > r.remaining { | ||||
| 		toRead = r.remaining | ||||
| 	} | ||||
| 
 | ||||
| 	n, err = r.r.Read(p[:int(toRead)]) | ||||
| 	r.remaining -= int64(n) | ||||
| 	if n < int(toRead) && err == io.EOF { | ||||
| 		err = io.ErrUnexpectedEOF | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // partialLengthWriter writes a stream of data using OpenPGP partial lengths.
 | ||||
| // See RFC 4880, section 4.2.2.4.
 | ||||
| type partialLengthWriter struct { | ||||
| 	w          io.WriteCloser | ||||
| 	buf        bytes.Buffer | ||||
| 	lengthByte [1]byte | ||||
| } | ||||
| 
 | ||||
| func (w *partialLengthWriter) Write(p []byte) (n int, err error) { | ||||
| 	bufLen := w.buf.Len() | ||||
| 	if bufLen > 512 { | ||||
| 		for power := uint(30); ; power-- { | ||||
| 			l := 1 << power | ||||
| 			if bufLen >= l { | ||||
| 				w.lengthByte[0] = 224 + uint8(power) | ||||
| 				_, err = w.w.Write(w.lengthByte[:]) | ||||
| 				if err != nil { | ||||
| 					return | ||||
| 				} | ||||
| 				var m int | ||||
| 				m, err = w.w.Write(w.buf.Next(l)) | ||||
| 				if err != nil { | ||||
| 					return | ||||
| 				} | ||||
| 				if m != l { | ||||
| 					return 0, io.ErrShortWrite | ||||
| 				} | ||||
| 				break | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return w.buf.Write(p) | ||||
| } | ||||
| 
 | ||||
| func (w *partialLengthWriter) Close() (err error) { | ||||
| 	len := w.buf.Len() | ||||
| 	err = serializeLength(w.w, len) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	_, err = w.buf.WriteTo(w.w) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return w.w.Close() | ||||
| } | ||||
| 
 | ||||
| // A spanReader is an io.LimitReader, but it returns ErrUnexpectedEOF if the
 | ||||
| // underlying Reader returns EOF before the limit has been reached.
 | ||||
| type spanReader struct { | ||||
| 	r io.Reader | ||||
| 	n int64 | ||||
| } | ||||
| 
 | ||||
| func (l *spanReader) Read(p []byte) (n int, err error) { | ||||
| 	if l.n <= 0 { | ||||
| 		return 0, io.EOF | ||||
| 	} | ||||
| 	if int64(len(p)) > l.n { | ||||
| 		p = p[0:l.n] | ||||
| 	} | ||||
| 	n, err = l.r.Read(p) | ||||
| 	l.n -= int64(n) | ||||
| 	if l.n > 0 && err == io.EOF { | ||||
| 		err = io.ErrUnexpectedEOF | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // readHeader parses a packet header and returns an io.Reader which will return
 | ||||
| // the contents of the packet. See RFC 4880, section 4.2.
 | ||||
| func readHeader(r io.Reader) (tag packetType, length int64, contents io.Reader, err error) { | ||||
| 	var buf [4]byte | ||||
| 	_, err = io.ReadFull(r, buf[:1]) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	if buf[0]&0x80 == 0 { | ||||
| 		err = errors.StructuralError("tag byte does not have MSB set") | ||||
| 		return | ||||
| 	} | ||||
| 	if buf[0]&0x40 == 0 { | ||||
| 		// Old format packet
 | ||||
| 		tag = packetType((buf[0] & 0x3f) >> 2) | ||||
| 		lengthType := buf[0] & 3 | ||||
| 		if lengthType == 3 { | ||||
| 			length = -1 | ||||
| 			contents = r | ||||
| 			return | ||||
| 		} | ||||
| 		lengthBytes := 1 << lengthType | ||||
| 		_, err = readFull(r, buf[0:lengthBytes]) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		for i := 0; i < lengthBytes; i++ { | ||||
| 			length <<= 8 | ||||
| 			length |= int64(buf[i]) | ||||
| 		} | ||||
| 		contents = &spanReader{r, length} | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	// New format packet
 | ||||
| 	tag = packetType(buf[0] & 0x3f) | ||||
| 	length, isPartial, err := readLength(r) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	if isPartial { | ||||
| 		contents = &partialLengthReader{ | ||||
| 			remaining: length, | ||||
| 			isPartial: true, | ||||
| 			r:         r, | ||||
| 		} | ||||
| 		length = -1 | ||||
| 	} else { | ||||
| 		contents = &spanReader{r, length} | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // serializeHeader writes an OpenPGP packet header to w. See RFC 4880, section
 | ||||
| // 4.2.
 | ||||
| func serializeHeader(w io.Writer, ptype packetType, length int) (err error) { | ||||
| 	err = serializeType(w, ptype) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	return serializeLength(w, length) | ||||
| } | ||||
| 
 | ||||
| // serializeType writes an OpenPGP packet type to w. See RFC 4880, section
 | ||||
| // 4.2.
 | ||||
| func serializeType(w io.Writer, ptype packetType) (err error) { | ||||
| 	var buf [1]byte | ||||
| 	buf[0] = 0x80 | 0x40 | byte(ptype) | ||||
| 	_, err = w.Write(buf[:]) | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // serializeLength writes an OpenPGP packet length to w. See RFC 4880, section
 | ||||
| // 4.2.2.
 | ||||
| func serializeLength(w io.Writer, length int) (err error) { | ||||
| 	var buf [5]byte | ||||
| 	var n int | ||||
| 
 | ||||
| 	if length < 192 { | ||||
| 		buf[0] = byte(length) | ||||
| 		n = 1 | ||||
| 	} else if length < 8384 { | ||||
| 		length -= 192 | ||||
| 		buf[0] = 192 + byte(length>>8) | ||||
| 		buf[1] = byte(length) | ||||
| 		n = 2 | ||||
| 	} else { | ||||
| 		buf[0] = 255 | ||||
| 		buf[1] = byte(length >> 24) | ||||
| 		buf[2] = byte(length >> 16) | ||||
| 		buf[3] = byte(length >> 8) | ||||
| 		buf[4] = byte(length) | ||||
| 		n = 5 | ||||
| 	} | ||||
| 
 | ||||
| 	_, err = w.Write(buf[:n]) | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // serializeStreamHeader writes an OpenPGP packet header to w where the
 | ||||
| // length of the packet is unknown. It returns a io.WriteCloser which can be
 | ||||
| // used to write the contents of the packet. See RFC 4880, section 4.2.
 | ||||
| func serializeStreamHeader(w io.WriteCloser, ptype packetType) (out io.WriteCloser, err error) { | ||||
| 	err = serializeType(w, ptype) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	out = &partialLengthWriter{w: w} | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // Packet represents an OpenPGP packet. Users are expected to try casting
 | ||||
| // instances of this interface to specific packet types.
 | ||||
| type Packet interface { | ||||
| 	parse(io.Reader) error | ||||
| } | ||||
| 
 | ||||
| // consumeAll reads from the given Reader until error, returning the number of
 | ||||
| // bytes read.
 | ||||
| func consumeAll(r io.Reader) (n int64, err error) { | ||||
| 	var m int | ||||
| 	var buf [1024]byte | ||||
| 
 | ||||
| 	for { | ||||
| 		m, err = r.Read(buf[:]) | ||||
| 		n += int64(m) | ||||
| 		if err == io.EOF { | ||||
| 			err = nil | ||||
| 			return | ||||
| 		} | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // packetType represents the numeric ids of the different OpenPGP packet types. See
 | ||||
| // http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-2
 | ||||
| type packetType uint8 | ||||
| 
 | ||||
| const ( | ||||
| 	packetTypeEncryptedKey              packetType = 1 | ||||
| 	packetTypeSignature                 packetType = 2 | ||||
| 	packetTypeSymmetricKeyEncrypted     packetType = 3 | ||||
| 	packetTypeOnePassSignature          packetType = 4 | ||||
| 	packetTypePrivateKey                packetType = 5 | ||||
| 	packetTypePublicKey                 packetType = 6 | ||||
| 	packetTypePrivateSubkey             packetType = 7 | ||||
| 	packetTypeCompressed                packetType = 8 | ||||
| 	packetTypeSymmetricallyEncrypted    packetType = 9 | ||||
| 	packetTypeLiteralData               packetType = 11 | ||||
| 	packetTypeUserId                    packetType = 13 | ||||
| 	packetTypePublicSubkey              packetType = 14 | ||||
| 	packetTypeUserAttribute             packetType = 17 | ||||
| 	packetTypeSymmetricallyEncryptedMDC packetType = 18 | ||||
| 	packetTypeAEADEncrypted             packetType = 20 | ||||
| ) | ||||
| 
 | ||||
| // EncryptedDataPacket holds encrypted data. It is currently implemented by
 | ||||
| // SymmetricallyEncrypted and AEADEncrypted.
 | ||||
| type EncryptedDataPacket interface { | ||||
| 	Decrypt(CipherFunction, []byte) (io.ReadCloser, error) | ||||
| } | ||||
| 
 | ||||
| // Read reads a single OpenPGP packet from the given io.Reader. If there is an
 | ||||
| // error parsing a packet, the whole packet is consumed from the input.
 | ||||
| func Read(r io.Reader) (p Packet, err error) { | ||||
| 	tag, _, contents, err := readHeader(r) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	switch tag { | ||||
| 	case packetTypeEncryptedKey: | ||||
| 		p = new(EncryptedKey) | ||||
| 	case packetTypeSignature: | ||||
| 		p = new(Signature) | ||||
| 	case packetTypeSymmetricKeyEncrypted: | ||||
| 		p = new(SymmetricKeyEncrypted) | ||||
| 	case packetTypeOnePassSignature: | ||||
| 		p = new(OnePassSignature) | ||||
| 	case packetTypePrivateKey, packetTypePrivateSubkey: | ||||
| 		pk := new(PrivateKey) | ||||
| 		if tag == packetTypePrivateSubkey { | ||||
| 			pk.IsSubkey = true | ||||
| 		} | ||||
| 		p = pk | ||||
| 	case packetTypePublicKey, packetTypePublicSubkey: | ||||
| 		isSubkey := tag == packetTypePublicSubkey | ||||
| 		p = &PublicKey{IsSubkey: isSubkey} | ||||
| 	case packetTypeCompressed: | ||||
| 		p = new(Compressed) | ||||
| 	case packetTypeSymmetricallyEncrypted: | ||||
| 		err = errors.UnsupportedError("Symmetrically encrypted packets without MDC are not supported") | ||||
| 	case packetTypeLiteralData: | ||||
| 		p = new(LiteralData) | ||||
| 	case packetTypeUserId: | ||||
| 		p = new(UserId) | ||||
| 	case packetTypeUserAttribute: | ||||
| 		p = new(UserAttribute) | ||||
| 	case packetTypeSymmetricallyEncryptedMDC: | ||||
| 		se := new(SymmetricallyEncrypted) | ||||
| 		se.MDC = true | ||||
| 		p = se | ||||
| 	case packetTypeAEADEncrypted: | ||||
| 		p = new(AEADEncrypted) | ||||
| 	default: | ||||
| 		err = errors.UnknownPacketTypeError(tag) | ||||
| 	} | ||||
| 	if p != nil { | ||||
| 		err = p.parse(contents) | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		consumeAll(contents) | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // SignatureType represents the different semantic meanings of an OpenPGP
 | ||||
| // signature. See RFC 4880, section 5.2.1.
 | ||||
| type SignatureType uint8 | ||||
| 
 | ||||
| const ( | ||||
| 	SigTypeBinary            SignatureType = 0x00 | ||||
| 	SigTypeText                            = 0x01 | ||||
| 	SigTypeGenericCert                     = 0x10 | ||||
| 	SigTypePersonaCert                     = 0x11 | ||||
| 	SigTypeCasualCert                      = 0x12 | ||||
| 	SigTypePositiveCert                    = 0x13 | ||||
| 	SigTypeSubkeyBinding                   = 0x18 | ||||
| 	SigTypePrimaryKeyBinding               = 0x19 | ||||
| 	SigTypeDirectSignature                 = 0x1F | ||||
| 	SigTypeKeyRevocation                   = 0x20 | ||||
| 	SigTypeSubkeyRevocation                = 0x28 | ||||
| ) | ||||
| 
 | ||||
| // PublicKeyAlgorithm represents the different public key system specified for
 | ||||
| // OpenPGP. See
 | ||||
| // http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-12
 | ||||
| type PublicKeyAlgorithm uint8 | ||||
| 
 | ||||
| const ( | ||||
| 	PubKeyAlgoRSA     PublicKeyAlgorithm = 1 | ||||
| 	PubKeyAlgoElGamal PublicKeyAlgorithm = 16 | ||||
| 	PubKeyAlgoDSA     PublicKeyAlgorithm = 17 | ||||
| 	// RFC 6637, Section 5.
 | ||||
| 	PubKeyAlgoECDH  PublicKeyAlgorithm = 18 | ||||
| 	PubKeyAlgoECDSA PublicKeyAlgorithm = 19 | ||||
| 	// https://www.ietf.org/archive/id/draft-koch-eddsa-for-openpgp-04.txt
 | ||||
| 	PubKeyAlgoEdDSA PublicKeyAlgorithm = 22 | ||||
| 
 | ||||
| 	// Deprecated in RFC 4880, Section 13.5. Use key flags instead.
 | ||||
| 	PubKeyAlgoRSAEncryptOnly PublicKeyAlgorithm = 2 | ||||
| 	PubKeyAlgoRSASignOnly    PublicKeyAlgorithm = 3 | ||||
| ) | ||||
| 
 | ||||
| // CanEncrypt returns true if it's possible to encrypt a message to a public
 | ||||
| // key of the given type.
 | ||||
| func (pka PublicKeyAlgorithm) CanEncrypt() bool { | ||||
| 	switch pka { | ||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoElGamal, PubKeyAlgoECDH: | ||||
| 		return true | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| // CanSign returns true if it's possible for a public key of the given type to
 | ||||
| // sign a message.
 | ||||
| func (pka PublicKeyAlgorithm) CanSign() bool { | ||||
| 	switch pka { | ||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA, PubKeyAlgoECDSA, PubKeyAlgoEdDSA: | ||||
| 		return true | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| // CipherFunction represents the different block ciphers specified for OpenPGP. See
 | ||||
| // http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-13
 | ||||
| type CipherFunction algorithm.CipherFunction | ||||
| 
 | ||||
| const ( | ||||
| 	Cipher3DES   CipherFunction = 2 | ||||
| 	CipherCAST5  CipherFunction = 3 | ||||
| 	CipherAES128 CipherFunction = 7 | ||||
| 	CipherAES192 CipherFunction = 8 | ||||
| 	CipherAES256 CipherFunction = 9 | ||||
| ) | ||||
| 
 | ||||
| // KeySize returns the key size, in bytes, of cipher.
 | ||||
| func (cipher CipherFunction) KeySize() int { | ||||
| 	return algorithm.CipherFunction(cipher).KeySize() | ||||
| } | ||||
| 
 | ||||
| // blockSize returns the block size, in bytes, of cipher.
 | ||||
| func (cipher CipherFunction) blockSize() int { | ||||
| 	return algorithm.CipherFunction(cipher).BlockSize() | ||||
| } | ||||
| 
 | ||||
| // new returns a fresh instance of the given cipher.
 | ||||
| func (cipher CipherFunction) new(key []byte) (block cipher.Block) { | ||||
| 	return algorithm.CipherFunction(cipher).New(key) | ||||
| } | ||||
| 
 | ||||
| // padToKeySize left-pads a MPI with zeroes to match the length of the
 | ||||
| // specified RSA public.
 | ||||
| func padToKeySize(pub *rsa.PublicKey, b []byte) []byte { | ||||
| 	k := (pub.N.BitLen() + 7) / 8 | ||||
| 	if len(b) >= k { | ||||
| 		return b | ||||
| 	} | ||||
| 	bb := make([]byte, k) | ||||
| 	copy(bb[len(bb)-len(b):], b) | ||||
| 	return bb | ||||
| } | ||||
| 
 | ||||
| // CompressionAlgo Represents the different compression algorithms
 | ||||
| // supported by OpenPGP (except for BZIP2, which is not currently
 | ||||
| // supported). See Section 9.3 of RFC 4880.
 | ||||
| type CompressionAlgo uint8 | ||||
| 
 | ||||
| const ( | ||||
| 	CompressionNone CompressionAlgo = 0 | ||||
| 	CompressionZIP  CompressionAlgo = 1 | ||||
| 	CompressionZLIB CompressionAlgo = 2 | ||||
| ) | ||||
| 
 | ||||
| // AEADMode represents the different Authenticated Encryption with Associated
 | ||||
| // Data specified for OpenPGP.
 | ||||
| type AEADMode algorithm.AEADMode | ||||
| 
 | ||||
| const ( | ||||
| 	AEADModeEAX             AEADMode = 1 | ||||
| 	AEADModeOCB             AEADMode = 2 | ||||
| 	AEADModeExperimentalGCM AEADMode = 100 | ||||
| ) | ||||
| 
 | ||||
| func (mode AEADMode) NonceLength() int { | ||||
| 	return algorithm.AEADMode(mode).NonceLength() | ||||
| } | ||||
| 
 | ||||
| func (mode AEADMode) TagLength() int { | ||||
| 	return algorithm.AEADMode(mode).TagLength() | ||||
| } | ||||
| 
 | ||||
| // new returns a fresh instance of the given mode.
 | ||||
| func (mode AEADMode) new(block cipher.Block) cipher.AEAD { | ||||
| 	return algorithm.AEADMode(mode).New(block) | ||||
| } | ||||
| 
 | ||||
| // ReasonForRevocation represents a revocation reason code as per RFC4880
 | ||||
| // section 5.2.3.23.
 | ||||
| type ReasonForRevocation uint8 | ||||
| 
 | ||||
| const ( | ||||
| 	NoReason       ReasonForRevocation = 0 | ||||
| 	KeySuperseded  ReasonForRevocation = 1 | ||||
| 	KeyCompromised ReasonForRevocation = 2 | ||||
| 	KeyRetired     ReasonForRevocation = 3 | ||||
| ) | ||||
							
								
								
									
										780
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/private_key.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										780
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/private_key.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							|  | @ -0,0 +1,780 @@ | |||
| // 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 ( | ||||
| 	"bytes" | ||||
| 	"crypto" | ||||
| 	"crypto/cipher" | ||||
| 	"crypto/dsa" | ||||
| 	"crypto/ecdsa" | ||||
| 	"crypto/elliptic" | ||||
| 	"crypto/rand" | ||||
| 	"crypto/rsa" | ||||
| 	"crypto/sha1" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"math/big" | ||||
| 	"strconv" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/internal/ecc" | ||||
| 	"golang.org/x/crypto/curve25519" | ||||
| 
 | ||||
| 	"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" | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/s2k" | ||||
| 	"golang.org/x/crypto/ed25519" | ||||
| ) | ||||
| 
 | ||||
| // PrivateKey represents a possibly encrypted private key. See RFC 4880,
 | ||||
| // section 5.5.3.
 | ||||
| type PrivateKey struct { | ||||
| 	PublicKey | ||||
| 	Encrypted     bool // if true then the private key is unavailable until Decrypt has been called.
 | ||||
| 	encryptedData []byte | ||||
| 	cipher        CipherFunction | ||||
| 	s2k           func(out, in []byte) | ||||
| 	// An *{rsa|dsa|elgamal|ecdh|ecdsa|ed25519}.PrivateKey or
 | ||||
| 	// crypto.Signer/crypto.Decrypter (Decryptor RSA only).
 | ||||
| 	PrivateKey   interface{} | ||||
| 	sha1Checksum bool | ||||
| 	iv           []byte | ||||
| 
 | ||||
| 	// Type of encryption of the S2K packet
 | ||||
| 	// Allowed values are 0 (Not encrypted), 254 (SHA1), or
 | ||||
| 	// 255 (2-byte checksum)
 | ||||
| 	s2kType S2KType | ||||
| 	// Full parameters of the S2K packet
 | ||||
| 	s2kParams *s2k.Params | ||||
| } | ||||
| 
 | ||||
| //S2KType s2k packet type
 | ||||
| type S2KType uint8 | ||||
| 
 | ||||
| const ( | ||||
| 	// S2KNON unencrypt
 | ||||
| 	S2KNON S2KType = 0 | ||||
| 	// S2KSHA1 sha1 sum check
 | ||||
| 	S2KSHA1 S2KType = 254 | ||||
| 	// S2KCHECKSUM sum check
 | ||||
| 	S2KCHECKSUM S2KType = 255 | ||||
| ) | ||||
| 
 | ||||
| func NewRSAPrivateKey(creationTime time.Time, priv *rsa.PrivateKey) *PrivateKey { | ||||
| 	pk := new(PrivateKey) | ||||
| 	pk.PublicKey = *NewRSAPublicKey(creationTime, &priv.PublicKey) | ||||
| 	pk.PrivateKey = priv | ||||
| 	return pk | ||||
| } | ||||
| 
 | ||||
| func NewDSAPrivateKey(creationTime time.Time, priv *dsa.PrivateKey) *PrivateKey { | ||||
| 	pk := new(PrivateKey) | ||||
| 	pk.PublicKey = *NewDSAPublicKey(creationTime, &priv.PublicKey) | ||||
| 	pk.PrivateKey = priv | ||||
| 	return pk | ||||
| } | ||||
| 
 | ||||
| func NewElGamalPrivateKey(creationTime time.Time, priv *elgamal.PrivateKey) *PrivateKey { | ||||
| 	pk := new(PrivateKey) | ||||
| 	pk.PublicKey = *NewElGamalPublicKey(creationTime, &priv.PublicKey) | ||||
| 	pk.PrivateKey = priv | ||||
| 	return pk | ||||
| } | ||||
| 
 | ||||
| func NewECDSAPrivateKey(creationTime time.Time, priv *ecdsa.PrivateKey) *PrivateKey { | ||||
| 	pk := new(PrivateKey) | ||||
| 	pk.PublicKey = *NewECDSAPublicKey(creationTime, &priv.PublicKey) | ||||
| 	pk.PrivateKey = priv | ||||
| 	return pk | ||||
| } | ||||
| 
 | ||||
| func NewEdDSAPrivateKey(creationTime time.Time, priv *ed25519.PrivateKey) *PrivateKey { | ||||
| 	pk := new(PrivateKey) | ||||
| 	pub := priv.Public().(ed25519.PublicKey) | ||||
| 	pk.PublicKey = *NewEdDSAPublicKey(creationTime, &pub) | ||||
| 	pk.PrivateKey = priv | ||||
| 	return pk | ||||
| } | ||||
| 
 | ||||
| func NewECDHPrivateKey(creationTime time.Time, priv *ecdh.PrivateKey) *PrivateKey { | ||||
| 	pk := new(PrivateKey) | ||||
| 	pk.PublicKey = *NewECDHPublicKey(creationTime, &priv.PublicKey) | ||||
| 	pk.PrivateKey = priv | ||||
| 	return pk | ||||
| } | ||||
| 
 | ||||
| // NewSignerPrivateKey creates a PrivateKey from a crypto.Signer that
 | ||||
| // implements RSA, ECDSA or EdDSA.
 | ||||
| func NewSignerPrivateKey(creationTime time.Time, signer crypto.Signer) *PrivateKey { | ||||
| 	pk := new(PrivateKey) | ||||
| 	// In general, the public Keys should be used as pointers. We still
 | ||||
| 	// type-switch on the values, for backwards-compatibility.
 | ||||
| 	switch pubkey := signer.Public().(type) { | ||||
| 	case *rsa.PublicKey: | ||||
| 		pk.PublicKey = *NewRSAPublicKey(creationTime, pubkey) | ||||
| 	case rsa.PublicKey: | ||||
| 		pk.PublicKey = *NewRSAPublicKey(creationTime, &pubkey) | ||||
| 	case *ecdsa.PublicKey: | ||||
| 		pk.PublicKey = *NewECDSAPublicKey(creationTime, pubkey) | ||||
| 	case ecdsa.PublicKey: | ||||
| 		pk.PublicKey = *NewECDSAPublicKey(creationTime, &pubkey) | ||||
| 	case *ed25519.PublicKey: | ||||
| 		pk.PublicKey = *NewEdDSAPublicKey(creationTime, pubkey) | ||||
| 	case ed25519.PublicKey: | ||||
| 		pk.PublicKey = *NewEdDSAPublicKey(creationTime, &pubkey) | ||||
| 	default: | ||||
| 		panic("openpgp: unknown crypto.Signer type in NewSignerPrivateKey") | ||||
| 	} | ||||
| 	pk.PrivateKey = signer | ||||
| 	return pk | ||||
| } | ||||
| 
 | ||||
| // NewDecrypterPrivateKey creates a PrivateKey from a *{rsa|elgamal|ecdh}.PrivateKey.
 | ||||
| func NewDecrypterPrivateKey(creationTime time.Time, decrypter interface{}) *PrivateKey { | ||||
| 	pk := new(PrivateKey) | ||||
| 	switch priv := decrypter.(type) { | ||||
| 	case *rsa.PrivateKey: | ||||
| 		pk.PublicKey = *NewRSAPublicKey(creationTime, &priv.PublicKey) | ||||
| 	case *elgamal.PrivateKey: | ||||
| 		pk.PublicKey = *NewElGamalPublicKey(creationTime, &priv.PublicKey) | ||||
| 	case *ecdh.PrivateKey: | ||||
| 		pk.PublicKey = *NewECDHPublicKey(creationTime, &priv.PublicKey) | ||||
| 	default: | ||||
| 		panic("openpgp: unknown decrypter type in NewDecrypterPrivateKey") | ||||
| 	} | ||||
| 	pk.PrivateKey = decrypter | ||||
| 	return pk | ||||
| } | ||||
| 
 | ||||
| func (pk *PrivateKey) parse(r io.Reader) (err error) { | ||||
| 	err = (&pk.PublicKey).parse(r) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	v5 := pk.PublicKey.Version == 5 | ||||
| 
 | ||||
| 	var buf [1]byte | ||||
| 	_, err = readFull(r, buf[:]) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	pk.s2kType = S2KType(buf[0]) | ||||
| 	var optCount [1]byte | ||||
| 	if v5 { | ||||
| 		if _, err = readFull(r, optCount[:]); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	switch pk.s2kType { | ||||
| 	case S2KNON: | ||||
| 		pk.s2k = nil | ||||
| 		pk.Encrypted = false | ||||
| 	case S2KSHA1, S2KCHECKSUM: | ||||
| 		if v5 && pk.s2kType == S2KCHECKSUM { | ||||
| 			return errors.StructuralError("wrong s2k identifier for version 5") | ||||
| 		} | ||||
| 		_, err = readFull(r, buf[:]) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		pk.cipher = CipherFunction(buf[0]) | ||||
| 		pk.s2kParams, err = s2k.ParseIntoParams(r) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		if pk.s2kParams.Dummy() { | ||||
| 			return | ||||
| 		} | ||||
| 		pk.s2k, err = pk.s2kParams.Function() | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		pk.Encrypted = true | ||||
| 		if pk.s2kType == S2KSHA1 { | ||||
| 			pk.sha1Checksum = true | ||||
| 		} | ||||
| 	default: | ||||
| 		return errors.UnsupportedError("deprecated s2k function in private key") | ||||
| 	} | ||||
| 
 | ||||
| 	if pk.Encrypted { | ||||
| 		blockSize := pk.cipher.blockSize() | ||||
| 		if blockSize == 0 { | ||||
| 			return errors.UnsupportedError("unsupported cipher in private key: " + strconv.Itoa(int(pk.cipher))) | ||||
| 		} | ||||
| 		pk.iv = make([]byte, blockSize) | ||||
| 		_, err = readFull(r, pk.iv) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	var privateKeyData []byte | ||||
| 	if v5 { | ||||
| 		var n [4]byte /* secret material four octet count */ | ||||
| 		_, err = readFull(r, n[:]) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		count := uint32(uint32(n[0])<<24 | uint32(n[1])<<16 | uint32(n[2])<<8 | uint32(n[3])) | ||||
| 		if !pk.Encrypted { | ||||
| 			count = count + 2 /* two octet checksum */ | ||||
| 		} | ||||
| 		privateKeyData = make([]byte, count) | ||||
| 		_, err = readFull(r, privateKeyData) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 	} else { | ||||
| 		privateKeyData, err = ioutil.ReadAll(r) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 	if !pk.Encrypted { | ||||
| 		return pk.parsePrivateKey(privateKeyData) | ||||
| 	} | ||||
| 
 | ||||
| 	pk.encryptedData = privateKeyData | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // Dummy returns true if the private key is a dummy key. This is a GNU extension.
 | ||||
| func (pk *PrivateKey) Dummy() bool { | ||||
| 	return pk.s2kParams.Dummy() | ||||
| } | ||||
| 
 | ||||
| func mod64kHash(d []byte) uint16 { | ||||
| 	var h uint16 | ||||
| 	for _, b := range d { | ||||
| 		h += uint16(b) | ||||
| 	} | ||||
| 	return h | ||||
| } | ||||
| 
 | ||||
| func (pk *PrivateKey) Serialize(w io.Writer) (err error) { | ||||
| 	contents := bytes.NewBuffer(nil) | ||||
| 	err = pk.PublicKey.serializeWithoutHeaders(contents) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	if _, err = contents.Write([]byte{uint8(pk.s2kType)}); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	optional := bytes.NewBuffer(nil) | ||||
| 	if pk.Encrypted || pk.Dummy() { | ||||
| 		optional.Write([]byte{uint8(pk.cipher)}) | ||||
| 		if err := pk.s2kParams.Serialize(optional); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		if pk.Encrypted { | ||||
| 			optional.Write(pk.iv) | ||||
| 		} | ||||
| 	} | ||||
| 	if pk.Version == 5 { | ||||
| 		contents.Write([]byte{uint8(optional.Len())}) | ||||
| 	} | ||||
| 	io.Copy(contents, optional) | ||||
| 
 | ||||
| 	if !pk.Dummy() { | ||||
| 		l := 0 | ||||
| 		var priv []byte | ||||
| 		if !pk.Encrypted { | ||||
| 			buf := bytes.NewBuffer(nil) | ||||
| 			err = pk.serializePrivateKey(buf) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			l = buf.Len() | ||||
| 			if pk.sha1Checksum { | ||||
| 				h := sha1.New() | ||||
| 				h.Write(buf.Bytes()) | ||||
| 				buf.Write(h.Sum(nil)) | ||||
| 			} else { | ||||
| 				checksum := mod64kHash(buf.Bytes()) | ||||
| 				buf.Write([]byte{byte(checksum >> 8), byte(checksum)}) | ||||
| 			} | ||||
| 			priv = buf.Bytes() | ||||
| 		} else { | ||||
| 			priv, l = pk.encryptedData, len(pk.encryptedData) | ||||
| 		} | ||||
| 
 | ||||
| 		if pk.Version == 5 { | ||||
| 			contents.Write([]byte{byte(l >> 24), byte(l >> 16), byte(l >> 8), byte(l)}) | ||||
| 		} | ||||
| 		contents.Write(priv) | ||||
| 	} | ||||
| 
 | ||||
| 	ptype := packetTypePrivateKey | ||||
| 	if pk.IsSubkey { | ||||
| 		ptype = packetTypePrivateSubkey | ||||
| 	} | ||||
| 	err = serializeHeader(w, ptype, contents.Len()) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	_, err = io.Copy(w, contents) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| func serializeRSAPrivateKey(w io.Writer, priv *rsa.PrivateKey) error { | ||||
| 	if _, err := w.Write(new(encoding.MPI).SetBig(priv.D).EncodedBytes()); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if _, err := w.Write(new(encoding.MPI).SetBig(priv.Primes[1]).EncodedBytes()); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if _, err := w.Write(new(encoding.MPI).SetBig(priv.Primes[0]).EncodedBytes()); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	_, err := w.Write(new(encoding.MPI).SetBig(priv.Precomputed.Qinv).EncodedBytes()) | ||||
| 	return err | ||||
| } | ||||
| 
 | ||||
| func serializeDSAPrivateKey(w io.Writer, priv *dsa.PrivateKey) error { | ||||
| 	_, err := w.Write(new(encoding.MPI).SetBig(priv.X).EncodedBytes()) | ||||
| 	return err | ||||
| } | ||||
| 
 | ||||
| func serializeElGamalPrivateKey(w io.Writer, priv *elgamal.PrivateKey) error { | ||||
| 	_, err := w.Write(new(encoding.MPI).SetBig(priv.X).EncodedBytes()) | ||||
| 	return err | ||||
| } | ||||
| 
 | ||||
| func serializeECDSAPrivateKey(w io.Writer, priv *ecdsa.PrivateKey) error { | ||||
| 	_, err := w.Write(new(encoding.MPI).SetBig(priv.D).EncodedBytes()) | ||||
| 	return err | ||||
| } | ||||
| 
 | ||||
| func serializeEdDSAPrivateKey(w io.Writer, priv *ed25519.PrivateKey) error { | ||||
| 	keySize := ed25519.PrivateKeySize - ed25519.PublicKeySize | ||||
| 	_, err := w.Write(encoding.NewMPI((*priv)[:keySize]).EncodedBytes()) | ||||
| 	return err | ||||
| } | ||||
| 
 | ||||
| func serializeECDHPrivateKey(w io.Writer, priv *ecdh.PrivateKey) error { | ||||
| 	_, err := w.Write(encoding.NewMPI(priv.D).EncodedBytes()) | ||||
| 	return err | ||||
| } | ||||
| 
 | ||||
| // Decrypt decrypts an encrypted private key using a passphrase.
 | ||||
| func (pk *PrivateKey) Decrypt(passphrase []byte) error { | ||||
| 	if pk.Dummy() { | ||||
| 		return errors.ErrDummyPrivateKey("dummy key found") | ||||
| 	} | ||||
| 	if !pk.Encrypted { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	key := make([]byte, pk.cipher.KeySize()) | ||||
| 	pk.s2k(key, passphrase) | ||||
| 	block := pk.cipher.new(key) | ||||
| 	cfb := cipher.NewCFBDecrypter(block, pk.iv) | ||||
| 
 | ||||
| 	data := make([]byte, len(pk.encryptedData)) | ||||
| 	cfb.XORKeyStream(data, pk.encryptedData) | ||||
| 
 | ||||
| 	if pk.sha1Checksum { | ||||
| 		if len(data) < sha1.Size { | ||||
| 			return errors.StructuralError("truncated private key data") | ||||
| 		} | ||||
| 		h := sha1.New() | ||||
| 		h.Write(data[:len(data)-sha1.Size]) | ||||
| 		sum := h.Sum(nil) | ||||
| 		if !bytes.Equal(sum, data[len(data)-sha1.Size:]) { | ||||
| 			return errors.StructuralError("private key checksum failure") | ||||
| 		} | ||||
| 		data = data[:len(data)-sha1.Size] | ||||
| 	} else { | ||||
| 		if len(data) < 2 { | ||||
| 			return errors.StructuralError("truncated private key data") | ||||
| 		} | ||||
| 		var sum uint16 | ||||
| 		for i := 0; i < len(data)-2; i++ { | ||||
| 			sum += uint16(data[i]) | ||||
| 		} | ||||
| 		if data[len(data)-2] != uint8(sum>>8) || | ||||
| 			data[len(data)-1] != uint8(sum) { | ||||
| 			return errors.StructuralError("private key checksum failure") | ||||
| 		} | ||||
| 		data = data[:len(data)-2] | ||||
| 	} | ||||
| 
 | ||||
| 	err := pk.parsePrivateKey(data) | ||||
| 	if _, ok := err.(errors.KeyInvalidError); ok { | ||||
| 		return errors.KeyInvalidError("invalid key parameters") | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	// Mark key as unencrypted
 | ||||
| 	pk.s2kType = S2KNON | ||||
| 	pk.s2k = nil | ||||
| 	pk.Encrypted = false | ||||
| 	pk.encryptedData = nil | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // Encrypt encrypts an unencrypted private key using a passphrase.
 | ||||
| func (pk *PrivateKey) Encrypt(passphrase []byte) error { | ||||
| 	priv := bytes.NewBuffer(nil) | ||||
| 	err := pk.serializePrivateKey(priv) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	//Default config of private key encryption
 | ||||
| 	pk.cipher = CipherAES256 | ||||
| 	s2kConfig := &s2k.Config{ | ||||
| 		S2KMode:  3, //Iterated
 | ||||
| 		S2KCount: 65536, | ||||
| 		Hash:     crypto.SHA256, | ||||
| 	} | ||||
| 
 | ||||
| 	pk.s2kParams, err = s2k.Generate(rand.Reader, s2kConfig) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	privateKeyBytes := priv.Bytes() | ||||
| 	key := make([]byte, pk.cipher.KeySize()) | ||||
| 
 | ||||
| 	pk.sha1Checksum = true | ||||
| 	pk.s2k, err = pk.s2kParams.Function() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	pk.s2k(key, passphrase) | ||||
| 	block := pk.cipher.new(key) | ||||
| 	pk.iv = make([]byte, pk.cipher.blockSize()) | ||||
| 	_, err = rand.Read(pk.iv) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	cfb := cipher.NewCFBEncrypter(block, pk.iv) | ||||
| 
 | ||||
| 	if pk.sha1Checksum { | ||||
| 		pk.s2kType = S2KSHA1 | ||||
| 		h := sha1.New() | ||||
| 		h.Write(privateKeyBytes) | ||||
| 		sum := h.Sum(nil) | ||||
| 		privateKeyBytes = append(privateKeyBytes, sum...) | ||||
| 	} else { | ||||
| 		pk.s2kType = S2KCHECKSUM | ||||
| 		var sum uint16 | ||||
| 		for _, b := range privateKeyBytes { | ||||
| 			sum += uint16(b) | ||||
| 		} | ||||
| 		priv.Write([]byte{uint8(sum >> 8), uint8(sum)}) | ||||
| 	} | ||||
| 
 | ||||
| 	pk.encryptedData = make([]byte, len(privateKeyBytes)) | ||||
| 	cfb.XORKeyStream(pk.encryptedData, privateKeyBytes) | ||||
| 	pk.Encrypted = true | ||||
| 	pk.PrivateKey = nil | ||||
| 	return err | ||||
| } | ||||
| 
 | ||||
| func (pk *PrivateKey) serializePrivateKey(w io.Writer) (err error) { | ||||
| 	switch priv := pk.PrivateKey.(type) { | ||||
| 	case *rsa.PrivateKey: | ||||
| 		err = serializeRSAPrivateKey(w, priv) | ||||
| 	case *dsa.PrivateKey: | ||||
| 		err = serializeDSAPrivateKey(w, priv) | ||||
| 	case *elgamal.PrivateKey: | ||||
| 		err = serializeElGamalPrivateKey(w, priv) | ||||
| 	case *ecdsa.PrivateKey: | ||||
| 		err = serializeECDSAPrivateKey(w, priv) | ||||
| 	case *ed25519.PrivateKey: | ||||
| 		err = serializeEdDSAPrivateKey(w, priv) | ||||
| 	case *ecdh.PrivateKey: | ||||
| 		err = serializeECDHPrivateKey(w, priv) | ||||
| 	default: | ||||
| 		err = errors.InvalidArgumentError("unknown private key type") | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| func (pk *PrivateKey) parsePrivateKey(data []byte) (err error) { | ||||
| 	switch pk.PublicKey.PubKeyAlgo { | ||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoRSAEncryptOnly: | ||||
| 		return pk.parseRSAPrivateKey(data) | ||||
| 	case PubKeyAlgoDSA: | ||||
| 		return pk.parseDSAPrivateKey(data) | ||||
| 	case PubKeyAlgoElGamal: | ||||
| 		return pk.parseElGamalPrivateKey(data) | ||||
| 	case PubKeyAlgoECDSA: | ||||
| 		return pk.parseECDSAPrivateKey(data) | ||||
| 	case PubKeyAlgoECDH: | ||||
| 		return pk.parseECDHPrivateKey(data) | ||||
| 	case PubKeyAlgoEdDSA: | ||||
| 		return pk.parseEdDSAPrivateKey(data) | ||||
| 	} | ||||
| 	panic("impossible") | ||||
| } | ||||
| 
 | ||||
| func (pk *PrivateKey) parseRSAPrivateKey(data []byte) (err error) { | ||||
| 	rsaPub := pk.PublicKey.PublicKey.(*rsa.PublicKey) | ||||
| 	rsaPriv := new(rsa.PrivateKey) | ||||
| 	rsaPriv.PublicKey = *rsaPub | ||||
| 
 | ||||
| 	buf := bytes.NewBuffer(data) | ||||
| 	d := new(encoding.MPI) | ||||
| 	if _, err := d.ReadFrom(buf); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	p := new(encoding.MPI) | ||||
| 	if _, err := p.ReadFrom(buf); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	q := new(encoding.MPI) | ||||
| 	if _, err := q.ReadFrom(buf); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	rsaPriv.D = new(big.Int).SetBytes(d.Bytes()) | ||||
| 	rsaPriv.Primes = make([]*big.Int, 2) | ||||
| 	rsaPriv.Primes[0] = new(big.Int).SetBytes(p.Bytes()) | ||||
| 	rsaPriv.Primes[1] = new(big.Int).SetBytes(q.Bytes()) | ||||
| 	if err := rsaPriv.Validate(); err != nil { | ||||
| 		return errors.KeyInvalidError(err.Error()) | ||||
| 	} | ||||
| 	rsaPriv.Precompute() | ||||
| 	pk.PrivateKey = rsaPriv | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (pk *PrivateKey) parseDSAPrivateKey(data []byte) (err error) { | ||||
| 	dsaPub := pk.PublicKey.PublicKey.(*dsa.PublicKey) | ||||
| 	dsaPriv := new(dsa.PrivateKey) | ||||
| 	dsaPriv.PublicKey = *dsaPub | ||||
| 
 | ||||
| 	buf := bytes.NewBuffer(data) | ||||
| 	x := new(encoding.MPI) | ||||
| 	if _, err := x.ReadFrom(buf); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	dsaPriv.X = new(big.Int).SetBytes(x.Bytes()) | ||||
| 	if err := validateDSAParameters(dsaPriv); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	pk.PrivateKey = dsaPriv | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (pk *PrivateKey) parseElGamalPrivateKey(data []byte) (err error) { | ||||
| 	pub := pk.PublicKey.PublicKey.(*elgamal.PublicKey) | ||||
| 	priv := new(elgamal.PrivateKey) | ||||
| 	priv.PublicKey = *pub | ||||
| 
 | ||||
| 	buf := bytes.NewBuffer(data) | ||||
| 	x := new(encoding.MPI) | ||||
| 	if _, err := x.ReadFrom(buf); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	priv.X = new(big.Int).SetBytes(x.Bytes()) | ||||
| 	if err := validateElGamalParameters(priv); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	pk.PrivateKey = priv | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (pk *PrivateKey) parseECDSAPrivateKey(data []byte) (err error) { | ||||
| 	ecdsaPub := pk.PublicKey.PublicKey.(*ecdsa.PublicKey) | ||||
| 	ecdsaPriv := new(ecdsa.PrivateKey) | ||||
| 	ecdsaPriv.PublicKey = *ecdsaPub | ||||
| 
 | ||||
| 	buf := bytes.NewBuffer(data) | ||||
| 	d := new(encoding.MPI) | ||||
| 	if _, err := d.ReadFrom(buf); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	ecdsaPriv.D = new(big.Int).SetBytes(d.Bytes()) | ||||
| 	if err := validateECDSAParameters(ecdsaPriv); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	pk.PrivateKey = ecdsaPriv | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (pk *PrivateKey) parseECDHPrivateKey(data []byte) (err error) { | ||||
| 	ecdhPub := pk.PublicKey.PublicKey.(*ecdh.PublicKey) | ||||
| 	ecdhPriv := new(ecdh.PrivateKey) | ||||
| 	ecdhPriv.PublicKey = *ecdhPub | ||||
| 
 | ||||
| 	buf := bytes.NewBuffer(data) | ||||
| 	d := new(encoding.MPI) | ||||
| 	if _, err := d.ReadFrom(buf); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	ecdhPriv.D = d.Bytes() | ||||
| 	if err := validateECDHParameters(ecdhPriv); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	pk.PrivateKey = ecdhPriv | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (pk *PrivateKey) parseEdDSAPrivateKey(data []byte) (err error) { | ||||
| 	eddsaPub := pk.PublicKey.PublicKey.(*ed25519.PublicKey) | ||||
| 	eddsaPriv := make(ed25519.PrivateKey, ed25519.PrivateKeySize) | ||||
| 
 | ||||
| 	buf := bytes.NewBuffer(data) | ||||
| 	d := new(encoding.MPI) | ||||
| 	if _, err := d.ReadFrom(buf); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	priv := d.Bytes() | ||||
| 	copy(eddsaPriv[32-len(priv):32], priv) | ||||
| 	copy(eddsaPriv[32:], (*eddsaPub)[:]) | ||||
| 	if err := validateEdDSAParameters(&eddsaPriv); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	pk.PrivateKey = &eddsaPriv | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func validateECDSAParameters(priv *ecdsa.PrivateKey) error { | ||||
| 	return validateCommonECC(priv.Curve, priv.D.Bytes(), priv.X, priv.Y) | ||||
| } | ||||
| 
 | ||||
| func validateECDHParameters(priv *ecdh.PrivateKey) error { | ||||
| 	if priv.CurveType != ecc.Curve25519 { | ||||
| 		return validateCommonECC(priv.Curve, priv.D, priv.X, priv.Y) | ||||
| 	} | ||||
| 	// Handle Curve25519
 | ||||
| 	Q := priv.X.Bytes()[1:] | ||||
| 	var d [32]byte | ||||
| 	// Copy reversed d
 | ||||
| 	l := len(priv.D) | ||||
| 	for i := 0; i < l; i++ { | ||||
| 		d[i] = priv.D[l-i-1] | ||||
| 	} | ||||
| 	var expectedQ [32]byte | ||||
| 	curve25519.ScalarBaseMult(&expectedQ, &d) | ||||
| 	if !bytes.Equal(Q, expectedQ[:]) { | ||||
| 		return errors.KeyInvalidError("ECDH curve25519: invalid point") | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func validateCommonECC(curve elliptic.Curve, d []byte, X, Y *big.Int) error { | ||||
| 	// the public point should not be at infinity (0,0)
 | ||||
| 	zero := new(big.Int) | ||||
| 	if X.Cmp(zero) == 0 && Y.Cmp(zero) == 0 { | ||||
| 		return errors.KeyInvalidError(fmt.Sprintf("ecc (%s): infinity point", curve.Params().Name)) | ||||
| 	} | ||||
| 	// re-derive the public point Q' = (X,Y) = dG
 | ||||
| 	// to compare to declared Q in public key
 | ||||
| 	expectedX, expectedY := curve.ScalarBaseMult(d) | ||||
| 	if X.Cmp(expectedX) != 0 || Y.Cmp(expectedY) != 0 { | ||||
| 		return errors.KeyInvalidError(fmt.Sprintf("ecc (%s): invalid point", curve.Params().Name)) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func validateEdDSAParameters(priv *ed25519.PrivateKey) error { | ||||
| 	// In EdDSA, the serialized public point is stored as part of private key (together with the seed),
 | ||||
| 	// hence we can re-derive the key from the seed
 | ||||
| 	seed := priv.Seed() | ||||
| 	expectedPriv := ed25519.NewKeyFromSeed(seed) | ||||
| 	if !bytes.Equal(*priv, expectedPriv) { | ||||
| 		return errors.KeyInvalidError("eddsa: invalid point") | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func validateDSAParameters(priv *dsa.PrivateKey) error { | ||||
| 	p := priv.P // group prime
 | ||||
| 	q := priv.Q // subgroup order
 | ||||
| 	g := priv.G // g has order q mod p
 | ||||
| 	x := priv.X // secret
 | ||||
| 	y := priv.Y // y == g**x mod p
 | ||||
| 	one := big.NewInt(1) | ||||
| 	// expect g, y >= 2 and g < p
 | ||||
| 	if g.Cmp(one) <= 0 || y.Cmp(one) <= 0 || g.Cmp(p) > 0 { | ||||
| 		return errors.KeyInvalidError("dsa: invalid group") | ||||
| 	} | ||||
| 	// expect p > q
 | ||||
| 	if p.Cmp(q) <= 0 { | ||||
| 		return errors.KeyInvalidError("dsa: invalid group prime") | ||||
| 	} | ||||
| 	// q should be large enough and divide p-1
 | ||||
| 	pSub1 := new(big.Int).Sub(p, one) | ||||
| 	if q.BitLen() < 150 || new(big.Int).Mod(pSub1, q).Cmp(big.NewInt(0)) != 0 { | ||||
| 		return errors.KeyInvalidError("dsa: invalid order") | ||||
| 	} | ||||
| 	// confirm that g has order q mod p
 | ||||
| 	if !q.ProbablyPrime(32) || new(big.Int).Exp(g, q, p).Cmp(one) != 0 { | ||||
| 		return errors.KeyInvalidError("dsa: invalid order") | ||||
| 	} | ||||
| 	// check y
 | ||||
| 	if new(big.Int).Exp(g, x, p).Cmp(y) != 0 { | ||||
| 		return errors.KeyInvalidError("dsa: mismatching values") | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func validateElGamalParameters(priv *elgamal.PrivateKey) error { | ||||
| 	p := priv.P // group prime
 | ||||
| 	g := priv.G // g has order p-1 mod p
 | ||||
| 	x := priv.X // secret
 | ||||
| 	y := priv.Y // y == g**x mod p
 | ||||
| 	one := big.NewInt(1) | ||||
| 	// Expect g, y >= 2 and g < p
 | ||||
| 	if g.Cmp(one) <= 0 || y.Cmp(one) <= 0 || g.Cmp(p) > 0 { | ||||
| 		return errors.KeyInvalidError("elgamal: invalid group") | ||||
| 	} | ||||
| 	if p.BitLen() < 1024 { | ||||
| 		return errors.KeyInvalidError("elgamal: group order too small") | ||||
| 	} | ||||
| 	pSub1 := new(big.Int).Sub(p, one) | ||||
| 	if new(big.Int).Exp(g, pSub1, p).Cmp(one) != 0 { | ||||
| 		return errors.KeyInvalidError("elgamal: invalid group") | ||||
| 	} | ||||
| 	// Since p-1 is not prime, g might have a smaller order that divides p-1.
 | ||||
| 	// We cannot confirm the exact order of g, but we make sure it is not too small.
 | ||||
| 	gExpI := new(big.Int).Set(g) | ||||
| 	i := 1 | ||||
| 	threshold := 2 << 17 // we want order > threshold
 | ||||
| 	for i < threshold { | ||||
| 		i++ // we check every order to make sure key validation is not easily bypassed by guessing y'
 | ||||
| 		gExpI.Mod(new(big.Int).Mul(gExpI, g), p) | ||||
| 		if gExpI.Cmp(one) == 0 { | ||||
| 			return errors.KeyInvalidError("elgamal: order too small") | ||||
| 		} | ||||
| 	} | ||||
| 	// Check y
 | ||||
| 	if new(big.Int).Exp(g, x, p).Cmp(y) != 0 { | ||||
| 		return errors.KeyInvalidError("elgamal: mismatching values") | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										12
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/private_key_test_data.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										12
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/private_key_test_data.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							|  | @ -0,0 +1,12 @@ | |||
| package packet | ||||
| 
 | ||||
| // Generated with `gpg --export-secret-keys "Test Key 2"`
 | ||||
| const privKeyRSAHex = "9501fe044cc349a8010400b70ca0010e98c090008d45d1ee8f9113bd5861fd57b88bacb7c68658747663f1e1a3b5a98f32fda6472373c024b97359cd2efc88ff60f77751adfbf6af5e615e6a1408cfad8bf0cea30b0d5f53aa27ad59089ba9b15b7ebc2777a25d7b436144027e3bcd203909f147d0e332b240cf63d3395f5dfe0df0a6c04e8655af7eacdf0011010001fe0303024a252e7d475fd445607de39a265472aa74a9320ba2dac395faa687e9e0336aeb7e9a7397e511b5afd9dc84557c80ac0f3d4d7bfec5ae16f20d41c8c84a04552a33870b930420e230e179564f6d19bb153145e76c33ae993886c388832b0fa042ddda7f133924f3854481533e0ede31d51278c0519b29abc3bf53da673e13e3e1214b52413d179d7f66deee35cac8eacb060f78379d70ef4af8607e68131ff529439668fc39c9ce6dfef8a5ac234d234802cbfb749a26107db26406213ae5c06d4673253a3cbee1fcbae58d6ab77e38d6e2c0e7c6317c48e054edadb5a40d0d48acb44643d998139a8a66bb820be1f3f80185bc777d14b5954b60effe2448a036d565c6bc0b915fcea518acdd20ab07bc1529f561c58cd044f723109b93f6fd99f876ff891d64306b5d08f48bab59f38695e9109c4dec34013ba3153488ce070268381ba923ee1eb77125b36afcb4347ec3478c8f2735b06ef17351d872e577fa95d0c397c88c71b59629a36aec" | ||||
| 
 | ||||
| // Generated by `gpg --export-secret-keys` followed by a manual extraction of
 | ||||
| // the ElGamal subkey from the packets.
 | ||||
| const privKeyElGamalHex = "9d0157044df9ee1a100400eb8e136a58ec39b582629cdadf830bc64e0a94ed8103ca8bb247b27b11b46d1d25297ef4bcc3071785ba0c0bedfe89eabc5287fcc0edf81ab5896c1c8e4b20d27d79813c7aede75320b33eaeeaa586edc00fd1036c10133e6ba0ff277245d0d59d04b2b3421b7244aca5f4a8d870c6f1c1fbff9e1c26699a860b9504f35ca1d700030503fd1ededd3b840795be6d9ccbe3c51ee42e2f39233c432b831ddd9c4e72b7025a819317e47bf94f9ee316d7273b05d5fcf2999c3a681f519b1234bbfa6d359b4752bd9c3f77d6b6456cde152464763414ca130f4e91d91041432f90620fec0e6d6b5116076c2985d5aeaae13be492b9b329efcaf7ee25120159a0a30cd976b42d7afe030302dae7eb80db744d4960c4df930d57e87fe81412eaace9f900e6c839817a614ddb75ba6603b9417c33ea7b6c93967dfa2bcff3fa3c74a5ce2c962db65b03aece14c96cbd0038fc" | ||||
| 
 | ||||
| // pkcs1PrivKeyHex is a PKCS#1, RSA private key.
 | ||||
| // Generated by `openssl genrsa 1024 | openssl rsa -outform DER  | xxd -p`
 | ||||
| const pkcs1PrivKeyHex = "3082025d02010002818100e98edfa1c3b35884a54d0b36a6a603b0290fa85e49e30fa23fc94fef9c6790bc4849928607aa48d809da326fb42a969d06ad756b98b9c1a90f5d4a2b6d0ac05953c97f4da3120164a21a679793ce181c906dc01d235cc085ddcdf6ea06c389b6ab8885dfd685959e693138856a68a7e5db263337ff82a088d583a897cf2d59e9020301000102818100b6d5c9eb70b02d5369b3ee5b520a14490b5bde8a317d36f7e4c74b7460141311d1e5067735f8f01d6f5908b2b96fbd881f7a1ab9a84d82753e39e19e2d36856be960d05ac9ef8e8782ea1b6d65aee28fdfe1d61451e8cff0adfe84322f12cf455028b581cf60eb9e0e140ba5d21aeba6c2634d7c65318b9a665fc01c3191ca21024100fa5e818da3705b0fa33278bb28d4b6f6050388af2d4b75ec9375dd91ccf2e7d7068086a8b82a8f6282e4fbbdb8a7f2622eb97295249d87acea7f5f816f54d347024100eecf9406d7dc49cdfb95ab1eff4064de84c7a30f64b2798936a0d2018ba9eb52e4b636f82e96c49cc63b80b675e91e40d1b2e4017d4b9adaf33ab3d9cf1c214f024100c173704ace742c082323066226a4655226819a85304c542b9dacbeacbf5d1881ee863485fcf6f59f3a604f9b42289282067447f2b13dfeed3eab7851fc81e0550240741fc41f3fc002b382eed8730e33c5d8de40256e4accee846667f536832f711ab1d4590e7db91a8a116ac5bff3be13d3f9243ff2e976662aa9b395d907f8e9c9024046a5696c9ef882363e06c9fa4e2f5b580906452befba03f4a99d0f873697ef1f851d2226ca7934b30b7c3e80cb634a67172bbbf4781735fe3e09263e2dd723e7" | ||||
							
								
								
									
										825
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/public_key.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										825
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/public_key.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							|  | @ -0,0 +1,825 @@ | |||
| // 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/dsa" | ||||
| 	"crypto/ecdsa" | ||||
| 	"crypto/elliptic" | ||||
| 	"crypto/rsa" | ||||
| 	"crypto/sha1" | ||||
| 	"crypto/sha256" | ||||
| 	_ "crypto/sha512" | ||||
| 	"encoding/binary" | ||||
| 	"fmt" | ||||
| 	"hash" | ||||
| 	"io" | ||||
| 	"math/big" | ||||
| 	"strconv" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"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/algorithm" | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/internal/ecc" | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/internal/encoding" | ||||
| 	"golang.org/x/crypto/ed25519" | ||||
| ) | ||||
| 
 | ||||
| type kdfHashFunction byte | ||||
| type kdfAlgorithm byte | ||||
| 
 | ||||
| // PublicKey represents an OpenPGP public key. See RFC 4880, section 5.5.2.
 | ||||
| type PublicKey struct { | ||||
| 	Version      int | ||||
| 	CreationTime time.Time | ||||
| 	PubKeyAlgo   PublicKeyAlgorithm | ||||
| 	PublicKey    interface{} // *rsa.PublicKey, *dsa.PublicKey, *ecdsa.PublicKey or *eddsa.PublicKey
 | ||||
| 	Fingerprint  []byte | ||||
| 	KeyId        uint64 | ||||
| 	IsSubkey     bool | ||||
| 
 | ||||
| 	// RFC 4880 fields
 | ||||
| 	n, e, p, q, g, y encoding.Field | ||||
| 
 | ||||
| 	// RFC 6637 fields
 | ||||
| 	// oid contains the OID byte sequence identifying the elliptic curve used
 | ||||
| 	oid encoding.Field | ||||
| 
 | ||||
| 	// kdf stores key derivation function parameters
 | ||||
| 	// used for ECDH encryption. See RFC 6637, Section 9.
 | ||||
| 	kdf encoding.Field | ||||
| } | ||||
| 
 | ||||
| // UpgradeToV5 updates the version of the key to v5, and updates all necessary
 | ||||
| // fields.
 | ||||
| func (pk *PublicKey) UpgradeToV5() { | ||||
| 	pk.Version = 5 | ||||
| 	pk.setFingerprintAndKeyId() | ||||
| } | ||||
| 
 | ||||
| // signingKey provides a convenient abstraction over signature verification
 | ||||
| // for v3 and v4 public keys.
 | ||||
| type signingKey interface { | ||||
| 	SerializeForHash(io.Writer) error | ||||
| 	SerializeSignaturePrefix(io.Writer) | ||||
| 	serializeWithoutHeaders(io.Writer) error | ||||
| } | ||||
| 
 | ||||
| // NewRSAPublicKey returns a PublicKey that wraps the given rsa.PublicKey.
 | ||||
| func NewRSAPublicKey(creationTime time.Time, pub *rsa.PublicKey) *PublicKey { | ||||
| 	pk := &PublicKey{ | ||||
| 		Version:      4, | ||||
| 		CreationTime: creationTime, | ||||
| 		PubKeyAlgo:   PubKeyAlgoRSA, | ||||
| 		PublicKey:    pub, | ||||
| 		n:            new(encoding.MPI).SetBig(pub.N), | ||||
| 		e:            new(encoding.MPI).SetBig(big.NewInt(int64(pub.E))), | ||||
| 	} | ||||
| 
 | ||||
| 	pk.setFingerprintAndKeyId() | ||||
| 	return pk | ||||
| } | ||||
| 
 | ||||
| // NewDSAPublicKey returns a PublicKey that wraps the given dsa.PublicKey.
 | ||||
| func NewDSAPublicKey(creationTime time.Time, pub *dsa.PublicKey) *PublicKey { | ||||
| 	pk := &PublicKey{ | ||||
| 		Version:      4, | ||||
| 		CreationTime: creationTime, | ||||
| 		PubKeyAlgo:   PubKeyAlgoDSA, | ||||
| 		PublicKey:    pub, | ||||
| 		p:            new(encoding.MPI).SetBig(pub.P), | ||||
| 		q:            new(encoding.MPI).SetBig(pub.Q), | ||||
| 		g:            new(encoding.MPI).SetBig(pub.G), | ||||
| 		y:            new(encoding.MPI).SetBig(pub.Y), | ||||
| 	} | ||||
| 
 | ||||
| 	pk.setFingerprintAndKeyId() | ||||
| 	return pk | ||||
| } | ||||
| 
 | ||||
| // NewElGamalPublicKey returns a PublicKey that wraps the given elgamal.PublicKey.
 | ||||
| func NewElGamalPublicKey(creationTime time.Time, pub *elgamal.PublicKey) *PublicKey { | ||||
| 	pk := &PublicKey{ | ||||
| 		Version:      4, | ||||
| 		CreationTime: creationTime, | ||||
| 		PubKeyAlgo:   PubKeyAlgoElGamal, | ||||
| 		PublicKey:    pub, | ||||
| 		p:            new(encoding.MPI).SetBig(pub.P), | ||||
| 		g:            new(encoding.MPI).SetBig(pub.G), | ||||
| 		y:            new(encoding.MPI).SetBig(pub.Y), | ||||
| 	} | ||||
| 
 | ||||
| 	pk.setFingerprintAndKeyId() | ||||
| 	return pk | ||||
| } | ||||
| 
 | ||||
| func NewECDSAPublicKey(creationTime time.Time, pub *ecdsa.PublicKey) *PublicKey { | ||||
| 	pk := &PublicKey{ | ||||
| 		Version:      4, | ||||
| 		CreationTime: creationTime, | ||||
| 		PubKeyAlgo:   PubKeyAlgoECDSA, | ||||
| 		PublicKey:    pub, | ||||
| 		p:            encoding.NewMPI(elliptic.Marshal(pub.Curve, pub.X, pub.Y)), | ||||
| 	} | ||||
| 
 | ||||
| 	curveInfo := ecc.FindByCurve(pub.Curve) | ||||
| 	if curveInfo == nil { | ||||
| 		panic("unknown elliptic curve") | ||||
| 	} | ||||
| 	pk.oid = curveInfo.Oid | ||||
| 	pk.setFingerprintAndKeyId() | ||||
| 	return pk | ||||
| } | ||||
| 
 | ||||
| func NewECDHPublicKey(creationTime time.Time, pub *ecdh.PublicKey) *PublicKey { | ||||
| 	var pk *PublicKey | ||||
| 	var curveInfo *ecc.CurveInfo | ||||
| 	var kdf = encoding.NewOID([]byte{0x1, pub.Hash.Id(), pub.Cipher.Id()}) | ||||
| 	if pub.CurveType == ecc.Curve25519 { | ||||
| 		pk = &PublicKey{ | ||||
| 			Version:      4, | ||||
| 			CreationTime: creationTime, | ||||
| 			PubKeyAlgo:   PubKeyAlgoECDH, | ||||
| 			PublicKey:    pub, | ||||
| 			p:            encoding.NewMPI(pub.X.Bytes()), | ||||
| 			kdf:          kdf, | ||||
| 		} | ||||
| 		curveInfo = ecc.FindByName("Curve25519") | ||||
| 	} else { | ||||
| 		pk = &PublicKey{ | ||||
| 			Version:      4, | ||||
| 			CreationTime: creationTime, | ||||
| 			PubKeyAlgo:   PubKeyAlgoECDH, | ||||
| 			PublicKey:    pub, | ||||
| 			p:            encoding.NewMPI(elliptic.Marshal(pub.Curve, pub.X, pub.Y)), | ||||
| 			kdf:          kdf, | ||||
| 		} | ||||
| 		curveInfo = ecc.FindByCurve(pub.Curve) | ||||
| 	} | ||||
| 	if curveInfo == nil { | ||||
| 		panic("unknown elliptic curve") | ||||
| 	} | ||||
| 	pk.oid = curveInfo.Oid | ||||
| 	pk.setFingerprintAndKeyId() | ||||
| 	return pk | ||||
| } | ||||
| 
 | ||||
| func NewEdDSAPublicKey(creationTime time.Time, pub *ed25519.PublicKey) *PublicKey { | ||||
| 	curveInfo := ecc.FindByName("Ed25519") | ||||
| 	pk := &PublicKey{ | ||||
| 		Version:      4, | ||||
| 		CreationTime: creationTime, | ||||
| 		PubKeyAlgo:   PubKeyAlgoEdDSA, | ||||
| 		PublicKey:    pub, | ||||
| 		oid:          curveInfo.Oid, | ||||
| 		// Native point format, see draft-koch-eddsa-for-openpgp-04, Appendix B
 | ||||
| 		p: encoding.NewMPI(append([]byte{0x40}, *pub...)), | ||||
| 	} | ||||
| 
 | ||||
| 	pk.setFingerprintAndKeyId() | ||||
| 	return pk | ||||
| } | ||||
| 
 | ||||
| func (pk *PublicKey) parse(r io.Reader) (err error) { | ||||
| 	// RFC 4880, section 5.5.2
 | ||||
| 	var buf [6]byte | ||||
| 	_, err = readFull(r, buf[:]) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	if buf[0] != 4 && buf[0] != 5 { | ||||
| 		return errors.UnsupportedError("public key version " + strconv.Itoa(int(buf[0]))) | ||||
| 	} | ||||
| 
 | ||||
| 	pk.Version = int(buf[0]) | ||||
| 	if pk.Version == 5 { | ||||
| 		var n [4]byte | ||||
| 		_, err = readFull(r, n[:]) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 	pk.CreationTime = time.Unix(int64(uint32(buf[1])<<24|uint32(buf[2])<<16|uint32(buf[3])<<8|uint32(buf[4])), 0) | ||||
| 	pk.PubKeyAlgo = PublicKeyAlgorithm(buf[5]) | ||||
| 	switch pk.PubKeyAlgo { | ||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly: | ||||
| 		err = pk.parseRSA(r) | ||||
| 	case PubKeyAlgoDSA: | ||||
| 		err = pk.parseDSA(r) | ||||
| 	case PubKeyAlgoElGamal: | ||||
| 		err = pk.parseElGamal(r) | ||||
| 	case PubKeyAlgoECDSA: | ||||
| 		err = pk.parseECDSA(r) | ||||
| 	case PubKeyAlgoECDH: | ||||
| 		err = pk.parseECDH(r) | ||||
| 	case PubKeyAlgoEdDSA: | ||||
| 		err = pk.parseEdDSA(r) | ||||
| 	default: | ||||
| 		err = errors.UnsupportedError("public key type: " + strconv.Itoa(int(pk.PubKeyAlgo))) | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	pk.setFingerprintAndKeyId() | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| func (pk *PublicKey) setFingerprintAndKeyId() { | ||||
| 	// RFC 4880, section 12.2
 | ||||
| 	if pk.Version == 5 { | ||||
| 		fingerprint := sha256.New() | ||||
| 		pk.SerializeForHash(fingerprint) | ||||
| 		pk.Fingerprint = make([]byte, 32) | ||||
| 		copy(pk.Fingerprint, fingerprint.Sum(nil)) | ||||
| 		pk.KeyId = binary.BigEndian.Uint64(pk.Fingerprint[:8]) | ||||
| 	} else { | ||||
| 		fingerprint := sha1.New() | ||||
| 		pk.SerializeForHash(fingerprint) | ||||
| 		pk.Fingerprint = make([]byte, 20) | ||||
| 		copy(pk.Fingerprint, fingerprint.Sum(nil)) | ||||
| 		pk.KeyId = binary.BigEndian.Uint64(pk.Fingerprint[12:20]) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // parseRSA parses RSA public key material from the given Reader. See RFC 4880,
 | ||||
| // section 5.5.2.
 | ||||
| func (pk *PublicKey) parseRSA(r io.Reader) (err error) { | ||||
| 	pk.n = new(encoding.MPI) | ||||
| 	if _, err = pk.n.ReadFrom(r); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	pk.e = new(encoding.MPI) | ||||
| 	if _, err = pk.e.ReadFrom(r); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	if len(pk.e.Bytes()) > 3 { | ||||
| 		err = errors.UnsupportedError("large public exponent") | ||||
| 		return | ||||
| 	} | ||||
| 	rsa := &rsa.PublicKey{ | ||||
| 		N: new(big.Int).SetBytes(pk.n.Bytes()), | ||||
| 		E: 0, | ||||
| 	} | ||||
| 	for i := 0; i < len(pk.e.Bytes()); i++ { | ||||
| 		rsa.E <<= 8 | ||||
| 		rsa.E |= int(pk.e.Bytes()[i]) | ||||
| 	} | ||||
| 	pk.PublicKey = rsa | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // parseDSA parses DSA public key material from the given Reader. See RFC 4880,
 | ||||
| // section 5.5.2.
 | ||||
| func (pk *PublicKey) parseDSA(r io.Reader) (err error) { | ||||
| 	pk.p = new(encoding.MPI) | ||||
| 	if _, err = pk.p.ReadFrom(r); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	pk.q = new(encoding.MPI) | ||||
| 	if _, err = pk.q.ReadFrom(r); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	pk.g = new(encoding.MPI) | ||||
| 	if _, err = pk.g.ReadFrom(r); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	pk.y = new(encoding.MPI) | ||||
| 	if _, err = pk.y.ReadFrom(r); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	dsa := new(dsa.PublicKey) | ||||
| 	dsa.P = new(big.Int).SetBytes(pk.p.Bytes()) | ||||
| 	dsa.Q = new(big.Int).SetBytes(pk.q.Bytes()) | ||||
| 	dsa.G = new(big.Int).SetBytes(pk.g.Bytes()) | ||||
| 	dsa.Y = new(big.Int).SetBytes(pk.y.Bytes()) | ||||
| 	pk.PublicKey = dsa | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // parseElGamal parses ElGamal public key material from the given Reader. See
 | ||||
| // RFC 4880, section 5.5.2.
 | ||||
| func (pk *PublicKey) parseElGamal(r io.Reader) (err error) { | ||||
| 	pk.p = new(encoding.MPI) | ||||
| 	if _, err = pk.p.ReadFrom(r); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	pk.g = new(encoding.MPI) | ||||
| 	if _, err = pk.g.ReadFrom(r); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	pk.y = new(encoding.MPI) | ||||
| 	if _, err = pk.y.ReadFrom(r); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	elgamal := new(elgamal.PublicKey) | ||||
| 	elgamal.P = new(big.Int).SetBytes(pk.p.Bytes()) | ||||
| 	elgamal.G = new(big.Int).SetBytes(pk.g.Bytes()) | ||||
| 	elgamal.Y = new(big.Int).SetBytes(pk.y.Bytes()) | ||||
| 	pk.PublicKey = elgamal | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // parseECDSA parses ECDSA public key material from the given Reader. See
 | ||||
| // RFC 6637, Section 9.
 | ||||
| func (pk *PublicKey) parseECDSA(r io.Reader) (err error) { | ||||
| 	pk.oid = new(encoding.OID) | ||||
| 	if _, err = pk.oid.ReadFrom(r); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	pk.p = new(encoding.MPI) | ||||
| 	if _, err = pk.p.ReadFrom(r); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	var c elliptic.Curve | ||||
| 	curveInfo := ecc.FindByOid(pk.oid) | ||||
| 	if curveInfo == nil || curveInfo.SigAlgorithm != ecc.ECDSA { | ||||
| 		return errors.UnsupportedError(fmt.Sprintf("unsupported oid: %x", pk.oid)) | ||||
| 	} | ||||
| 	c = curveInfo.Curve | ||||
| 	x, y := elliptic.Unmarshal(c, pk.p.Bytes()) | ||||
| 	if x == nil { | ||||
| 		return errors.UnsupportedError("failed to parse EC point") | ||||
| 	} | ||||
| 	pk.PublicKey = &ecdsa.PublicKey{Curve: c, X: x, Y: y} | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // parseECDH parses ECDH public key material from the given Reader. See
 | ||||
| // RFC 6637, Section 9.
 | ||||
| func (pk *PublicKey) parseECDH(r io.Reader) (err error) { | ||||
| 	pk.oid = new(encoding.OID) | ||||
| 	if _, err = pk.oid.ReadFrom(r); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	pk.p = new(encoding.MPI) | ||||
| 	if _, err = pk.p.ReadFrom(r); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	pk.kdf = new(encoding.OID) | ||||
| 	if _, err = pk.kdf.ReadFrom(r); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	curveInfo := ecc.FindByOid(pk.oid) | ||||
| 	if curveInfo == nil { | ||||
| 		return errors.UnsupportedError(fmt.Sprintf("unsupported oid: %x", pk.oid)) | ||||
| 	} | ||||
| 
 | ||||
| 	c := curveInfo.Curve | ||||
| 	cType := curveInfo.CurveType | ||||
| 
 | ||||
| 	var x, y *big.Int | ||||
| 	if cType == ecc.Curve25519 { | ||||
| 		x = new(big.Int) | ||||
| 		x.SetBytes(pk.p.Bytes()) | ||||
| 	} else { | ||||
| 		x, y = elliptic.Unmarshal(c, pk.p.Bytes()) | ||||
| 	} | ||||
| 	if x == nil { | ||||
| 		return errors.UnsupportedError("failed to parse EC point") | ||||
| 	} | ||||
| 
 | ||||
| 	if kdfLen := len(pk.kdf.Bytes()); kdfLen < 3 { | ||||
| 		return errors.UnsupportedError("unsupported ECDH KDF length: " + strconv.Itoa(kdfLen)) | ||||
| 	} | ||||
| 	if reserved := pk.kdf.Bytes()[0]; reserved != 0x01 { | ||||
| 		return errors.UnsupportedError("unsupported KDF reserved field: " + strconv.Itoa(int(reserved))) | ||||
| 	} | ||||
| 	kdfHash, ok := algorithm.HashById[pk.kdf.Bytes()[1]] | ||||
| 	if !ok { | ||||
| 		return errors.UnsupportedError("unsupported ECDH KDF hash: " + strconv.Itoa(int(pk.kdf.Bytes()[1]))) | ||||
| 	} | ||||
| 	kdfCipher, ok := algorithm.CipherById[pk.kdf.Bytes()[2]] | ||||
| 	if !ok { | ||||
| 		return errors.UnsupportedError("unsupported ECDH KDF cipher: " + strconv.Itoa(int(pk.kdf.Bytes()[2]))) | ||||
| 	} | ||||
| 
 | ||||
| 	pk.PublicKey = &ecdh.PublicKey{ | ||||
| 		CurveType: cType, | ||||
| 		Curve:     c, | ||||
| 		X:         x, | ||||
| 		Y:         y, | ||||
| 		KDF: ecdh.KDF{ | ||||
| 			Hash:   kdfHash, | ||||
| 			Cipher: kdfCipher, | ||||
| 		}, | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| func (pk *PublicKey) parseEdDSA(r io.Reader) (err error) { | ||||
| 	pk.oid = new(encoding.OID) | ||||
| 	if _, err = pk.oid.ReadFrom(r); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	curveInfo := ecc.FindByOid(pk.oid) | ||||
| 	if curveInfo == nil || curveInfo.SigAlgorithm != ecc.EdDSA { | ||||
| 		return errors.UnsupportedError(fmt.Sprintf("unsupported oid: %x", pk.oid)) | ||||
| 	} | ||||
| 	pk.p = new(encoding.MPI) | ||||
| 	if _, err = pk.p.ReadFrom(r); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	eddsa := make(ed25519.PublicKey, ed25519.PublicKeySize) | ||||
| 	switch flag := pk.p.Bytes()[0]; flag { | ||||
| 	case 0x04: | ||||
| 		// TODO: see _grcy_ecc_eddsa_ensure_compact in grcypt
 | ||||
| 		return errors.UnsupportedError("unsupported EdDSA compression: " + strconv.Itoa(int(flag))) | ||||
| 	case 0x40: | ||||
| 		copy(eddsa[:], pk.p.Bytes()[1:]) | ||||
| 	default: | ||||
| 		return errors.UnsupportedError("unsupported EdDSA compression: " + strconv.Itoa(int(flag))) | ||||
| 	} | ||||
| 
 | ||||
| 	pk.PublicKey = &eddsa | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // SerializeForHash serializes the PublicKey to w with the special packet
 | ||||
| // header format needed for hashing.
 | ||||
| func (pk *PublicKey) SerializeForHash(w io.Writer) error { | ||||
| 	pk.SerializeSignaturePrefix(w) | ||||
| 	return pk.serializeWithoutHeaders(w) | ||||
| } | ||||
| 
 | ||||
| // SerializeSignaturePrefix writes the prefix for this public key to the given Writer.
 | ||||
| // The prefix is used when calculating a signature over this public key. See
 | ||||
| // RFC 4880, section 5.2.4.
 | ||||
| func (pk *PublicKey) SerializeSignaturePrefix(w io.Writer) { | ||||
| 	var pLength = pk.algorithmSpecificByteCount() | ||||
| 	if pk.Version == 5 { | ||||
| 		pLength += 10 // version, timestamp (4), algorithm, key octet count (4).
 | ||||
| 		w.Write([]byte{ | ||||
| 			0x9A, | ||||
| 			byte(pLength >> 24), | ||||
| 			byte(pLength >> 16), | ||||
| 			byte(pLength >> 8), | ||||
| 			byte(pLength), | ||||
| 		}) | ||||
| 		return | ||||
| 	} | ||||
| 	pLength += 6 | ||||
| 	w.Write([]byte{0x99, byte(pLength >> 8), byte(pLength)}) | ||||
| } | ||||
| 
 | ||||
| func (pk *PublicKey) Serialize(w io.Writer) (err error) { | ||||
| 	length := 6 // 6 byte header
 | ||||
| 	length += pk.algorithmSpecificByteCount() | ||||
| 	if pk.Version == 5 { | ||||
| 		length += 4 // octet key count
 | ||||
| 	} | ||||
| 	packetType := packetTypePublicKey | ||||
| 	if pk.IsSubkey { | ||||
| 		packetType = packetTypePublicSubkey | ||||
| 	} | ||||
| 	err = serializeHeader(w, packetType, length) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	return pk.serializeWithoutHeaders(w) | ||||
| } | ||||
| 
 | ||||
| func (pk *PublicKey) algorithmSpecificByteCount() int { | ||||
| 	length := 0 | ||||
| 	switch pk.PubKeyAlgo { | ||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly: | ||||
| 		length += int(pk.n.EncodedLength()) | ||||
| 		length += int(pk.e.EncodedLength()) | ||||
| 	case PubKeyAlgoDSA: | ||||
| 		length += int(pk.p.EncodedLength()) | ||||
| 		length += int(pk.q.EncodedLength()) | ||||
| 		length += int(pk.g.EncodedLength()) | ||||
| 		length += int(pk.y.EncodedLength()) | ||||
| 	case PubKeyAlgoElGamal: | ||||
| 		length += int(pk.p.EncodedLength()) | ||||
| 		length += int(pk.g.EncodedLength()) | ||||
| 		length += int(pk.y.EncodedLength()) | ||||
| 	case PubKeyAlgoECDSA: | ||||
| 		length += int(pk.oid.EncodedLength()) | ||||
| 		length += int(pk.p.EncodedLength()) | ||||
| 	case PubKeyAlgoECDH: | ||||
| 		length += int(pk.oid.EncodedLength()) | ||||
| 		length += int(pk.p.EncodedLength()) | ||||
| 		length += int(pk.kdf.EncodedLength()) | ||||
| 	case PubKeyAlgoEdDSA: | ||||
| 		length += int(pk.oid.EncodedLength()) | ||||
| 		length += int(pk.p.EncodedLength()) | ||||
| 	default: | ||||
| 		panic("unknown public key algorithm") | ||||
| 	} | ||||
| 	return length | ||||
| } | ||||
| 
 | ||||
| // serializeWithoutHeaders marshals the PublicKey to w in the form of an
 | ||||
| // OpenPGP public key packet, not including the packet header.
 | ||||
| func (pk *PublicKey) serializeWithoutHeaders(w io.Writer) (err error) { | ||||
| 	t := uint32(pk.CreationTime.Unix()) | ||||
| 	if _, err = w.Write([]byte{ | ||||
| 		byte(pk.Version), | ||||
| 		byte(t >> 24), byte(t >> 16), byte(t >> 8), byte(t), | ||||
| 		byte(pk.PubKeyAlgo), | ||||
| 	}); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	if pk.Version == 5 { | ||||
| 		n := pk.algorithmSpecificByteCount() | ||||
| 		if _, err = w.Write([]byte{ | ||||
| 			byte(n >> 24), byte(n >> 16), byte(n >> 8), byte(n), | ||||
| 		}); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	switch pk.PubKeyAlgo { | ||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly: | ||||
| 		if _, err = w.Write(pk.n.EncodedBytes()); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		_, err = w.Write(pk.e.EncodedBytes()) | ||||
| 		return | ||||
| 	case PubKeyAlgoDSA: | ||||
| 		if _, err = w.Write(pk.p.EncodedBytes()); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		if _, err = w.Write(pk.q.EncodedBytes()); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		if _, err = w.Write(pk.g.EncodedBytes()); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		_, err = w.Write(pk.y.EncodedBytes()) | ||||
| 		return | ||||
| 	case PubKeyAlgoElGamal: | ||||
| 		if _, err = w.Write(pk.p.EncodedBytes()); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		if _, err = w.Write(pk.g.EncodedBytes()); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		_, err = w.Write(pk.y.EncodedBytes()) | ||||
| 		return | ||||
| 	case PubKeyAlgoECDSA: | ||||
| 		if _, err = w.Write(pk.oid.EncodedBytes()); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		_, err = w.Write(pk.p.EncodedBytes()) | ||||
| 		return | ||||
| 	case PubKeyAlgoECDH: | ||||
| 		if _, err = w.Write(pk.oid.EncodedBytes()); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		if _, err = w.Write(pk.p.EncodedBytes()); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		_, err = w.Write(pk.kdf.EncodedBytes()) | ||||
| 		return | ||||
| 	case PubKeyAlgoEdDSA: | ||||
| 		if _, err = w.Write(pk.oid.EncodedBytes()); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		_, err = w.Write(pk.p.EncodedBytes()) | ||||
| 		return | ||||
| 	} | ||||
| 	return errors.InvalidArgumentError("bad public-key algorithm") | ||||
| } | ||||
| 
 | ||||
| // CanSign returns true iff this public key can generate signatures
 | ||||
| func (pk *PublicKey) CanSign() bool { | ||||
| 	return pk.PubKeyAlgo != PubKeyAlgoRSAEncryptOnly && pk.PubKeyAlgo != PubKeyAlgoElGamal && pk.PubKeyAlgo != PubKeyAlgoECDH | ||||
| } | ||||
| 
 | ||||
| // VerifySignature returns nil iff sig is a valid signature, made by this
 | ||||
| // public key, of the data hashed into signed. signed is mutated by this call.
 | ||||
| func (pk *PublicKey) VerifySignature(signed hash.Hash, sig *Signature) (err error) { | ||||
| 	if !pk.CanSign() { | ||||
| 		return errors.InvalidArgumentError("public key cannot generate signatures") | ||||
| 	} | ||||
| 	if sig.Version == 5 && (sig.SigType == 0x00 || sig.SigType == 0x01) { | ||||
| 		sig.AddMetadataToHashSuffix() | ||||
| 	} | ||||
| 	signed.Write(sig.HashSuffix) | ||||
| 	hashBytes := signed.Sum(nil) | ||||
| 	if hashBytes[0] != sig.HashTag[0] || hashBytes[1] != sig.HashTag[1] { | ||||
| 		return errors.SignatureError("hash tag doesn't match") | ||||
| 	} | ||||
| 
 | ||||
| 	if pk.PubKeyAlgo != sig.PubKeyAlgo { | ||||
| 		return errors.InvalidArgumentError("public key and signature use different algorithms") | ||||
| 	} | ||||
| 
 | ||||
| 	switch pk.PubKeyAlgo { | ||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: | ||||
| 		rsaPublicKey, _ := pk.PublicKey.(*rsa.PublicKey) | ||||
| 		err = rsa.VerifyPKCS1v15(rsaPublicKey, sig.Hash, hashBytes, padToKeySize(rsaPublicKey, sig.RSASignature.Bytes())) | ||||
| 		if err != nil { | ||||
| 			return errors.SignatureError("RSA verification failure") | ||||
| 		} | ||||
| 		return nil | ||||
| 	case PubKeyAlgoDSA: | ||||
| 		dsaPublicKey, _ := pk.PublicKey.(*dsa.PublicKey) | ||||
| 		// Need to truncate hashBytes to match FIPS 186-3 section 4.6.
 | ||||
| 		subgroupSize := (dsaPublicKey.Q.BitLen() + 7) / 8 | ||||
| 		if len(hashBytes) > subgroupSize { | ||||
| 			hashBytes = hashBytes[:subgroupSize] | ||||
| 		} | ||||
| 		if !dsa.Verify(dsaPublicKey, hashBytes, new(big.Int).SetBytes(sig.DSASigR.Bytes()), new(big.Int).SetBytes(sig.DSASigS.Bytes())) { | ||||
| 			return errors.SignatureError("DSA verification failure") | ||||
| 		} | ||||
| 		return nil | ||||
| 	case PubKeyAlgoECDSA: | ||||
| 		ecdsaPublicKey := pk.PublicKey.(*ecdsa.PublicKey) | ||||
| 		if !ecdsa.Verify(ecdsaPublicKey, hashBytes, new(big.Int).SetBytes(sig.ECDSASigR.Bytes()), new(big.Int).SetBytes(sig.ECDSASigS.Bytes())) { | ||||
| 			return errors.SignatureError("ECDSA verification failure") | ||||
| 		} | ||||
| 		return nil | ||||
| 	case PubKeyAlgoEdDSA: | ||||
| 		eddsaPublicKey := pk.PublicKey.(*ed25519.PublicKey) | ||||
| 
 | ||||
| 		sigR := sig.EdDSASigR.Bytes() | ||||
| 		sigS := sig.EdDSASigS.Bytes() | ||||
| 
 | ||||
| 		eddsaSig := make([]byte, ed25519.SignatureSize) | ||||
| 		copy(eddsaSig[32-len(sigR):32], sigR) | ||||
| 		copy(eddsaSig[64-len(sigS):], sigS) | ||||
| 
 | ||||
| 		if !ed25519.Verify(*eddsaPublicKey, hashBytes, eddsaSig) { | ||||
| 			return errors.SignatureError("EdDSA verification failure") | ||||
| 		} | ||||
| 		return nil | ||||
| 	default: | ||||
| 		return errors.SignatureError("Unsupported public key algorithm used in signature") | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // keySignatureHash returns a Hash of the message that needs to be signed for
 | ||||
| // pk to assert a subkey relationship to signed.
 | ||||
| func keySignatureHash(pk, signed signingKey, hashFunc crypto.Hash) (h hash.Hash, err error) { | ||||
| 	if !hashFunc.Available() { | ||||
| 		return nil, errors.UnsupportedError("hash function") | ||||
| 	} | ||||
| 	h = hashFunc.New() | ||||
| 
 | ||||
| 	// RFC 4880, section 5.2.4
 | ||||
| 	err = pk.SerializeForHash(h) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	err = signed.SerializeForHash(h) | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // VerifyKeySignature returns nil iff sig is a valid signature, made by this
 | ||||
| // public key, of signed.
 | ||||
| func (pk *PublicKey) VerifyKeySignature(signed *PublicKey, sig *Signature) error { | ||||
| 	h, err := keySignatureHash(pk, signed, sig.Hash) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if err = pk.VerifySignature(h, sig); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	if sig.FlagSign { | ||||
| 		// Signing subkeys must be cross-signed. See
 | ||||
| 		// https://www.gnupg.org/faq/subkey-cross-certify.html.
 | ||||
| 		if sig.EmbeddedSignature == nil { | ||||
| 			return errors.StructuralError("signing subkey is missing cross-signature") | ||||
| 		} | ||||
| 		// Verify the cross-signature. This is calculated over the same
 | ||||
| 		// data as the main signature, so we cannot just recursively
 | ||||
| 		// call signed.VerifyKeySignature(...)
 | ||||
| 		if h, err = keySignatureHash(pk, signed, sig.EmbeddedSignature.Hash); err != nil { | ||||
| 			return errors.StructuralError("error while hashing for cross-signature: " + err.Error()) | ||||
| 		} | ||||
| 		if err := signed.VerifySignature(h, sig.EmbeddedSignature); err != nil { | ||||
| 			return errors.StructuralError("error while verifying cross-signature: " + err.Error()) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func keyRevocationHash(pk signingKey, hashFunc crypto.Hash) (h hash.Hash, err error) { | ||||
| 	if !hashFunc.Available() { | ||||
| 		return nil, errors.UnsupportedError("hash function") | ||||
| 	} | ||||
| 	h = hashFunc.New() | ||||
| 
 | ||||
| 	// RFC 4880, section 5.2.4
 | ||||
| 	err = pk.SerializeForHash(h) | ||||
| 
 | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // VerifyRevocationSignature returns nil iff sig is a valid signature, made by this
 | ||||
| // public key.
 | ||||
| func (pk *PublicKey) VerifyRevocationSignature(sig *Signature) (err error) { | ||||
| 	h, err := keyRevocationHash(pk, sig.Hash) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return pk.VerifySignature(h, sig) | ||||
| } | ||||
| 
 | ||||
| // VerifySubkeyRevocationSignature returns nil iff sig is a valid subkey revocation signature,
 | ||||
| // made by the passed in signingKey.
 | ||||
| func (pk *PublicKey) VerifySubkeyRevocationSignature(sig *Signature, signingKey *PublicKey) (err error) { | ||||
| 	h, err := keyRevocationHash(pk, sig.Hash) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return signingKey.VerifySignature(h, sig) | ||||
| } | ||||
| 
 | ||||
| // userIdSignatureHash returns a Hash of the message that needs to be signed
 | ||||
| // to assert that pk is a valid key for id.
 | ||||
| func userIdSignatureHash(id string, pk *PublicKey, hashFunc crypto.Hash) (h hash.Hash, err error) { | ||||
| 	if !hashFunc.Available() { | ||||
| 		return nil, errors.UnsupportedError("hash function") | ||||
| 	} | ||||
| 	h = hashFunc.New() | ||||
| 
 | ||||
| 	// RFC 4880, section 5.2.4
 | ||||
| 	pk.SerializeSignaturePrefix(h) | ||||
| 	pk.serializeWithoutHeaders(h) | ||||
| 
 | ||||
| 	var buf [5]byte | ||||
| 	buf[0] = 0xb4 | ||||
| 	buf[1] = byte(len(id) >> 24) | ||||
| 	buf[2] = byte(len(id) >> 16) | ||||
| 	buf[3] = byte(len(id) >> 8) | ||||
| 	buf[4] = byte(len(id)) | ||||
| 	h.Write(buf[:]) | ||||
| 	h.Write([]byte(id)) | ||||
| 
 | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // VerifyUserIdSignature returns nil iff sig is a valid signature, made by this
 | ||||
| // public key, that id is the identity of pub.
 | ||||
| func (pk *PublicKey) VerifyUserIdSignature(id string, pub *PublicKey, sig *Signature) (err error) { | ||||
| 	h, err := userIdSignatureHash(id, pub, sig.Hash) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return pk.VerifySignature(h, sig) | ||||
| } | ||||
| 
 | ||||
| // KeyIdString returns the public key's fingerprint in capital hex
 | ||||
| // (e.g. "6C7EE1B8621CC013").
 | ||||
| func (pk *PublicKey) KeyIdString() string { | ||||
| 	return fmt.Sprintf("%X", pk.Fingerprint[12:20]) | ||||
| } | ||||
| 
 | ||||
| // KeyIdShortString returns the short form of public key's fingerprint
 | ||||
| // in capital hex, as shown by gpg --list-keys (e.g. "621CC013").
 | ||||
| func (pk *PublicKey) KeyIdShortString() string { | ||||
| 	return fmt.Sprintf("%X", pk.Fingerprint[16:20]) | ||||
| } | ||||
| 
 | ||||
| // BitLength returns the bit length for the given public key.
 | ||||
| func (pk *PublicKey) BitLength() (bitLength uint16, err error) { | ||||
| 	switch pk.PubKeyAlgo { | ||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly: | ||||
| 		bitLength = pk.n.BitLength() | ||||
| 	case PubKeyAlgoDSA: | ||||
| 		bitLength = pk.p.BitLength() | ||||
| 	case PubKeyAlgoElGamal: | ||||
| 		bitLength = pk.p.BitLength() | ||||
| 	case PubKeyAlgoECDSA: | ||||
| 		bitLength = pk.p.BitLength() | ||||
| 	case PubKeyAlgoECDH: | ||||
| 		bitLength = pk.p.BitLength() | ||||
| 	case PubKeyAlgoEdDSA: | ||||
| 		bitLength = pk.p.BitLength() | ||||
| 	default: | ||||
| 		err = errors.InvalidArgumentError("bad public-key algorithm") | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // KeyExpired returns whether sig is a self-signature of a key that has
 | ||||
| // expired or is created in the future.
 | ||||
| func (pk *PublicKey) KeyExpired(sig *Signature, currentTime time.Time) bool { | ||||
| 	if pk.CreationTime.After(currentTime) { | ||||
| 		return true | ||||
| 	} | ||||
| 	if sig.KeyLifetimeSecs == nil || *sig.KeyLifetimeSecs == 0 { | ||||
| 		return false | ||||
| 	} | ||||
| 	expiry := pk.CreationTime.Add(time.Duration(*sig.KeyLifetimeSecs) * time.Second) | ||||
| 	return currentTime.After(expiry) | ||||
| } | ||||
							
								
								
									
										24
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/public_key_test_data.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										24
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/public_key_test_data.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							|  | @ -0,0 +1,24 @@ | |||
| package packet | ||||
| 
 | ||||
| const rsaFingerprintHex = "5fb74b1d03b1e3cb31bc2f8aa34d7e18c20c31bb" | ||||
| 
 | ||||
| const rsaPkDataHex = "988d044d3c5c10010400b1d13382944bd5aba23a4312968b5095d14f947f600eb478e14a6fcb16b0e0cac764884909c020bc495cfcc39a935387c661507bdb236a0612fb582cac3af9b29cc2c8c70090616c41b662f4da4c1201e195472eb7f4ae1ccbcbf9940fe21d985e379a5563dde5b9a23d35f1cfaa5790da3b79db26f23695107bfaca8e7b5bcd0011010001" | ||||
| 
 | ||||
| const dsaFingerprintHex = "eece4c094db002103714c63c8e8fbe54062f19ed" | ||||
| 
 | ||||
| const dsaPkDataHex = "9901a2044d432f89110400cd581334f0d7a1e1bdc8b9d6d8c0baf68793632735d2bb0903224cbaa1dfbf35a60ee7a13b92643421e1eb41aa8d79bea19a115a677f6b8ba3c7818ce53a6c2a24a1608bd8b8d6e55c5090cbde09dd26e356267465ae25e69ec8bdd57c7bbb2623e4d73336f73a0a9098f7f16da2e25252130fd694c0e8070c55a812a423ae7f00a0ebf50e70c2f19c3520a551bd4b08d30f23530d3d03ff7d0bf4a53a64a09dc5e6e6e35854b7d70c882b0c60293401958b1bd9e40abec3ea05ba87cf64899299d4bd6aa7f459c201d3fbbd6c82004bdc5e8a9eb8082d12054cc90fa9d4ec251a843236a588bf49552441817436c4f43326966fe85447d4e6d0acf8fa1ef0f014730770603ad7634c3088dc52501c237328417c31c89ed70400b2f1a98b0bf42f11fefc430704bebbaa41d9f355600c3facee1e490f64208e0e094ea55e3a598a219a58500bf78ac677b670a14f4e47e9cf8eab4f368cc1ddcaa18cc59309d4cc62dd4f680e73e6cc3e1ce87a84d0925efbcb26c575c093fc42eecf45135fabf6403a25c2016e1774c0484e440a18319072c617cc97ac0a3bb0" | ||||
| 
 | ||||
| const ecdsaFingerprintHex = "9892270b38b8980b05c8d56d43fe956c542ca00b" | ||||
| 
 | ||||
| const ecdsaPkDataHex = "9893045071c29413052b8104002304230401f4867769cedfa52c325018896245443968e52e51d0c2df8d939949cb5b330f2921711fbee1c9b9dddb95d15cb0255e99badeddda7cc23d9ddcaacbc290969b9f24019375d61c2e4e3b36953a28d8b2bc95f78c3f1d592fb24499be348656a7b17e3963187b4361afe497bc5f9f81213f04069f8e1fb9e6a6290ae295ca1a92b894396cb4" | ||||
| 
 | ||||
| const ecdhFingerprintHex = "722354df2475a42164d1d49faa8b938f9a201946" | ||||
| 
 | ||||
| const ecdhPkDataHex = "b90073044d53059212052b810400220303042faa84024a20b6735c4897efa5bfb41bf85b7eefeab5ca0cb9ffc8ea04a46acb25534a577694f9e25340a4ab5223a9dd1eda530c8aa2e6718db10d7e672558c7736fe09369ea5739a2a3554bf16d41faa50562f11c6d39bbd5dffb6b9a9ec91803010909" | ||||
| 
 | ||||
| const eddsaFingerprintHex = "b2d5e5ec0e6deca6bc8eeeb00907e75e1dd99ad8" | ||||
| 
 | ||||
| const eddsaPkDataHex = "98330456e2132b16092b06010401da470f01010740bbda39266affa511a8c2d02edf690fb784b0499c4406185811a163539ef11dc1b41d74657374696e67203c74657374696e674074657374696e672e636f6d3e8879041316080021050256e2132b021b03050b09080702061508090a0b020416020301021e01021780000a09100907e75e1dd99ad86d0c00fe39d2008359352782bc9b61ac382584cd8eff3f57a18c2287e3afeeb05d1f04ba00fe2d0bc1ddf3ff8adb9afa3e7d9287244b4ec567f3db4d60b74a9b5465ed528203" | ||||
| 
 | ||||
| // Source: https://sites.google.com/site/brainhub/pgpecckeys#TOC-ECC-NIST-P-384-key
 | ||||
| const ecc384PubHex = `99006f044d53059213052b81040022030304f6b8c5aced5b84ef9f4a209db2e4a9dfb70d28cb8c10ecd57674a9fa5a67389942b62d5e51367df4c7bfd3f8e500feecf07ed265a621a8ebbbe53e947ec78c677eba143bd1533c2b350e1c29f82313e1e1108eba063be1e64b10e6950e799c2db42465635f6473615f64685f333834203c6f70656e70677040627261696e6875622e6f72673e8900cb04101309005305024d530592301480000000002000077072656665727265642d656d61696c2d656e636f64696e67407067702e636f6d7067706d696d65040b090807021901051b03000000021602051e010000000415090a08000a0910098033880f54719fca2b0180aa37350968bd5f115afd8ce7bc7b103822152dbff06d0afcda835329510905b98cb469ba208faab87c7412b799e7b633017f58364ea480e8a1a3f253a0c5f22c446e8be9a9fce6210136ee30811abbd49139de28b5bdf8dc36d06ae748579e9ff503b90073044d53059212052b810400220303042faa84024a20b6735c4897efa5bfb41bf85b7eefeab5ca0cb9ffc8ea04a46acb25534a577694f9e25340a4ab5223a9dd1eda530c8aa2e6718db10d7e672558c7736fe09369ea5739a2a3554bf16d41faa50562f11c6d39bbd5dffb6b9a9ec9180301090989008404181309000c05024d530592051b0c000000000a0910098033880f54719f80970180eee7a6d8fcee41ee4f9289df17f9bcf9d955dca25c583b94336f3a2b2d4986dc5cf417b8d2dc86f741a9e1a6d236c0e3017d1c76575458a0cfb93ae8a2b274fcc65ceecd7a91eec83656ba13219969f06945b48c56bd04152c3a0553c5f2f4bd1267` | ||||
|  | @ -0,0 +1,78 @@ | |||
| // 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 ( | ||||
| 	"io" | ||||
| 
 | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/errors" | ||||
| ) | ||||
| 
 | ||||
| // Reader reads packets from an io.Reader and allows packets to be 'unread' so
 | ||||
| // that they result from the next call to Next.
 | ||||
| type Reader struct { | ||||
| 	q       []Packet | ||||
| 	readers []io.Reader | ||||
| } | ||||
| 
 | ||||
| // New io.Readers are pushed when a compressed or encrypted packet is processed
 | ||||
| // and recursively treated as a new source of packets. However, a carefully
 | ||||
| // crafted packet can trigger an infinite recursive sequence of packets. See
 | ||||
| // http://mumble.net/~campbell/misc/pgp-quine
 | ||||
| // https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2013-4402
 | ||||
| // This constant limits the number of recursive packets that may be pushed.
 | ||||
| const maxReaders = 32 | ||||
| 
 | ||||
| // Next returns the most recently unread Packet, or reads another packet from
 | ||||
| // the top-most io.Reader. Unknown packet types are skipped.
 | ||||
| func (r *Reader) Next() (p Packet, err error) { | ||||
| 	if len(r.q) > 0 { | ||||
| 		p = r.q[len(r.q)-1] | ||||
| 		r.q = r.q[:len(r.q)-1] | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	for len(r.readers) > 0 { | ||||
| 		p, err = Read(r.readers[len(r.readers)-1]) | ||||
| 		if err == nil { | ||||
| 			return | ||||
| 		} | ||||
| 		if err == io.EOF { | ||||
| 			r.readers = r.readers[:len(r.readers)-1] | ||||
| 			continue | ||||
| 		} | ||||
| 		// TODO: Add strict mode that rejects unknown packets, instead of ignoring them.
 | ||||
| 		if _, ok := err.(errors.UnknownPacketTypeError); !ok { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return nil, io.EOF | ||||
| } | ||||
| 
 | ||||
| // Push causes the Reader to start reading from a new io.Reader. When an EOF
 | ||||
| // error is seen from the new io.Reader, it is popped and the Reader continues
 | ||||
| // to read from the next most recent io.Reader. Push returns a StructuralError
 | ||||
| // if pushing the reader would exceed the maximum recursion level, otherwise it
 | ||||
| // returns nil.
 | ||||
| func (r *Reader) Push(reader io.Reader) (err error) { | ||||
| 	if len(r.readers) >= maxReaders { | ||||
| 		return errors.StructuralError("too many layers of packets") | ||||
| 	} | ||||
| 	r.readers = append(r.readers, reader) | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // Unread causes the given Packet to be returned from the next call to Next.
 | ||||
| func (r *Reader) Unread(p Packet) { | ||||
| 	r.q = append(r.q, p) | ||||
| } | ||||
| 
 | ||||
| func NewReader(r io.Reader) *Reader { | ||||
| 	return &Reader{ | ||||
| 		q:       nil, | ||||
| 		readers: []io.Reader{r}, | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										964
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/signature.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										964
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/signature.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							|  | @ -0,0 +1,964 @@ | |||
| // 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 ( | ||||
| 	"bytes" | ||||
| 	"crypto" | ||||
| 	"crypto/dsa" | ||||
| 	"crypto/ecdsa" | ||||
| 	"encoding/asn1" | ||||
| 	"encoding/binary" | ||||
| 	"hash" | ||||
| 	"io" | ||||
| 	"math/big" | ||||
| 	"strconv" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/errors" | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/internal/encoding" | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/s2k" | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
| 	// See RFC 4880, section 5.2.3.21 for details.
 | ||||
| 	KeyFlagCertify = 1 << iota | ||||
| 	KeyFlagSign | ||||
| 	KeyFlagEncryptCommunications | ||||
| 	KeyFlagEncryptStorage | ||||
| ) | ||||
| 
 | ||||
| // Signature represents a signature. See RFC 4880, section 5.2.
 | ||||
| type Signature struct { | ||||
| 	Version    int | ||||
| 	SigType    SignatureType | ||||
| 	PubKeyAlgo PublicKeyAlgorithm | ||||
| 	Hash       crypto.Hash | ||||
| 
 | ||||
| 	// HashSuffix is extra data that is hashed in after the signed data.
 | ||||
| 	HashSuffix []byte | ||||
| 	// HashTag contains the first two bytes of the hash for fast rejection
 | ||||
| 	// of bad signed data.
 | ||||
| 	HashTag [2]byte | ||||
| 
 | ||||
| 	// Metadata includes format, filename and time, and is protected by v5
 | ||||
| 	// signatures of type 0x00 or 0x01. This metadata is included into the hash
 | ||||
| 	// computation; if nil, six 0x00 bytes are used instead. See section 5.2.4.
 | ||||
| 	Metadata *LiteralData | ||||
| 
 | ||||
| 	CreationTime time.Time | ||||
| 
 | ||||
| 	RSASignature         encoding.Field | ||||
| 	DSASigR, DSASigS     encoding.Field | ||||
| 	ECDSASigR, ECDSASigS encoding.Field | ||||
| 	EdDSASigR, EdDSASigS encoding.Field | ||||
| 
 | ||||
| 	// rawSubpackets contains the unparsed subpackets, in order.
 | ||||
| 	rawSubpackets []outputSubpacket | ||||
| 
 | ||||
| 	// The following are optional so are nil when not included in the
 | ||||
| 	// signature.
 | ||||
| 
 | ||||
| 	SigLifetimeSecs, KeyLifetimeSecs                        *uint32 | ||||
| 	PreferredSymmetric, PreferredHash, PreferredCompression []uint8 | ||||
| 	PreferredAEAD                                           []uint8 | ||||
| 	IssuerKeyId                                             *uint64 | ||||
| 	IssuerFingerprint                                       []byte | ||||
| 	IsPrimaryId                                             *bool | ||||
| 
 | ||||
| 	// FlagsValid is set if any flags were given. See RFC 4880, section
 | ||||
| 	// 5.2.3.21 for details.
 | ||||
| 	FlagsValid                                                           bool | ||||
| 	FlagCertify, FlagSign, FlagEncryptCommunications, FlagEncryptStorage bool | ||||
| 
 | ||||
| 	// RevocationReason is set if this signature has been revoked.
 | ||||
| 	// See RFC 4880, section 5.2.3.23 for details.
 | ||||
| 	RevocationReason     *uint8 | ||||
| 	RevocationReasonText string | ||||
| 
 | ||||
| 	// In a self-signature, these flags are set there is a features subpacket
 | ||||
| 	// indicating that the issuer implementation supports these features
 | ||||
| 	// (section 5.2.5.25).
 | ||||
| 	MDC, AEAD, V5Keys bool | ||||
| 
 | ||||
| 	// EmbeddedSignature, if non-nil, is a signature of the parent key, by
 | ||||
| 	// this key. This prevents an attacker from claiming another's signing
 | ||||
| 	// subkey as their own.
 | ||||
| 	EmbeddedSignature *Signature | ||||
| 
 | ||||
| 	outSubpackets []outputSubpacket | ||||
| } | ||||
| 
 | ||||
| func (sig *Signature) parse(r io.Reader) (err error) { | ||||
| 	// RFC 4880, section 5.2.3
 | ||||
| 	var buf [5]byte | ||||
| 	_, err = readFull(r, buf[:1]) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	if buf[0] != 4 && buf[0] != 5 { | ||||
| 		err = errors.UnsupportedError("signature packet version " + strconv.Itoa(int(buf[0]))) | ||||
| 		return | ||||
| 	} | ||||
| 	sig.Version = int(buf[0]) | ||||
| 	_, err = readFull(r, buf[:5]) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	sig.SigType = SignatureType(buf[0]) | ||||
| 	sig.PubKeyAlgo = PublicKeyAlgorithm(buf[1]) | ||||
| 	switch sig.PubKeyAlgo { | ||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA, PubKeyAlgoECDSA, PubKeyAlgoEdDSA: | ||||
| 	default: | ||||
| 		err = errors.UnsupportedError("public key algorithm " + strconv.Itoa(int(sig.PubKeyAlgo))) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	var ok bool | ||||
| 	sig.Hash, ok = s2k.HashIdToHash(buf[2]) | ||||
| 	if !ok { | ||||
| 		return errors.UnsupportedError("hash function " + strconv.Itoa(int(buf[2]))) | ||||
| 	} | ||||
| 
 | ||||
| 	hashedSubpacketsLength := int(buf[3])<<8 | int(buf[4]) | ||||
| 	hashedSubpackets := make([]byte, hashedSubpacketsLength) | ||||
| 	_, err = readFull(r, hashedSubpackets) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	sig.buildHashSuffix(hashedSubpackets) | ||||
| 	err = parseSignatureSubpackets(sig, hashedSubpackets, true) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	_, err = readFull(r, buf[:2]) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	unhashedSubpacketsLength := int(buf[0])<<8 | int(buf[1]) | ||||
| 	unhashedSubpackets := make([]byte, unhashedSubpacketsLength) | ||||
| 	_, err = readFull(r, unhashedSubpackets) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	err = parseSignatureSubpackets(sig, unhashedSubpackets, false) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	_, err = readFull(r, sig.HashTag[:2]) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	switch sig.PubKeyAlgo { | ||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: | ||||
| 		sig.RSASignature = new(encoding.MPI) | ||||
| 		_, err = sig.RSASignature.ReadFrom(r) | ||||
| 	case PubKeyAlgoDSA: | ||||
| 		sig.DSASigR = new(encoding.MPI) | ||||
| 		if _, err = sig.DSASigR.ReadFrom(r); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 
 | ||||
| 		sig.DSASigS = new(encoding.MPI) | ||||
| 		_, err = sig.DSASigS.ReadFrom(r) | ||||
| 	case PubKeyAlgoECDSA: | ||||
| 		sig.ECDSASigR = new(encoding.MPI) | ||||
| 		if _, err = sig.ECDSASigR.ReadFrom(r); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 
 | ||||
| 		sig.ECDSASigS = new(encoding.MPI) | ||||
| 		_, err = sig.ECDSASigS.ReadFrom(r) | ||||
| 	case PubKeyAlgoEdDSA: | ||||
| 		sig.EdDSASigR = new(encoding.MPI) | ||||
| 		if _, err = sig.EdDSASigR.ReadFrom(r); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 
 | ||||
| 		sig.EdDSASigS = new(encoding.MPI) | ||||
| 		if _, err = sig.EdDSASigS.ReadFrom(r); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 	default: | ||||
| 		panic("unreachable") | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // parseSignatureSubpackets parses subpackets of the main signature packet. See
 | ||||
| // RFC 4880, section 5.2.3.1.
 | ||||
| func parseSignatureSubpackets(sig *Signature, subpackets []byte, isHashed bool) (err error) { | ||||
| 	for len(subpackets) > 0 { | ||||
| 		subpackets, err = parseSignatureSubpacket(sig, subpackets, isHashed) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if sig.CreationTime.IsZero() { | ||||
| 		err = errors.StructuralError("no creation time in signature") | ||||
| 	} | ||||
| 
 | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| type signatureSubpacketType uint8 | ||||
| 
 | ||||
| const ( | ||||
| 	creationTimeSubpacket        signatureSubpacketType = 2 | ||||
| 	signatureExpirationSubpacket signatureSubpacketType = 3 | ||||
| 	keyExpirationSubpacket       signatureSubpacketType = 9 | ||||
| 	prefSymmetricAlgosSubpacket  signatureSubpacketType = 11 | ||||
| 	issuerSubpacket              signatureSubpacketType = 16 | ||||
| 	prefHashAlgosSubpacket       signatureSubpacketType = 21 | ||||
| 	prefCompressionSubpacket     signatureSubpacketType = 22 | ||||
| 	primaryUserIdSubpacket       signatureSubpacketType = 25 | ||||
| 	keyFlagsSubpacket            signatureSubpacketType = 27 | ||||
| 	reasonForRevocationSubpacket signatureSubpacketType = 29 | ||||
| 	featuresSubpacket            signatureSubpacketType = 30 | ||||
| 	embeddedSignatureSubpacket   signatureSubpacketType = 32 | ||||
| 	issuerFingerprintSubpacket   signatureSubpacketType = 33 | ||||
| 	prefAeadAlgosSubpacket       signatureSubpacketType = 34 | ||||
| ) | ||||
| 
 | ||||
| // parseSignatureSubpacket parses a single subpacket. len(subpacket) is >= 1.
 | ||||
| func parseSignatureSubpacket(sig *Signature, subpacket []byte, isHashed bool) (rest []byte, err error) { | ||||
| 	// RFC 4880, section 5.2.3.1
 | ||||
| 	var ( | ||||
| 		length     uint32 | ||||
| 		packetType signatureSubpacketType | ||||
| 		isCritical bool | ||||
| 	) | ||||
| 	switch { | ||||
| 	case subpacket[0] < 192: | ||||
| 		length = uint32(subpacket[0]) | ||||
| 		subpacket = subpacket[1:] | ||||
| 	case subpacket[0] < 255: | ||||
| 		if len(subpacket) < 2 { | ||||
| 			goto Truncated | ||||
| 		} | ||||
| 		length = uint32(subpacket[0]-192)<<8 + uint32(subpacket[1]) + 192 | ||||
| 		subpacket = subpacket[2:] | ||||
| 	default: | ||||
| 		if len(subpacket) < 5 { | ||||
| 			goto Truncated | ||||
| 		} | ||||
| 		length = uint32(subpacket[1])<<24 | | ||||
| 			uint32(subpacket[2])<<16 | | ||||
| 			uint32(subpacket[3])<<8 | | ||||
| 			uint32(subpacket[4]) | ||||
| 		subpacket = subpacket[5:] | ||||
| 	} | ||||
| 	if length > uint32(len(subpacket)) { | ||||
| 		goto Truncated | ||||
| 	} | ||||
| 	rest = subpacket[length:] | ||||
| 	subpacket = subpacket[:length] | ||||
| 	if len(subpacket) == 0 { | ||||
| 		err = errors.StructuralError("zero length signature subpacket") | ||||
| 		return | ||||
| 	} | ||||
| 	packetType = signatureSubpacketType(subpacket[0] & 0x7f) | ||||
| 	isCritical = subpacket[0]&0x80 == 0x80 | ||||
| 	subpacket = subpacket[1:] | ||||
| 	sig.rawSubpackets = append(sig.rawSubpackets, outputSubpacket{isHashed, packetType, isCritical, subpacket}) | ||||
| 	switch packetType { | ||||
| 	case creationTimeSubpacket: | ||||
| 		if !isHashed { | ||||
| 			err = errors.StructuralError("signature creation time in non-hashed area") | ||||
| 			return | ||||
| 		} | ||||
| 		if len(subpacket) != 4 { | ||||
| 			err = errors.StructuralError("signature creation time not four bytes") | ||||
| 			return | ||||
| 		} | ||||
| 		t := binary.BigEndian.Uint32(subpacket) | ||||
| 		sig.CreationTime = time.Unix(int64(t), 0) | ||||
| 	case signatureExpirationSubpacket: | ||||
| 		// Signature expiration time, section 5.2.3.10
 | ||||
| 		if !isHashed { | ||||
| 			return | ||||
| 		} | ||||
| 		if len(subpacket) != 4 { | ||||
| 			err = errors.StructuralError("expiration subpacket with bad length") | ||||
| 			return | ||||
| 		} | ||||
| 		sig.SigLifetimeSecs = new(uint32) | ||||
| 		*sig.SigLifetimeSecs = binary.BigEndian.Uint32(subpacket) | ||||
| 	case keyExpirationSubpacket: | ||||
| 		// Key expiration time, section 5.2.3.6
 | ||||
| 		if !isHashed { | ||||
| 			return | ||||
| 		} | ||||
| 		if len(subpacket) != 4 { | ||||
| 			err = errors.StructuralError("key expiration subpacket with bad length") | ||||
| 			return | ||||
| 		} | ||||
| 		sig.KeyLifetimeSecs = new(uint32) | ||||
| 		*sig.KeyLifetimeSecs = binary.BigEndian.Uint32(subpacket) | ||||
| 	case prefSymmetricAlgosSubpacket: | ||||
| 		// Preferred symmetric algorithms, section 5.2.3.7
 | ||||
| 		if !isHashed { | ||||
| 			return | ||||
| 		} | ||||
| 		sig.PreferredSymmetric = make([]byte, len(subpacket)) | ||||
| 		copy(sig.PreferredSymmetric, subpacket) | ||||
| 	case issuerSubpacket: | ||||
| 		if sig.Version > 4 { | ||||
| 			err = errors.StructuralError("issuer subpacket found in v5 key") | ||||
| 		} | ||||
| 		// Issuer, section 5.2.3.5
 | ||||
| 		if len(subpacket) != 8 { | ||||
| 			err = errors.StructuralError("issuer subpacket with bad length") | ||||
| 			return | ||||
| 		} | ||||
| 		sig.IssuerKeyId = new(uint64) | ||||
| 		*sig.IssuerKeyId = binary.BigEndian.Uint64(subpacket) | ||||
| 	case prefHashAlgosSubpacket: | ||||
| 		// Preferred hash algorithms, section 5.2.3.8
 | ||||
| 		if !isHashed { | ||||
| 			return | ||||
| 		} | ||||
| 		sig.PreferredHash = make([]byte, len(subpacket)) | ||||
| 		copy(sig.PreferredHash, subpacket) | ||||
| 	case prefCompressionSubpacket: | ||||
| 		// Preferred compression algorithms, section 5.2.3.9
 | ||||
| 		if !isHashed { | ||||
| 			return | ||||
| 		} | ||||
| 		sig.PreferredCompression = make([]byte, len(subpacket)) | ||||
| 		copy(sig.PreferredCompression, subpacket) | ||||
| 	case primaryUserIdSubpacket: | ||||
| 		// Primary User ID, section 5.2.3.19
 | ||||
| 		if !isHashed { | ||||
| 			return | ||||
| 		} | ||||
| 		if len(subpacket) != 1 { | ||||
| 			err = errors.StructuralError("primary user id subpacket with bad length") | ||||
| 			return | ||||
| 		} | ||||
| 		sig.IsPrimaryId = new(bool) | ||||
| 		if subpacket[0] > 0 { | ||||
| 			*sig.IsPrimaryId = true | ||||
| 		} | ||||
| 	case keyFlagsSubpacket: | ||||
| 		// Key flags, section 5.2.3.21
 | ||||
| 		if !isHashed { | ||||
| 			return | ||||
| 		} | ||||
| 		if len(subpacket) == 0 { | ||||
| 			err = errors.StructuralError("empty key flags subpacket") | ||||
| 			return | ||||
| 		} | ||||
| 		sig.FlagsValid = true | ||||
| 		if subpacket[0]&KeyFlagCertify != 0 { | ||||
| 			sig.FlagCertify = true | ||||
| 		} | ||||
| 		if subpacket[0]&KeyFlagSign != 0 { | ||||
| 			sig.FlagSign = true | ||||
| 		} | ||||
| 		if subpacket[0]&KeyFlagEncryptCommunications != 0 { | ||||
| 			sig.FlagEncryptCommunications = true | ||||
| 		} | ||||
| 		if subpacket[0]&KeyFlagEncryptStorage != 0 { | ||||
| 			sig.FlagEncryptStorage = true | ||||
| 		} | ||||
| 	case reasonForRevocationSubpacket: | ||||
| 		// Reason For Revocation, section 5.2.3.23
 | ||||
| 		if !isHashed { | ||||
| 			return | ||||
| 		} | ||||
| 		if len(subpacket) == 0 { | ||||
| 			err = errors.StructuralError("empty revocation reason subpacket") | ||||
| 			return | ||||
| 		} | ||||
| 		sig.RevocationReason = new(uint8) | ||||
| 		*sig.RevocationReason = subpacket[0] | ||||
| 		sig.RevocationReasonText = string(subpacket[1:]) | ||||
| 	case featuresSubpacket: | ||||
| 		// Features subpacket, section 5.2.3.24 specifies a very general
 | ||||
| 		// mechanism for OpenPGP implementations to signal support for new
 | ||||
| 		// features.
 | ||||
| 		if !isHashed { | ||||
| 			return | ||||
| 		} | ||||
| 		if len(subpacket) > 0 { | ||||
| 			if subpacket[0]&0x01 != 0 { | ||||
| 				sig.MDC = true | ||||
| 			} | ||||
| 			if subpacket[0]&0x02 != 0 { | ||||
| 				sig.AEAD = true | ||||
| 			} | ||||
| 			if subpacket[0]&0x04 != 0 { | ||||
| 				sig.V5Keys = true | ||||
| 			} | ||||
| 		} | ||||
| 	case embeddedSignatureSubpacket: | ||||
| 		// Only usage is in signatures that cross-certify
 | ||||
| 		// signing subkeys. section 5.2.3.26 describes the
 | ||||
| 		// format, with its usage described in section 11.1
 | ||||
| 		if sig.EmbeddedSignature != nil { | ||||
| 			err = errors.StructuralError("Cannot have multiple embedded signatures") | ||||
| 			return | ||||
| 		} | ||||
| 		sig.EmbeddedSignature = new(Signature) | ||||
| 		// Embedded signatures are required to be v4 signatures see
 | ||||
| 		// section 12.1. However, we only parse v4 signatures in this
 | ||||
| 		// file anyway.
 | ||||
| 		if err := sig.EmbeddedSignature.parse(bytes.NewBuffer(subpacket)); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		if sigType := sig.EmbeddedSignature.SigType; sigType != SigTypePrimaryKeyBinding { | ||||
| 			return nil, errors.StructuralError("cross-signature has unexpected type " + strconv.Itoa(int(sigType))) | ||||
| 		} | ||||
| 	case issuerFingerprintSubpacket: | ||||
| 		v, l := subpacket[0], len(subpacket[1:]) | ||||
| 		if v == 5 && l != 32 || v != 5 && l != 20 { | ||||
| 			return nil, errors.StructuralError("bad fingerprint length") | ||||
| 		} | ||||
| 		sig.IssuerFingerprint = make([]byte, l) | ||||
| 		copy(sig.IssuerFingerprint, subpacket[1:]) | ||||
| 		sig.IssuerKeyId = new(uint64) | ||||
| 		if v == 5 { | ||||
| 			*sig.IssuerKeyId = binary.BigEndian.Uint64(subpacket[1:9]) | ||||
| 		} else { | ||||
| 			*sig.IssuerKeyId = binary.BigEndian.Uint64(subpacket[13:21]) | ||||
| 		} | ||||
| 	case prefAeadAlgosSubpacket: | ||||
| 		// Preferred symmetric algorithms, section 5.2.3.8
 | ||||
| 		if !isHashed { | ||||
| 			return | ||||
| 		} | ||||
| 		sig.PreferredAEAD = make([]byte, len(subpacket)) | ||||
| 		copy(sig.PreferredAEAD, subpacket) | ||||
| 	default: | ||||
| 		if isCritical { | ||||
| 			err = errors.UnsupportedError("unknown critical signature subpacket type " + strconv.Itoa(int(packetType))) | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 	return | ||||
| 
 | ||||
| Truncated: | ||||
| 	err = errors.StructuralError("signature subpacket truncated") | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // subpacketLengthLength returns the length, in bytes, of an encoded length value.
 | ||||
| func subpacketLengthLength(length int) int { | ||||
| 	if length < 192 { | ||||
| 		return 1 | ||||
| 	} | ||||
| 	if length < 16320 { | ||||
| 		return 2 | ||||
| 	} | ||||
| 	return 5 | ||||
| } | ||||
| 
 | ||||
| func (sig *Signature) CheckKeyIdOrFingerprint(pk *PublicKey) bool { | ||||
| 	if sig.IssuerFingerprint != nil && len(sig.IssuerFingerprint) >= 20 { | ||||
| 		return bytes.Equal(sig.IssuerFingerprint, pk.Fingerprint) | ||||
| 	} | ||||
| 	return sig.IssuerKeyId != nil && *sig.IssuerKeyId == pk.KeyId | ||||
| } | ||||
| 
 | ||||
| // serializeSubpacketLength marshals the given length into to.
 | ||||
| func serializeSubpacketLength(to []byte, length int) int { | ||||
| 	// RFC 4880, Section 4.2.2.
 | ||||
| 	if length < 192 { | ||||
| 		to[0] = byte(length) | ||||
| 		return 1 | ||||
| 	} | ||||
| 	if length < 16320 { | ||||
| 		length -= 192 | ||||
| 		to[0] = byte((length >> 8) + 192) | ||||
| 		to[1] = byte(length) | ||||
| 		return 2 | ||||
| 	} | ||||
| 	to[0] = 255 | ||||
| 	to[1] = byte(length >> 24) | ||||
| 	to[2] = byte(length >> 16) | ||||
| 	to[3] = byte(length >> 8) | ||||
| 	to[4] = byte(length) | ||||
| 	return 5 | ||||
| } | ||||
| 
 | ||||
| // subpacketsLength returns the serialized length, in bytes, of the given
 | ||||
| // subpackets.
 | ||||
| func subpacketsLength(subpackets []outputSubpacket, hashed bool) (length int) { | ||||
| 	for _, subpacket := range subpackets { | ||||
| 		if subpacket.hashed == hashed { | ||||
| 			length += subpacketLengthLength(len(subpacket.contents) + 1) | ||||
| 			length += 1 // type byte
 | ||||
| 			length += len(subpacket.contents) | ||||
| 		} | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // serializeSubpackets marshals the given subpackets into to.
 | ||||
| func serializeSubpackets(to []byte, subpackets []outputSubpacket, hashed bool) { | ||||
| 	for _, subpacket := range subpackets { | ||||
| 		if subpacket.hashed == hashed { | ||||
| 			n := serializeSubpacketLength(to, len(subpacket.contents)+1) | ||||
| 			to[n] = byte(subpacket.subpacketType) | ||||
| 			to = to[1+n:] | ||||
| 			n = copy(to, subpacket.contents) | ||||
| 			to = to[n:] | ||||
| 		} | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // SigExpired returns whether sig is a signature that has expired or is created
 | ||||
| // in the future.
 | ||||
| func (sig *Signature) SigExpired(currentTime time.Time) bool { | ||||
| 	if sig.CreationTime.After(currentTime) { | ||||
| 		return true | ||||
| 	} | ||||
| 	if sig.SigLifetimeSecs == nil || *sig.SigLifetimeSecs == 0 { | ||||
| 		return false | ||||
| 	} | ||||
| 	expiry := sig.CreationTime.Add(time.Duration(*sig.SigLifetimeSecs) * time.Second) | ||||
| 	return currentTime.After(expiry) | ||||
| } | ||||
| 
 | ||||
| // buildHashSuffix constructs the HashSuffix member of sig in preparation for signing.
 | ||||
| func (sig *Signature) buildHashSuffix(hashedSubpackets []byte) (err error) { | ||||
| 	hash, ok := s2k.HashToHashId(sig.Hash) | ||||
| 	if !ok { | ||||
| 		sig.HashSuffix = nil | ||||
| 		return errors.InvalidArgumentError("hash cannot be represented in OpenPGP: " + strconv.Itoa(int(sig.Hash))) | ||||
| 	} | ||||
| 
 | ||||
| 	hashedFields := bytes.NewBuffer([]byte{ | ||||
| 		uint8(sig.Version), | ||||
| 		uint8(sig.SigType), | ||||
| 		uint8(sig.PubKeyAlgo), | ||||
| 		uint8(hash), | ||||
| 		uint8(len(hashedSubpackets) >> 8), | ||||
| 		uint8(len(hashedSubpackets)), | ||||
| 	}) | ||||
| 	hashedFields.Write(hashedSubpackets) | ||||
| 
 | ||||
| 	var l uint64 = uint64(6 + len(hashedSubpackets)) | ||||
| 	if sig.Version == 5 { | ||||
| 		hashedFields.Write([]byte{0x05, 0xff}) | ||||
| 		hashedFields.Write([]byte{ | ||||
| 			uint8(l >> 56), uint8(l >> 48), uint8(l >> 40), uint8(l >> 32), | ||||
| 			uint8(l >> 24), uint8(l >> 16), uint8(l >> 8), uint8(l), | ||||
| 		}) | ||||
| 	} else { | ||||
| 		hashedFields.Write([]byte{0x04, 0xff}) | ||||
| 		hashedFields.Write([]byte{ | ||||
| 			uint8(l >> 24), uint8(l >> 16), uint8(l >> 8), uint8(l), | ||||
| 		}) | ||||
| 	} | ||||
| 	sig.HashSuffix = make([]byte, hashedFields.Len()) | ||||
| 	copy(sig.HashSuffix, hashedFields.Bytes()) | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| func (sig *Signature) signPrepareHash(h hash.Hash) (digest []byte, err error) { | ||||
| 	hashedSubpacketsLen := subpacketsLength(sig.outSubpackets, true) | ||||
| 	hashedSubpackets := make([]byte, hashedSubpacketsLen) | ||||
| 	serializeSubpackets(hashedSubpackets, sig.outSubpackets, true) | ||||
| 	err = sig.buildHashSuffix(hashedSubpackets) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	if sig.Version == 5 && (sig.SigType == 0x00 || sig.SigType == 0x01) { | ||||
| 		sig.AddMetadataToHashSuffix() | ||||
| 	} | ||||
| 
 | ||||
| 	h.Write(sig.HashSuffix) | ||||
| 	digest = h.Sum(nil) | ||||
| 	copy(sig.HashTag[:], digest) | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // Sign signs a message with a private key. The hash, h, must contain
 | ||||
| // the hash of the message to be signed and will be mutated by this function.
 | ||||
| // On success, the signature is stored in sig. Call Serialize to write it out.
 | ||||
| // If config is nil, sensible defaults will be used.
 | ||||
| func (sig *Signature) Sign(h hash.Hash, priv *PrivateKey, config *Config) (err error) { | ||||
| 	if priv.Dummy() { | ||||
| 		return errors.ErrDummyPrivateKey("dummy key found") | ||||
| 	} | ||||
| 	sig.Version = priv.PublicKey.Version | ||||
| 	sig.IssuerFingerprint = priv.PublicKey.Fingerprint | ||||
| 	sig.outSubpackets, err = sig.buildSubpackets(priv.PublicKey) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	digest, err := sig.signPrepareHash(h) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	switch priv.PubKeyAlgo { | ||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: | ||||
| 		// supports both *rsa.PrivateKey and crypto.Signer
 | ||||
| 		sigdata, err := priv.PrivateKey.(crypto.Signer).Sign(config.Random(), digest, sig.Hash) | ||||
| 		if err == nil { | ||||
| 			sig.RSASignature = encoding.NewMPI(sigdata) | ||||
| 		} | ||||
| 	case PubKeyAlgoDSA: | ||||
| 		dsaPriv := priv.PrivateKey.(*dsa.PrivateKey) | ||||
| 
 | ||||
| 		// Need to truncate hashBytes to match FIPS 186-3 section 4.6.
 | ||||
| 		subgroupSize := (dsaPriv.Q.BitLen() + 7) / 8 | ||||
| 		if len(digest) > subgroupSize { | ||||
| 			digest = digest[:subgroupSize] | ||||
| 		} | ||||
| 		r, s, err := dsa.Sign(config.Random(), dsaPriv, digest) | ||||
| 		if err == nil { | ||||
| 			sig.DSASigR = new(encoding.MPI).SetBig(r) | ||||
| 			sig.DSASigS = new(encoding.MPI).SetBig(s) | ||||
| 		} | ||||
| 	case PubKeyAlgoECDSA: | ||||
| 		var r, s *big.Int | ||||
| 		if pk, ok := priv.PrivateKey.(*ecdsa.PrivateKey); ok { | ||||
| 			// direct support, avoid asn1 wrapping/unwrapping
 | ||||
| 			r, s, err = ecdsa.Sign(config.Random(), pk, digest) | ||||
| 		} else { | ||||
| 			var b []byte | ||||
| 			b, err = priv.PrivateKey.(crypto.Signer).Sign(config.Random(), digest, sig.Hash) | ||||
| 			if err == nil { | ||||
| 				r, s, err = unwrapECDSASig(b) | ||||
| 			} | ||||
| 		} | ||||
| 		if err == nil { | ||||
| 			sig.ECDSASigR = new(encoding.MPI).SetBig(r) | ||||
| 			sig.ECDSASigS = new(encoding.MPI).SetBig(s) | ||||
| 		} | ||||
| 	case PubKeyAlgoEdDSA: | ||||
| 		sigdata, err := priv.PrivateKey.(crypto.Signer).Sign(config.Random(), digest, crypto.Hash(0)) | ||||
| 		if err == nil { | ||||
| 			sig.EdDSASigR = encoding.NewMPI(sigdata[:32]) | ||||
| 			sig.EdDSASigS = encoding.NewMPI(sigdata[32:]) | ||||
| 		} | ||||
| 	default: | ||||
| 		err = errors.UnsupportedError("public key algorithm: " + strconv.Itoa(int(sig.PubKeyAlgo))) | ||||
| 	} | ||||
| 
 | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // unwrapECDSASig parses the two integer components of an ASN.1-encoded ECDSA
 | ||||
| // signature.
 | ||||
| func unwrapECDSASig(b []byte) (r, s *big.Int, err error) { | ||||
| 	var ecsdaSig struct { | ||||
| 		R, S *big.Int | ||||
| 	} | ||||
| 	_, err = asn1.Unmarshal(b, &ecsdaSig) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	return ecsdaSig.R, ecsdaSig.S, nil | ||||
| } | ||||
| 
 | ||||
| // SignUserId computes a signature from priv, asserting that pub is a valid
 | ||||
| // key for the identity id.  On success, the signature is stored in sig. Call
 | ||||
| // Serialize to write it out.
 | ||||
| // If config is nil, sensible defaults will be used.
 | ||||
| func (sig *Signature) SignUserId(id string, pub *PublicKey, priv *PrivateKey, config *Config) error { | ||||
| 	if priv.Dummy() { | ||||
| 		return errors.ErrDummyPrivateKey("dummy key found") | ||||
| 	} | ||||
| 	h, err := userIdSignatureHash(id, pub, sig.Hash) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return sig.Sign(h, priv, config) | ||||
| } | ||||
| 
 | ||||
| // CrossSignKey computes a signature from signingKey on pub hashed using hashKey. On success,
 | ||||
| // the signature is stored in sig. Call Serialize to write it out.
 | ||||
| // If config is nil, sensible defaults will be used.
 | ||||
| func (sig *Signature) CrossSignKey(pub *PublicKey, hashKey *PublicKey, signingKey *PrivateKey, | ||||
| 	config *Config) error { | ||||
| 	h, err := keySignatureHash(hashKey, pub, sig.Hash) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return sig.Sign(h, signingKey, config) | ||||
| } | ||||
| 
 | ||||
| // SignKey computes a signature from priv, asserting that pub is a subkey. On
 | ||||
| // success, the signature is stored in sig. Call Serialize to write it out.
 | ||||
| // If config is nil, sensible defaults will be used.
 | ||||
| func (sig *Signature) SignKey(pub *PublicKey, priv *PrivateKey, config *Config) error { | ||||
| 	if priv.Dummy() { | ||||
| 		return errors.ErrDummyPrivateKey("dummy key found") | ||||
| 	} | ||||
| 	h, err := keySignatureHash(&priv.PublicKey, pub, sig.Hash) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return sig.Sign(h, priv, config) | ||||
| } | ||||
| 
 | ||||
| // RevokeKey computes a revocation signature of pub using priv. On success, the signature is
 | ||||
| // stored in sig. Call Serialize to write it out.
 | ||||
| // If config is nil, sensible defaults will be used.
 | ||||
| func (sig *Signature) RevokeKey(pub *PublicKey, priv *PrivateKey, config *Config) error { | ||||
| 	h, err := keyRevocationHash(pub, sig.Hash) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return sig.Sign(h, priv, config) | ||||
| } | ||||
| 
 | ||||
| // Serialize marshals sig to w. Sign, SignUserId or SignKey must have been
 | ||||
| // called first.
 | ||||
| func (sig *Signature) Serialize(w io.Writer) (err error) { | ||||
| 	if len(sig.outSubpackets) == 0 { | ||||
| 		sig.outSubpackets = sig.rawSubpackets | ||||
| 	} | ||||
| 	if sig.RSASignature == nil && sig.DSASigR == nil && sig.ECDSASigR == nil && sig.EdDSASigR == nil { | ||||
| 		return errors.InvalidArgumentError("Signature: need to call Sign, SignUserId or SignKey before Serialize") | ||||
| 	} | ||||
| 
 | ||||
| 	sigLength := 0 | ||||
| 	switch sig.PubKeyAlgo { | ||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: | ||||
| 		sigLength = int(sig.RSASignature.EncodedLength()) | ||||
| 	case PubKeyAlgoDSA: | ||||
| 		sigLength = int(sig.DSASigR.EncodedLength()) | ||||
| 		sigLength += int(sig.DSASigS.EncodedLength()) | ||||
| 	case PubKeyAlgoECDSA: | ||||
| 		sigLength = int(sig.ECDSASigR.EncodedLength()) | ||||
| 		sigLength += int(sig.ECDSASigS.EncodedLength()) | ||||
| 	case PubKeyAlgoEdDSA: | ||||
| 		sigLength = int(sig.EdDSASigR.EncodedLength()) | ||||
| 		sigLength += int(sig.EdDSASigS.EncodedLength()) | ||||
| 	default: | ||||
| 		panic("impossible") | ||||
| 	} | ||||
| 
 | ||||
| 	unhashedSubpacketsLen := subpacketsLength(sig.outSubpackets, false) | ||||
| 	length := len(sig.HashSuffix) - 6 /* trailer not included */ + | ||||
| 		2 /* length of unhashed subpackets */ + unhashedSubpacketsLen + | ||||
| 		2 /* hash tag */ + sigLength | ||||
| 	if sig.Version == 5 { | ||||
| 		length -= 4 // eight-octet instead of four-octet big endian
 | ||||
| 	} | ||||
| 	err = serializeHeader(w, packetTypeSignature, length) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	err = sig.serializeBody(w) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| func (sig *Signature) serializeBody(w io.Writer) (err error) { | ||||
| 	hashedSubpacketsLen := uint16(uint16(sig.HashSuffix[4])<<8) | uint16(sig.HashSuffix[5]) | ||||
| 	fields := sig.HashSuffix[:6+hashedSubpacketsLen] | ||||
| 	_, err = w.Write(fields) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	unhashedSubpacketsLen := subpacketsLength(sig.outSubpackets, false) | ||||
| 	unhashedSubpackets := make([]byte, 2+unhashedSubpacketsLen) | ||||
| 	unhashedSubpackets[0] = byte(unhashedSubpacketsLen >> 8) | ||||
| 	unhashedSubpackets[1] = byte(unhashedSubpacketsLen) | ||||
| 	serializeSubpackets(unhashedSubpackets[2:], sig.outSubpackets, false) | ||||
| 
 | ||||
| 	_, err = w.Write(unhashedSubpackets) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	_, err = w.Write(sig.HashTag[:]) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	switch sig.PubKeyAlgo { | ||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: | ||||
| 		_, err = w.Write(sig.RSASignature.EncodedBytes()) | ||||
| 	case PubKeyAlgoDSA: | ||||
| 		if _, err = w.Write(sig.DSASigR.EncodedBytes()); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		_, err = w.Write(sig.DSASigS.EncodedBytes()) | ||||
| 	case PubKeyAlgoECDSA: | ||||
| 		if _, err = w.Write(sig.ECDSASigR.EncodedBytes()); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		_, err = w.Write(sig.ECDSASigS.EncodedBytes()) | ||||
| 	case PubKeyAlgoEdDSA: | ||||
| 		if _, err = w.Write(sig.EdDSASigR.EncodedBytes()); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		_, err = w.Write(sig.EdDSASigS.EncodedBytes()) | ||||
| 	default: | ||||
| 		panic("impossible") | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // outputSubpacket represents a subpacket to be marshaled.
 | ||||
| type outputSubpacket struct { | ||||
| 	hashed        bool // true if this subpacket is in the hashed area.
 | ||||
| 	subpacketType signatureSubpacketType | ||||
| 	isCritical    bool | ||||
| 	contents      []byte | ||||
| } | ||||
| 
 | ||||
| func (sig *Signature) buildSubpackets(issuer PublicKey) (subpackets []outputSubpacket, err error) { | ||||
| 	creationTime := make([]byte, 4) | ||||
| 	binary.BigEndian.PutUint32(creationTime, uint32(sig.CreationTime.Unix())) | ||||
| 	subpackets = append(subpackets, outputSubpacket{true, creationTimeSubpacket, false, creationTime}) | ||||
| 
 | ||||
| 	if sig.IssuerKeyId != nil && sig.Version == 4 { | ||||
| 		keyId := make([]byte, 8) | ||||
| 		binary.BigEndian.PutUint64(keyId, *sig.IssuerKeyId) | ||||
| 		subpackets = append(subpackets, outputSubpacket{true, issuerSubpacket, true, keyId}) | ||||
| 	} | ||||
| 	if sig.IssuerFingerprint != nil { | ||||
| 		contents := append([]uint8{uint8(issuer.Version)}, sig.IssuerFingerprint...) | ||||
| 		subpackets = append(subpackets, outputSubpacket{true, issuerFingerprintSubpacket, true, contents}) | ||||
| 	} | ||||
| 	if sig.SigLifetimeSecs != nil && *sig.SigLifetimeSecs != 0 { | ||||
| 		sigLifetime := make([]byte, 4) | ||||
| 		binary.BigEndian.PutUint32(sigLifetime, *sig.SigLifetimeSecs) | ||||
| 		subpackets = append(subpackets, outputSubpacket{true, signatureExpirationSubpacket, true, sigLifetime}) | ||||
| 	} | ||||
| 
 | ||||
| 	// Key flags may only appear in self-signatures or certification signatures.
 | ||||
| 
 | ||||
| 	if sig.FlagsValid { | ||||
| 		var flags byte | ||||
| 		if sig.FlagCertify { | ||||
| 			flags |= KeyFlagCertify | ||||
| 		} | ||||
| 		if sig.FlagSign { | ||||
| 			flags |= KeyFlagSign | ||||
| 		} | ||||
| 		if sig.FlagEncryptCommunications { | ||||
| 			flags |= KeyFlagEncryptCommunications | ||||
| 		} | ||||
| 		if sig.FlagEncryptStorage { | ||||
| 			flags |= KeyFlagEncryptStorage | ||||
| 		} | ||||
| 		subpackets = append(subpackets, outputSubpacket{true, keyFlagsSubpacket, false, []byte{flags}}) | ||||
| 	} | ||||
| 
 | ||||
| 	// The following subpackets may only appear in self-signatures.
 | ||||
| 
 | ||||
| 	var features = byte(0x00) | ||||
| 	if sig.MDC { | ||||
| 		features |= 0x01 | ||||
| 	} | ||||
| 	if sig.AEAD { | ||||
| 		features |= 0x02 | ||||
| 	} | ||||
| 	if sig.V5Keys { | ||||
| 		features |= 0x04 | ||||
| 	} | ||||
| 
 | ||||
| 	if features != 0x00 { | ||||
| 		subpackets = append(subpackets, outputSubpacket{true, featuresSubpacket, false, []byte{features}}) | ||||
| 	} | ||||
| 
 | ||||
| 	if sig.KeyLifetimeSecs != nil && *sig.KeyLifetimeSecs != 0 { | ||||
| 		keyLifetime := make([]byte, 4) | ||||
| 		binary.BigEndian.PutUint32(keyLifetime, *sig.KeyLifetimeSecs) | ||||
| 		subpackets = append(subpackets, outputSubpacket{true, keyExpirationSubpacket, true, keyLifetime}) | ||||
| 	} | ||||
| 
 | ||||
| 	if sig.IsPrimaryId != nil && *sig.IsPrimaryId { | ||||
| 		subpackets = append(subpackets, outputSubpacket{true, primaryUserIdSubpacket, false, []byte{1}}) | ||||
| 	} | ||||
| 
 | ||||
| 	if len(sig.PreferredSymmetric) > 0 { | ||||
| 		subpackets = append(subpackets, outputSubpacket{true, prefSymmetricAlgosSubpacket, false, sig.PreferredSymmetric}) | ||||
| 	} | ||||
| 
 | ||||
| 	if len(sig.PreferredHash) > 0 { | ||||
| 		subpackets = append(subpackets, outputSubpacket{true, prefHashAlgosSubpacket, false, sig.PreferredHash}) | ||||
| 	} | ||||
| 
 | ||||
| 	if len(sig.PreferredCompression) > 0 { | ||||
| 		subpackets = append(subpackets, outputSubpacket{true, prefCompressionSubpacket, false, sig.PreferredCompression}) | ||||
| 	} | ||||
| 
 | ||||
| 	if len(sig.PreferredAEAD) > 0 { | ||||
| 		subpackets = append(subpackets, outputSubpacket{true, prefAeadAlgosSubpacket, false, sig.PreferredAEAD}) | ||||
| 	} | ||||
| 
 | ||||
| 	// Revocation reason appears only in revocation signatures and is serialized as per section 5.2.3.23.
 | ||||
| 	if sig.RevocationReason != nil { | ||||
| 		subpackets = append(subpackets, outputSubpacket{true, reasonForRevocationSubpacket, true, | ||||
| 			append([]uint8{*sig.RevocationReason}, []uint8(sig.RevocationReasonText)...)}) | ||||
| 	} | ||||
| 
 | ||||
| 	// EmbeddedSignature appears only in subkeys capable of signing and is serialized as per section 5.2.3.26.
 | ||||
| 	if sig.EmbeddedSignature != nil { | ||||
| 		var buf bytes.Buffer | ||||
| 		err = sig.EmbeddedSignature.serializeBody(&buf) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		subpackets = append(subpackets, outputSubpacket{true, embeddedSignatureSubpacket, true, buf.Bytes()}) | ||||
| 	} | ||||
| 
 | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // AddMetadataToHashSuffix modifies the current hash suffix to include metadata
 | ||||
| // (format, filename, and time). Version 5 keys protect this data including it
 | ||||
| // in the hash computation. See section 5.2.4.
 | ||||
| func (sig *Signature) AddMetadataToHashSuffix() { | ||||
| 	if sig == nil || sig.Version != 5 { | ||||
| 		return | ||||
| 	} | ||||
| 	if sig.SigType != 0x00 && sig.SigType != 0x01 { | ||||
| 		return | ||||
| 	} | ||||
| 	lit := sig.Metadata | ||||
| 	if lit == nil { | ||||
| 		// This will translate into six 0x00 bytes.
 | ||||
| 		lit = &LiteralData{} | ||||
| 	} | ||||
| 
 | ||||
| 	// Extract the current byte count
 | ||||
| 	n := sig.HashSuffix[len(sig.HashSuffix)-8:] | ||||
| 	l := uint64( | ||||
| 		uint64(n[0])<<56 | uint64(n[1])<<48 | uint64(n[2])<<40 | uint64(n[3])<<32 | | ||||
| 		uint64(n[4])<<24 | uint64(n[5])<<16 | uint64(n[6])<<8  | uint64(n[7])) | ||||
| 
 | ||||
| 	suffix := bytes.NewBuffer(nil) | ||||
| 	suffix.Write(sig.HashSuffix[:l]) | ||||
| 
 | ||||
| 	// Add the metadata
 | ||||
| 	var buf [4]byte | ||||
| 	buf[0] = lit.Format | ||||
| 	fileName := lit.FileName | ||||
| 	if len(lit.FileName) > 255 { | ||||
| 		fileName = fileName[:255] | ||||
| 	} | ||||
| 	buf[1] = byte(len(fileName)) | ||||
| 	suffix.Write(buf[:2]) | ||||
| 	suffix.Write([]byte(lit.FileName)) | ||||
| 	binary.BigEndian.PutUint32(buf[:], lit.Time) | ||||
| 	suffix.Write(buf[:]) | ||||
| 
 | ||||
| 	// Update the counter and restore trailing bytes
 | ||||
| 	l = uint64(suffix.Len()) | ||||
| 	suffix.Write([]byte{0x05, 0xff}) | ||||
| 	suffix.Write([]byte{ | ||||
| 		uint8(l >> 56), uint8(l >> 48), uint8(l >> 40), uint8(l >> 32), | ||||
| 		uint8(l >> 24), uint8(l >> 16), uint8(l >> 8), uint8(l), | ||||
| 	}) | ||||
| 	sig.HashSuffix = suffix.Bytes() | ||||
| } | ||||
							
								
								
									
										267
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/symmetric_key_encrypted.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										267
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/symmetric_key_encrypted.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							|  | @ -0,0 +1,267 @@ | |||
| // 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 ( | ||||
| 	"bytes" | ||||
| 	"crypto/cipher" | ||||
| 	"io" | ||||
| 	"strconv" | ||||
| 
 | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/errors" | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/s2k" | ||||
| ) | ||||
| 
 | ||||
| // This is the largest session key that we'll support. Since no 512-bit cipher
 | ||||
| // has even been seriously used, this is comfortably large.
 | ||||
| const maxSessionKeySizeInBytes = 64 | ||||
| 
 | ||||
| // SymmetricKeyEncrypted represents a passphrase protected session key. See RFC
 | ||||
| // 4880, section 5.3.
 | ||||
| type SymmetricKeyEncrypted struct { | ||||
| 	Version      int | ||||
| 	CipherFunc   CipherFunction | ||||
| 	Mode         AEADMode | ||||
| 	s2k          func(out, in []byte) | ||||
| 	aeadNonce    []byte | ||||
| 	encryptedKey []byte | ||||
| } | ||||
| 
 | ||||
| func (ske *SymmetricKeyEncrypted) parse(r io.Reader) error { | ||||
| 	// RFC 4880, section 5.3.
 | ||||
| 	var buf [2]byte | ||||
| 	if _, err := readFull(r, buf[:]); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	ske.Version = int(buf[0]) | ||||
| 	if ske.Version != 4 && ske.Version != 5 { | ||||
| 		return errors.UnsupportedError("unknown SymmetricKeyEncrypted version") | ||||
| 	} | ||||
| 	ske.CipherFunc = CipherFunction(buf[1]) | ||||
| 	if ske.CipherFunc.KeySize() == 0 { | ||||
| 		return errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(buf[1]))) | ||||
| 	} | ||||
| 
 | ||||
| 	if ske.Version == 5 { | ||||
| 		mode := make([]byte, 1) | ||||
| 		if _, err := r.Read(mode); err != nil { | ||||
| 			return errors.StructuralError("cannot read AEAD octect from packet") | ||||
| 		} | ||||
| 		ske.Mode = AEADMode(mode[0]) | ||||
| 	} | ||||
| 
 | ||||
| 	var err error | ||||
| 	if ske.s2k, err = s2k.Parse(r); err != nil { | ||||
| 		if _, ok := err.(errors.ErrDummyPrivateKey); ok { | ||||
| 			return errors.UnsupportedError("missing key GNU extension in session key") | ||||
| 		} | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	if ske.Version == 5 { | ||||
| 		// AEAD nonce
 | ||||
| 		nonce := make([]byte, ske.Mode.NonceLength()) | ||||
| 		_, err := readFull(r, nonce) | ||||
| 		if err != nil && err != io.ErrUnexpectedEOF { | ||||
| 			return err | ||||
| 		} | ||||
| 		ske.aeadNonce = nonce | ||||
| 	} | ||||
| 
 | ||||
| 	encryptedKey := make([]byte, maxSessionKeySizeInBytes) | ||||
| 	// The session key may follow. We just have to try and read to find
 | ||||
| 	// out. If it exists then we limit it to maxSessionKeySizeInBytes.
 | ||||
| 	n, err := readFull(r, encryptedKey) | ||||
| 	if err != nil && err != io.ErrUnexpectedEOF { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	if n != 0 { | ||||
| 		if n == maxSessionKeySizeInBytes { | ||||
| 			return errors.UnsupportedError("oversized encrypted session key") | ||||
| 		} | ||||
| 		ske.encryptedKey = encryptedKey[:n] | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // Decrypt attempts to decrypt an encrypted session key and returns the key and
 | ||||
| // the cipher to use when decrypting a subsequent Symmetrically Encrypted Data
 | ||||
| // packet.
 | ||||
| func (ske *SymmetricKeyEncrypted) Decrypt(passphrase []byte) ([]byte, CipherFunction, error) { | ||||
| 	key := make([]byte, ske.CipherFunc.KeySize()) | ||||
| 	ske.s2k(key, passphrase) | ||||
| 	if len(ske.encryptedKey) == 0 { | ||||
| 		return key, ske.CipherFunc, nil | ||||
| 	} | ||||
| 	switch ske.Version { | ||||
| 	case 4: | ||||
| 		plaintextKey, cipherFunc, err := ske.decryptV4(key) | ||||
| 		return plaintextKey, cipherFunc, err | ||||
| 	case 5: | ||||
| 		plaintextKey, err := ske.decryptV5(key) | ||||
| 		return plaintextKey, CipherFunction(0), err | ||||
| 	} | ||||
| 	err := errors.UnsupportedError("unknown SymmetricKeyEncrypted version") | ||||
| 	return nil, CipherFunction(0), err | ||||
| } | ||||
| 
 | ||||
| func (ske *SymmetricKeyEncrypted) decryptV4(key []byte) ([]byte, CipherFunction, error) { | ||||
| 	// the IV is all zeros
 | ||||
| 	iv := make([]byte, ske.CipherFunc.blockSize()) | ||||
| 	c := cipher.NewCFBDecrypter(ske.CipherFunc.new(key), iv) | ||||
| 	plaintextKey := make([]byte, len(ske.encryptedKey)) | ||||
| 	c.XORKeyStream(plaintextKey, ske.encryptedKey) | ||||
| 	cipherFunc := CipherFunction(plaintextKey[0]) | ||||
| 	if cipherFunc.blockSize() == 0 { | ||||
| 		return nil, ske.CipherFunc, errors.UnsupportedError( | ||||
| 			"unknown cipher: " + strconv.Itoa(int(cipherFunc))) | ||||
| 	} | ||||
| 	plaintextKey = plaintextKey[1:] | ||||
| 	if len(plaintextKey) != cipherFunc.KeySize() { | ||||
| 		return nil, cipherFunc, errors.StructuralError( | ||||
| 			"length of decrypted key not equal to cipher keysize") | ||||
| 	} | ||||
| 	return plaintextKey, cipherFunc, nil | ||||
| } | ||||
| 
 | ||||
| func (ske *SymmetricKeyEncrypted) decryptV5(key []byte) ([]byte, error) { | ||||
| 	blockCipher := CipherFunction(ske.CipherFunc).new(key) | ||||
| 	aead := ske.Mode.new(blockCipher) | ||||
| 
 | ||||
| 	adata := []byte{0xc3, byte(5), byte(ske.CipherFunc), byte(ske.Mode)} | ||||
| 	plaintextKey, err := aead.Open(nil, ske.aeadNonce, ske.encryptedKey, adata) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return plaintextKey, nil | ||||
| } | ||||
| 
 | ||||
| // SerializeSymmetricKeyEncrypted serializes a symmetric key packet to w.
 | ||||
| // The packet contains a random session key, encrypted by a key derived from
 | ||||
| // the given passphrase. The session key is returned and must be passed to
 | ||||
| // SerializeSymmetricallyEncrypted or SerializeAEADEncrypted, depending on
 | ||||
| // whether config.AEADConfig != nil.
 | ||||
| // If config is nil, sensible defaults will be used.
 | ||||
| func SerializeSymmetricKeyEncrypted(w io.Writer, passphrase []byte, config *Config) (key []byte, err error) { | ||||
| 	cipherFunc := config.Cipher() | ||||
| 	keySize := cipherFunc.KeySize() | ||||
| 	if keySize == 0 { | ||||
| 		return nil, errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(cipherFunc))) | ||||
| 	} | ||||
| 
 | ||||
| 	sessionKey := make([]byte, keySize) | ||||
| 	_, err = io.ReadFull(config.Random(), sessionKey) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	err = SerializeSymmetricKeyEncryptedReuseKey(w, sessionKey, passphrase, config) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	key = sessionKey | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // SerializeSymmetricKeyEncryptedReuseKey serializes a symmetric key packet to w.
 | ||||
| // The packet contains the given session key, encrypted by a key derived from
 | ||||
| // the given passphrase. The session key must be passed to
 | ||||
| // SerializeSymmetricallyEncrypted or SerializeAEADEncrypted, depending on
 | ||||
| // whether config.AEADConfig != nil.
 | ||||
| // If config is nil, sensible defaults will be used.
 | ||||
| func SerializeSymmetricKeyEncryptedReuseKey(w io.Writer, sessionKey []byte, passphrase []byte, config *Config) (err error) { | ||||
| 	var version int | ||||
| 	if config.AEAD() != nil { | ||||
| 		version = 5 | ||||
| 	} else { | ||||
| 		version = 4 | ||||
| 	} | ||||
| 	cipherFunc := config.Cipher() | ||||
| 	keySize := cipherFunc.KeySize() | ||||
| 	if keySize == 0 { | ||||
| 		return errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(cipherFunc))) | ||||
| 	} | ||||
| 
 | ||||
| 	s2kBuf := new(bytes.Buffer) | ||||
| 	keyEncryptingKey := make([]byte, keySize) | ||||
| 	// s2k.Serialize salts and stretches the passphrase, and writes the
 | ||||
| 	// resulting key to keyEncryptingKey and the s2k descriptor to s2kBuf.
 | ||||
| 	err = s2k.Serialize(s2kBuf, keyEncryptingKey, config.Random(), passphrase, &s2k.Config{Hash: config.Hash(), S2KCount: config.PasswordHashIterations()}) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	s2kBytes := s2kBuf.Bytes() | ||||
| 
 | ||||
| 	var packetLength int | ||||
| 	switch version { | ||||
| 	case 4: | ||||
| 		packetLength = 2 /* header */ + len(s2kBytes) + 1 /* cipher type */ + keySize | ||||
| 	case 5: | ||||
| 		nonceLen := config.AEAD().Mode().NonceLength() | ||||
| 		tagLen := config.AEAD().Mode().TagLength() | ||||
| 		packetLength = 3 + len(s2kBytes) + nonceLen + keySize + tagLen | ||||
| 	} | ||||
| 	err = serializeHeader(w, packetTypeSymmetricKeyEncrypted, packetLength) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	buf := make([]byte, 2) | ||||
| 	// Symmetric Key Encrypted Version
 | ||||
| 	buf[0] = byte(version) | ||||
| 	// Cipher function
 | ||||
| 	buf[1] = byte(cipherFunc) | ||||
| 
 | ||||
| 	if version == 5 { | ||||
| 		// AEAD mode
 | ||||
| 		buf = append(buf, byte(config.AEAD().Mode())) | ||||
| 	} | ||||
| 	_, err = w.Write(buf) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	_, err = w.Write(s2kBytes) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	switch version { | ||||
| 	case 4: | ||||
| 		iv := make([]byte, cipherFunc.blockSize()) | ||||
| 		c := cipher.NewCFBEncrypter(cipherFunc.new(keyEncryptingKey), iv) | ||||
| 		encryptedCipherAndKey := make([]byte, keySize+1) | ||||
| 		c.XORKeyStream(encryptedCipherAndKey, buf[1:]) | ||||
| 		c.XORKeyStream(encryptedCipherAndKey[1:], sessionKey) | ||||
| 		_, err = w.Write(encryptedCipherAndKey) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 	case 5: | ||||
| 		blockCipher := cipherFunc.new(keyEncryptingKey) | ||||
| 		mode := config.AEAD().Mode() | ||||
| 		aead := mode.new(blockCipher) | ||||
| 		// Sample nonce using random reader
 | ||||
| 		nonce := make([]byte, config.AEAD().Mode().NonceLength()) | ||||
| 		_, err = io.ReadFull(config.Random(), nonce) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		// Seal and write (encryptedData includes auth. tag)
 | ||||
| 		adata := []byte{0xc3, byte(5), byte(cipherFunc), byte(mode)} | ||||
| 		encryptedData := aead.Seal(nil, nonce, sessionKey, adata) | ||||
| 		_, err = w.Write(nonce) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		_, err = w.Write(encryptedData) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return | ||||
| } | ||||
							
								
								
									
										290
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/symmetrically_encrypted.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										290
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/symmetrically_encrypted.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							|  | @ -0,0 +1,290 @@ | |||
| // 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/cipher" | ||||
| 	"crypto/sha1" | ||||
| 	"crypto/subtle" | ||||
| 	"hash" | ||||
| 	"io" | ||||
| 	"strconv" | ||||
| 
 | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/errors" | ||||
| ) | ||||
| 
 | ||||
| // SymmetricallyEncrypted represents a symmetrically encrypted byte string. The
 | ||||
| // encrypted Contents will consist of more OpenPGP packets. See RFC 4880,
 | ||||
| // sections 5.7 and 5.13.
 | ||||
| type SymmetricallyEncrypted struct { | ||||
| 	MDC      bool // true iff this is a type 18 packet and thus has an embedded MAC.
 | ||||
| 	Contents io.Reader | ||||
| 	prefix   []byte | ||||
| } | ||||
| 
 | ||||
| const symmetricallyEncryptedVersion = 1 | ||||
| 
 | ||||
| func (se *SymmetricallyEncrypted) parse(r io.Reader) error { | ||||
| 	if se.MDC { | ||||
| 		// See RFC 4880, section 5.13.
 | ||||
| 		var buf [1]byte | ||||
| 		_, err := readFull(r, buf[:]) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		if buf[0] != symmetricallyEncryptedVersion { | ||||
| 			return errors.UnsupportedError("unknown SymmetricallyEncrypted version") | ||||
| 		} | ||||
| 	} | ||||
| 	se.Contents = r | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // Decrypt returns a ReadCloser, from which the decrypted Contents of the
 | ||||
| // packet can be read. An incorrect key will only be detected after trying
 | ||||
| // to decrypt the entire data.
 | ||||
| func (se *SymmetricallyEncrypted) Decrypt(c CipherFunction, key []byte) (io.ReadCloser, error) { | ||||
| 	keySize := c.KeySize() | ||||
| 	if keySize == 0 { | ||||
| 		return nil, errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(c))) | ||||
| 	} | ||||
| 	if len(key) != keySize { | ||||
| 		return nil, errors.InvalidArgumentError("SymmetricallyEncrypted: incorrect key length") | ||||
| 	} | ||||
| 
 | ||||
| 	if se.prefix == nil { | ||||
| 		se.prefix = make([]byte, c.blockSize()+2) | ||||
| 		_, err := readFull(se.Contents, se.prefix) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} else if len(se.prefix) != c.blockSize()+2 { | ||||
| 		return nil, errors.InvalidArgumentError("can't try ciphers with different block lengths") | ||||
| 	} | ||||
| 
 | ||||
| 	ocfbResync := OCFBResync | ||||
| 	if se.MDC { | ||||
| 		// MDC packets use a different form of OCFB mode.
 | ||||
| 		ocfbResync = OCFBNoResync | ||||
| 	} | ||||
| 
 | ||||
| 	s := NewOCFBDecrypter(c.new(key), se.prefix, ocfbResync) | ||||
| 
 | ||||
| 	plaintext := cipher.StreamReader{S: s, R: se.Contents} | ||||
| 
 | ||||
| 	if se.MDC { | ||||
| 		// MDC packets have an embedded hash that we need to check.
 | ||||
| 		h := sha1.New() | ||||
| 		h.Write(se.prefix) | ||||
| 		return &seMDCReader{in: plaintext, h: h}, nil | ||||
| 	} | ||||
| 
 | ||||
| 	// Otherwise, we just need to wrap plaintext so that it's a valid ReadCloser.
 | ||||
| 	return seReader{plaintext}, nil | ||||
| } | ||||
| 
 | ||||
| // seReader wraps an io.Reader with a no-op Close method.
 | ||||
| type seReader struct { | ||||
| 	in io.Reader | ||||
| } | ||||
| 
 | ||||
| func (ser seReader) Read(buf []byte) (int, error) { | ||||
| 	return ser.in.Read(buf) | ||||
| } | ||||
| 
 | ||||
| func (ser seReader) Close() error { | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| const mdcTrailerSize = 1 /* tag byte */ + 1 /* length byte */ + sha1.Size | ||||
| 
 | ||||
| // An seMDCReader wraps an io.Reader, maintains a running hash and keeps hold
 | ||||
| // of the most recent 22 bytes (mdcTrailerSize). Upon EOF, those bytes form an
 | ||||
| // MDC packet containing a hash of the previous Contents which is checked
 | ||||
| // against the running hash. See RFC 4880, section 5.13.
 | ||||
| type seMDCReader struct { | ||||
| 	in          io.Reader | ||||
| 	h           hash.Hash | ||||
| 	trailer     [mdcTrailerSize]byte | ||||
| 	scratch     [mdcTrailerSize]byte | ||||
| 	trailerUsed int | ||||
| 	error       bool | ||||
| 	eof         bool | ||||
| } | ||||
| 
 | ||||
| func (ser *seMDCReader) Read(buf []byte) (n int, err error) { | ||||
| 	if ser.error { | ||||
| 		err = io.ErrUnexpectedEOF | ||||
| 		return | ||||
| 	} | ||||
| 	if ser.eof { | ||||
| 		err = io.EOF | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	// If we haven't yet filled the trailer buffer then we must do that
 | ||||
| 	// first.
 | ||||
| 	for ser.trailerUsed < mdcTrailerSize { | ||||
| 		n, err = ser.in.Read(ser.trailer[ser.trailerUsed:]) | ||||
| 		ser.trailerUsed += n | ||||
| 		if err == io.EOF { | ||||
| 			if ser.trailerUsed != mdcTrailerSize { | ||||
| 				n = 0 | ||||
| 				err = io.ErrUnexpectedEOF | ||||
| 				ser.error = true | ||||
| 				return | ||||
| 			} | ||||
| 			ser.eof = true | ||||
| 			n = 0 | ||||
| 			return | ||||
| 		} | ||||
| 
 | ||||
| 		if err != nil { | ||||
| 			n = 0 | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// If it's a short read then we read into a temporary buffer and shift
 | ||||
| 	// the data into the caller's buffer.
 | ||||
| 	if len(buf) <= mdcTrailerSize { | ||||
| 		n, err = readFull(ser.in, ser.scratch[:len(buf)]) | ||||
| 		copy(buf, ser.trailer[:n]) | ||||
| 		ser.h.Write(buf[:n]) | ||||
| 		copy(ser.trailer[:], ser.trailer[n:]) | ||||
| 		copy(ser.trailer[mdcTrailerSize-n:], ser.scratch[:]) | ||||
| 		if n < len(buf) { | ||||
| 			ser.eof = true | ||||
| 			err = io.EOF | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	n, err = ser.in.Read(buf[mdcTrailerSize:]) | ||||
| 	copy(buf, ser.trailer[:]) | ||||
| 	ser.h.Write(buf[:n]) | ||||
| 	copy(ser.trailer[:], buf[n:]) | ||||
| 
 | ||||
| 	if err == io.EOF { | ||||
| 		ser.eof = true | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // This is a new-format packet tag byte for a type 19 (MDC) packet.
 | ||||
| const mdcPacketTagByte = byte(0x80) | 0x40 | 19 | ||||
| 
 | ||||
| func (ser *seMDCReader) Close() error { | ||||
| 	if ser.error { | ||||
| 		return errors.ErrMDCMissing | ||||
| 	} | ||||
| 
 | ||||
| 	for !ser.eof { | ||||
| 		// We haven't seen EOF so we need to read to the end
 | ||||
| 		var buf [1024]byte | ||||
| 		_, err := ser.Read(buf[:]) | ||||
| 		if err == io.EOF { | ||||
| 			break | ||||
| 		} | ||||
| 		if err != nil { | ||||
| 			return errors.ErrMDCMissing | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	ser.h.Write(ser.trailer[:2]) | ||||
| 
 | ||||
| 	final := ser.h.Sum(nil) | ||||
| 	if subtle.ConstantTimeCompare(final, ser.trailer[2:]) != 1 { | ||||
| 		return errors.ErrMDCHashMismatch | ||||
| 	} | ||||
| 	// The hash already includes the MDC header, but we still check its value
 | ||||
| 	// to confirm encryption correctness
 | ||||
| 	if ser.trailer[0] != mdcPacketTagByte || ser.trailer[1] != sha1.Size { | ||||
| 		return errors.ErrMDCMissing | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // An seMDCWriter writes through to an io.WriteCloser while maintains a running
 | ||||
| // hash of the data written. On close, it emits an MDC packet containing the
 | ||||
| // running hash.
 | ||||
| type seMDCWriter struct { | ||||
| 	w io.WriteCloser | ||||
| 	h hash.Hash | ||||
| } | ||||
| 
 | ||||
| func (w *seMDCWriter) Write(buf []byte) (n int, err error) { | ||||
| 	w.h.Write(buf) | ||||
| 	return w.w.Write(buf) | ||||
| } | ||||
| 
 | ||||
| func (w *seMDCWriter) Close() (err error) { | ||||
| 	var buf [mdcTrailerSize]byte | ||||
| 
 | ||||
| 	buf[0] = mdcPacketTagByte | ||||
| 	buf[1] = sha1.Size | ||||
| 	w.h.Write(buf[:2]) | ||||
| 	digest := w.h.Sum(nil) | ||||
| 	copy(buf[2:], digest) | ||||
| 
 | ||||
| 	_, err = w.w.Write(buf[:]) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	return w.w.Close() | ||||
| } | ||||
| 
 | ||||
| // noOpCloser is like an ioutil.NopCloser, but for an io.Writer.
 | ||||
| type noOpCloser struct { | ||||
| 	w io.Writer | ||||
| } | ||||
| 
 | ||||
| func (c noOpCloser) Write(data []byte) (n int, err error) { | ||||
| 	return c.w.Write(data) | ||||
| } | ||||
| 
 | ||||
| func (c noOpCloser) Close() error { | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // SerializeSymmetricallyEncrypted serializes a symmetrically encrypted packet
 | ||||
| // to w and returns a WriteCloser to which the to-be-encrypted packets can be
 | ||||
| // written.
 | ||||
| // If config is nil, sensible defaults will be used.
 | ||||
| func SerializeSymmetricallyEncrypted(w io.Writer, c CipherFunction, key []byte, config *Config) (Contents io.WriteCloser, err error) { | ||||
| 	if c.KeySize() != len(key) { | ||||
| 		return nil, errors.InvalidArgumentError("SymmetricallyEncrypted.Serialize: bad key length") | ||||
| 	} | ||||
| 	writeCloser := noOpCloser{w} | ||||
| 	ciphertext, err := serializeStreamHeader(writeCloser, packetTypeSymmetricallyEncryptedMDC) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	_, err = ciphertext.Write([]byte{symmetricallyEncryptedVersion}) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	block := c.new(key) | ||||
| 	blockSize := block.BlockSize() | ||||
| 	iv := make([]byte, blockSize) | ||||
| 	_, err = config.Random().Read(iv) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	s, prefix := NewOCFBEncrypter(block, iv, OCFBNoResync) | ||||
| 	_, err = ciphertext.Write(prefix) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	plaintext := cipher.StreamWriter{S: s, W: ciphertext} | ||||
| 
 | ||||
| 	h := sha1.New() | ||||
| 	h.Write(iv) | ||||
| 	h.Write(iv[blockSize-2:]) | ||||
| 	Contents = &seMDCWriter{w: plaintext, h: h} | ||||
| 	return | ||||
| } | ||||
							
								
								
									
										94
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/userattribute.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										94
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/userattribute.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							|  | @ -0,0 +1,94 @@ | |||
| // Copyright 2013 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 ( | ||||
| 	"bytes" | ||||
| 	"image" | ||||
| 	"image/jpeg" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| ) | ||||
| 
 | ||||
| const UserAttrImageSubpacket = 1 | ||||
| 
 | ||||
| // UserAttribute is capable of storing other types of data about a user
 | ||||
| // beyond name, email and a text comment. In practice, user attributes are typically used
 | ||||
| // to store a signed thumbnail photo JPEG image of the user.
 | ||||
| // See RFC 4880, section 5.12.
 | ||||
| type UserAttribute struct { | ||||
| 	Contents []*OpaqueSubpacket | ||||
| } | ||||
| 
 | ||||
| // NewUserAttributePhoto creates a user attribute packet
 | ||||
| // containing the given images.
 | ||||
| func NewUserAttributePhoto(photos ...image.Image) (uat *UserAttribute, err error) { | ||||
| 	uat = new(UserAttribute) | ||||
| 	for _, photo := range photos { | ||||
| 		var buf bytes.Buffer | ||||
| 		// RFC 4880, Section 5.12.1.
 | ||||
| 		data := []byte{ | ||||
| 			0x10, 0x00, // Little-endian image header length (16 bytes)
 | ||||
| 			0x01,       // Image header version 1
 | ||||
| 			0x01,       // JPEG
 | ||||
| 			0, 0, 0, 0, // 12 reserved octets, must be all zero.
 | ||||
| 			0, 0, 0, 0, | ||||
| 			0, 0, 0, 0} | ||||
| 		if _, err = buf.Write(data); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		if err = jpeg.Encode(&buf, photo, nil); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		uat.Contents = append(uat.Contents, &OpaqueSubpacket{ | ||||
| 			SubType:  UserAttrImageSubpacket, | ||||
| 			Contents: buf.Bytes()}) | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // NewUserAttribute creates a new user attribute packet containing the given subpackets.
 | ||||
| func NewUserAttribute(contents ...*OpaqueSubpacket) *UserAttribute { | ||||
| 	return &UserAttribute{Contents: contents} | ||||
| } | ||||
| 
 | ||||
| func (uat *UserAttribute) parse(r io.Reader) (err error) { | ||||
| 	// RFC 4880, section 5.13
 | ||||
| 	b, err := ioutil.ReadAll(r) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	uat.Contents, err = OpaqueSubpackets(b) | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // Serialize marshals the user attribute to w in the form of an OpenPGP packet, including
 | ||||
| // header.
 | ||||
| func (uat *UserAttribute) Serialize(w io.Writer) (err error) { | ||||
| 	var buf bytes.Buffer | ||||
| 	for _, sp := range uat.Contents { | ||||
| 		err = sp.Serialize(&buf) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	if err = serializeHeader(w, packetTypeUserAttribute, buf.Len()); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	_, err = w.Write(buf.Bytes()) | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // ImageData returns zero or more byte slices, each containing
 | ||||
| // JPEG File Interchange Format (JFIF), for each photo in the
 | ||||
| // user attribute packet.
 | ||||
| func (uat *UserAttribute) ImageData() (imageData [][]byte) { | ||||
| 	for _, sp := range uat.Contents { | ||||
| 		if sp.SubType == UserAttrImageSubpacket && len(sp.Contents) > 16 { | ||||
| 			imageData = append(imageData, sp.Contents[16:]) | ||||
| 		} | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | @ -0,0 +1,160 @@ | |||
| // 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 ( | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"strings" | ||||
| ) | ||||
| 
 | ||||
| // UserId contains text that is intended to represent the name and email
 | ||||
| // address of the key holder. See RFC 4880, section 5.11. By convention, this
 | ||||
| // takes the form "Full Name (Comment) <email@example.com>"
 | ||||
| type UserId struct { | ||||
| 	Id string // By convention, this takes the form "Full Name (Comment) <email@example.com>" which is split out in the fields below.
 | ||||
| 
 | ||||
| 	Name, Comment, Email string | ||||
| } | ||||
| 
 | ||||
| func hasInvalidCharacters(s string) bool { | ||||
| 	for _, c := range s { | ||||
| 		switch c { | ||||
| 		case '(', ')', '<', '>', 0: | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| // NewUserId returns a UserId or nil if any of the arguments contain invalid
 | ||||
| // characters. The invalid characters are '\x00', '(', ')', '<' and '>'
 | ||||
| func NewUserId(name, comment, email string) *UserId { | ||||
| 	// RFC 4880 doesn't deal with the structure of userid strings; the
 | ||||
| 	// name, comment and email form is just a convention. However, there's
 | ||||
| 	// no convention about escaping the metacharacters and GPG just refuses
 | ||||
| 	// to create user ids where, say, the name contains a '('. We mirror
 | ||||
| 	// this behaviour.
 | ||||
| 
 | ||||
| 	if hasInvalidCharacters(name) || hasInvalidCharacters(comment) || hasInvalidCharacters(email) { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	uid := new(UserId) | ||||
| 	uid.Name, uid.Comment, uid.Email = name, comment, email | ||||
| 	uid.Id = name | ||||
| 	if len(comment) > 0 { | ||||
| 		if len(uid.Id) > 0 { | ||||
| 			uid.Id += " " | ||||
| 		} | ||||
| 		uid.Id += "(" | ||||
| 		uid.Id += comment | ||||
| 		uid.Id += ")" | ||||
| 	} | ||||
| 	if len(email) > 0 { | ||||
| 		if len(uid.Id) > 0 { | ||||
| 			uid.Id += " " | ||||
| 		} | ||||
| 		uid.Id += "<" | ||||
| 		uid.Id += email | ||||
| 		uid.Id += ">" | ||||
| 	} | ||||
| 	return uid | ||||
| } | ||||
| 
 | ||||
| func (uid *UserId) parse(r io.Reader) (err error) { | ||||
| 	// RFC 4880, section 5.11
 | ||||
| 	b, err := ioutil.ReadAll(r) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	uid.Id = string(b) | ||||
| 	uid.Name, uid.Comment, uid.Email = parseUserId(uid.Id) | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // Serialize marshals uid to w in the form of an OpenPGP packet, including
 | ||||
| // header.
 | ||||
| func (uid *UserId) Serialize(w io.Writer) error { | ||||
| 	err := serializeHeader(w, packetTypeUserId, len(uid.Id)) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	_, err = w.Write([]byte(uid.Id)) | ||||
| 	return err | ||||
| } | ||||
| 
 | ||||
| // parseUserId extracts the name, comment and email from a user id string that
 | ||||
| // is formatted as "Full Name (Comment) <email@example.com>".
 | ||||
| func parseUserId(id string) (name, comment, email string) { | ||||
| 	var n, c, e struct { | ||||
| 		start, end int | ||||
| 	} | ||||
| 	var state int | ||||
| 
 | ||||
| 	for offset, rune := range id { | ||||
| 		switch state { | ||||
| 		case 0: | ||||
| 			// Entering name
 | ||||
| 			n.start = offset | ||||
| 			state = 1 | ||||
| 			fallthrough | ||||
| 		case 1: | ||||
| 			// In name
 | ||||
| 			if rune == '(' { | ||||
| 				state = 2 | ||||
| 				n.end = offset | ||||
| 			} else if rune == '<' { | ||||
| 				state = 5 | ||||
| 				n.end = offset | ||||
| 			} | ||||
| 		case 2: | ||||
| 			// Entering comment
 | ||||
| 			c.start = offset | ||||
| 			state = 3 | ||||
| 			fallthrough | ||||
| 		case 3: | ||||
| 			// In comment
 | ||||
| 			if rune == ')' { | ||||
| 				state = 4 | ||||
| 				c.end = offset | ||||
| 			} | ||||
| 		case 4: | ||||
| 			// Between comment and email
 | ||||
| 			if rune == '<' { | ||||
| 				state = 5 | ||||
| 			} | ||||
| 		case 5: | ||||
| 			// Entering email
 | ||||
| 			e.start = offset | ||||
| 			state = 6 | ||||
| 			fallthrough | ||||
| 		case 6: | ||||
| 			// In email
 | ||||
| 			if rune == '>' { | ||||
| 				state = 7 | ||||
| 				e.end = offset | ||||
| 			} | ||||
| 		default: | ||||
| 			// After email
 | ||||
| 		} | ||||
| 	} | ||||
| 	switch state { | ||||
| 	case 1: | ||||
| 		// ended in the name
 | ||||
| 		n.end = len(id) | ||||
| 	case 3: | ||||
| 		// ended in comment
 | ||||
| 		c.end = len(id) | ||||
| 	case 6: | ||||
| 		// ended in email
 | ||||
| 		e.end = len(id) | ||||
| 	} | ||||
| 
 | ||||
| 	name = strings.TrimSpace(id[n.start:n.end]) | ||||
| 	comment = strings.TrimSpace(id[c.start:c.end]) | ||||
| 	email = strings.TrimSpace(id[e.start:e.end]) | ||||
| 	return | ||||
| } | ||||
|  | @ -0,0 +1,508 @@ | |||
| // 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 implements high level operations on OpenPGP messages.
 | ||||
| package openpgp // import "github.com/ProtonMail/go-crypto/openpgp"
 | ||||
| 
 | ||||
| import ( | ||||
| 	"crypto" | ||||
| 	_ "crypto/sha256" | ||||
| 	"hash" | ||||
| 	"io" | ||||
| 	"strconv" | ||||
| 
 | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/armor" | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/errors" | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/packet" | ||||
| ) | ||||
| 
 | ||||
| // SignatureType is the armor type for a PGP signature.
 | ||||
| var SignatureType = "PGP SIGNATURE" | ||||
| 
 | ||||
| // readArmored reads an armored block with the given type.
 | ||||
| func readArmored(r io.Reader, expectedType string) (body io.Reader, err error) { | ||||
| 	block, err := armor.Decode(r) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	if block.Type != expectedType { | ||||
| 		return nil, errors.InvalidArgumentError("expected '" + expectedType + "', got: " + block.Type) | ||||
| 	} | ||||
| 
 | ||||
| 	return block.Body, nil | ||||
| } | ||||
| 
 | ||||
| // MessageDetails contains the result of parsing an OpenPGP encrypted and/or
 | ||||
| // signed message.
 | ||||
| type MessageDetails struct { | ||||
| 	IsEncrypted              bool                // true if the message was encrypted.
 | ||||
| 	EncryptedToKeyIds        []uint64            // the list of recipient key ids.
 | ||||
| 	IsSymmetricallyEncrypted bool                // true if a passphrase could have decrypted the message.
 | ||||
| 	DecryptedWith            Key                 // the private key used to decrypt the message, if any.
 | ||||
| 	IsSigned                 bool                // true if the message is signed.
 | ||||
| 	SignedByKeyId            uint64              // the key id of the signer, if any.
 | ||||
| 	SignedBy                 *Key                // the key of the signer, if available.
 | ||||
| 	LiteralData              *packet.LiteralData // the metadata of the contents
 | ||||
| 	UnverifiedBody           io.Reader           // the contents of the message.
 | ||||
| 
 | ||||
| 	// If IsSigned is true and SignedBy is non-zero then the signature will
 | ||||
| 	// be verified as UnverifiedBody is read. The signature cannot be
 | ||||
| 	// checked until the whole of UnverifiedBody is read so UnverifiedBody
 | ||||
| 	// must be consumed until EOF before the data can be trusted. Even if a
 | ||||
| 	// message isn't signed (or the signer is unknown) the data may contain
 | ||||
| 	// an authentication code that is only checked once UnverifiedBody has
 | ||||
| 	// been consumed. Once EOF has been seen, the following fields are
 | ||||
| 	// valid. (An authentication code failure is reported as a
 | ||||
| 	// SignatureError error when reading from UnverifiedBody.)
 | ||||
| 	Signature            *packet.Signature   // the signature packet itself.
 | ||||
| 	SignatureError       error               // nil if the signature is good.
 | ||||
| 	UnverifiedSignatures []*packet.Signature // all other unverified signature packets.
 | ||||
| 
 | ||||
| 	decrypted io.ReadCloser | ||||
| } | ||||
| 
 | ||||
| // A PromptFunction is used as a callback by functions that may need to decrypt
 | ||||
| // a private key, or prompt for a passphrase. It is called with a list of
 | ||||
| // acceptable, encrypted private keys and a boolean that indicates whether a
 | ||||
| // passphrase is usable. It should either decrypt a private key or return a
 | ||||
| // passphrase to try. If the decrypted private key or given passphrase isn't
 | ||||
| // correct, the function will be called again, forever. Any error returned will
 | ||||
| // be passed up.
 | ||||
| type PromptFunction func(keys []Key, symmetric bool) ([]byte, error) | ||||
| 
 | ||||
| // A keyEnvelopePair is used to store a private key with the envelope that
 | ||||
| // contains a symmetric key, encrypted with that key.
 | ||||
| type keyEnvelopePair struct { | ||||
| 	key          Key | ||||
| 	encryptedKey *packet.EncryptedKey | ||||
| } | ||||
| 
 | ||||
| // ReadMessage parses an OpenPGP message that may be signed and/or encrypted.
 | ||||
| // The given KeyRing should contain both public keys (for signature
 | ||||
| // verification) and, possibly encrypted, private keys for decrypting.
 | ||||
| // If config is nil, sensible defaults will be used.
 | ||||
| func ReadMessage(r io.Reader, keyring KeyRing, prompt PromptFunction, config *packet.Config) (md *MessageDetails, err error) { | ||||
| 	var p packet.Packet | ||||
| 
 | ||||
| 	var symKeys []*packet.SymmetricKeyEncrypted | ||||
| 	var pubKeys []keyEnvelopePair | ||||
| 	// Integrity protected encrypted packet: SymmetricallyEncrypted or AEADEncrypted
 | ||||
| 	var edp packet.EncryptedDataPacket | ||||
| 
 | ||||
| 	packets := packet.NewReader(r) | ||||
| 	md = new(MessageDetails) | ||||
| 	md.IsEncrypted = true | ||||
| 
 | ||||
| 	// The message, if encrypted, starts with a number of packets
 | ||||
| 	// containing an encrypted decryption key. The decryption key is either
 | ||||
| 	// encrypted to a public key, or with a passphrase. This loop
 | ||||
| 	// collects these packets.
 | ||||
| ParsePackets: | ||||
| 	for { | ||||
| 		p, err = packets.Next() | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		switch p := p.(type) { | ||||
| 		case *packet.SymmetricKeyEncrypted: | ||||
| 			// This packet contains the decryption key encrypted with a passphrase.
 | ||||
| 			md.IsSymmetricallyEncrypted = true | ||||
| 			symKeys = append(symKeys, p) | ||||
| 		case *packet.EncryptedKey: | ||||
| 			// This packet contains the decryption key encrypted to a public key.
 | ||||
| 			md.EncryptedToKeyIds = append(md.EncryptedToKeyIds, p.KeyId) | ||||
| 			switch p.Algo { | ||||
| 			case packet.PubKeyAlgoRSA, packet.PubKeyAlgoRSAEncryptOnly, packet.PubKeyAlgoElGamal, packet.PubKeyAlgoECDH: | ||||
| 				break | ||||
| 			default: | ||||
| 				continue | ||||
| 			} | ||||
| 			var keys []Key | ||||
| 			if p.KeyId == 0 { | ||||
| 				keys = keyring.DecryptionKeys() | ||||
| 			} else { | ||||
| 				keys = keyring.KeysById(p.KeyId) | ||||
| 			} | ||||
| 			for _, k := range keys { | ||||
| 				pubKeys = append(pubKeys, keyEnvelopePair{k, p}) | ||||
| 			} | ||||
| 		case *packet.SymmetricallyEncrypted, *packet.AEADEncrypted: | ||||
| 			edp = p.(packet.EncryptedDataPacket) | ||||
| 			break ParsePackets | ||||
| 		case *packet.Compressed, *packet.LiteralData, *packet.OnePassSignature: | ||||
| 			// This message isn't encrypted.
 | ||||
| 			if len(symKeys) != 0 || len(pubKeys) != 0 { | ||||
| 				return nil, errors.StructuralError("key material not followed by encrypted message") | ||||
| 			} | ||||
| 			packets.Unread(p) | ||||
| 			return readSignedMessage(packets, nil, keyring, config) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	var candidates []Key | ||||
| 	var decrypted io.ReadCloser | ||||
| 
 | ||||
| 	// Now that we have the list of encrypted keys we need to decrypt at
 | ||||
| 	// least one of them or, if we cannot, we need to call the prompt
 | ||||
| 	// function so that it can decrypt a key or give us a passphrase.
 | ||||
| FindKey: | ||||
| 	for { | ||||
| 		// See if any of the keys already have a private key available
 | ||||
| 		candidates = candidates[:0] | ||||
| 		candidateFingerprints := make(map[string]bool) | ||||
| 
 | ||||
| 		for _, pk := range pubKeys { | ||||
| 			if pk.key.PrivateKey == nil { | ||||
| 				continue | ||||
| 			} | ||||
| 			if !pk.key.PrivateKey.Encrypted { | ||||
| 				if len(pk.encryptedKey.Key) == 0 { | ||||
| 					errDec := pk.encryptedKey.Decrypt(pk.key.PrivateKey, config) | ||||
| 					if errDec != nil { | ||||
| 						continue | ||||
| 					} | ||||
| 				} | ||||
| 				// Try to decrypt symmetrically encrypted
 | ||||
| 				decrypted, err = edp.Decrypt(pk.encryptedKey.CipherFunc, pk.encryptedKey.Key) | ||||
| 				if err != nil && err != errors.ErrKeyIncorrect { | ||||
| 					return nil, err | ||||
| 				} | ||||
| 				if decrypted != nil { | ||||
| 					md.DecryptedWith = pk.key | ||||
| 					break FindKey | ||||
| 				} | ||||
| 			} else { | ||||
| 				fpr := string(pk.key.PublicKey.Fingerprint[:]) | ||||
| 				if v := candidateFingerprints[fpr]; v { | ||||
| 					continue | ||||
| 				} | ||||
| 				candidates = append(candidates, pk.key) | ||||
| 				candidateFingerprints[fpr] = true | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		if len(candidates) == 0 && len(symKeys) == 0 { | ||||
| 			return nil, errors.ErrKeyIncorrect | ||||
| 		} | ||||
| 
 | ||||
| 		if prompt == nil { | ||||
| 			return nil, errors.ErrKeyIncorrect | ||||
| 		} | ||||
| 
 | ||||
| 		passphrase, err := prompt(candidates, len(symKeys) != 0) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 
 | ||||
| 		// Try the symmetric passphrase first
 | ||||
| 		if len(symKeys) != 0 && passphrase != nil { | ||||
| 			for _, s := range symKeys { | ||||
| 				key, cipherFunc, err := s.Decrypt(passphrase) | ||||
| 				// On wrong passphrase, session key decryption is very likely to result in an invalid cipherFunc:
 | ||||
| 				// only for < 5% of cases we will proceed to decrypt the data
 | ||||
| 				if err == nil { | ||||
| 					decrypted, err = edp.Decrypt(cipherFunc, key) | ||||
| 					// TODO: ErrKeyIncorrect is no longer thrown on SEIP decryption,
 | ||||
| 					// but it might still be relevant for when we implement AEAD decryption (otherwise, remove?)
 | ||||
| 					if err != nil && err != errors.ErrKeyIncorrect { | ||||
| 						return nil, err | ||||
| 					} | ||||
| 					if decrypted != nil { | ||||
| 						break FindKey | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	md.decrypted = decrypted | ||||
| 	if err := packets.Push(decrypted); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	mdFinal, sensitiveParsingErr := readSignedMessage(packets, md, keyring, config) | ||||
| 	if sensitiveParsingErr != nil { | ||||
| 		return nil, errors.StructuralError("parsing error") | ||||
| 	} | ||||
| 	return mdFinal, nil | ||||
| } | ||||
| 
 | ||||
| // readSignedMessage reads a possibly signed message if mdin is non-zero then
 | ||||
| // that structure is updated and returned. Otherwise a fresh MessageDetails is
 | ||||
| // used.
 | ||||
| func readSignedMessage(packets *packet.Reader, mdin *MessageDetails, keyring KeyRing, config *packet.Config) (md *MessageDetails, err error) { | ||||
| 	if mdin == nil { | ||||
| 		mdin = new(MessageDetails) | ||||
| 	} | ||||
| 	md = mdin | ||||
| 
 | ||||
| 	var p packet.Packet | ||||
| 	var h hash.Hash | ||||
| 	var wrappedHash hash.Hash | ||||
| 	var prevLast bool | ||||
| FindLiteralData: | ||||
| 	for { | ||||
| 		p, err = packets.Next() | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		switch p := p.(type) { | ||||
| 		case *packet.Compressed: | ||||
| 			if err := packets.Push(p.Body); err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 		case *packet.OnePassSignature: | ||||
| 			if prevLast { | ||||
| 				return nil, errors.UnsupportedError("nested signature packets") | ||||
| 			} | ||||
| 
 | ||||
| 			if p.IsLast { | ||||
| 				prevLast = true | ||||
| 			} | ||||
| 
 | ||||
| 			h, wrappedHash, err = hashForSignature(p.Hash, p.SigType) | ||||
| 			if err != nil { | ||||
| 				md.SignatureError = err | ||||
| 			} | ||||
| 
 | ||||
| 			md.IsSigned = true | ||||
| 			md.SignedByKeyId = p.KeyId | ||||
| 			keys := keyring.KeysByIdUsage(p.KeyId, packet.KeyFlagSign) | ||||
| 			if len(keys) > 0 { | ||||
| 				md.SignedBy = &keys[0] | ||||
| 			} | ||||
| 		case *packet.LiteralData: | ||||
| 			md.LiteralData = p | ||||
| 			break FindLiteralData | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if md.IsSigned && md.SignatureError == nil { | ||||
| 		md.UnverifiedBody = &signatureCheckReader{packets, h, wrappedHash, md, config} | ||||
| 	} else if md.decrypted != nil { | ||||
| 		md.UnverifiedBody = checkReader{md} | ||||
| 	} else { | ||||
| 		md.UnverifiedBody = md.LiteralData.Body | ||||
| 	} | ||||
| 
 | ||||
| 	return md, nil | ||||
| } | ||||
| 
 | ||||
| // hashForSignature returns a pair of hashes that can be used to verify a
 | ||||
| // signature. The signature may specify that the contents of the signed message
 | ||||
| // should be preprocessed (i.e. to normalize line endings). Thus this function
 | ||||
| // returns two hashes. The second should be used to hash the message itself and
 | ||||
| // performs any needed preprocessing.
 | ||||
| func hashForSignature(hashId crypto.Hash, sigType packet.SignatureType) (hash.Hash, hash.Hash, error) { | ||||
| 	if hashId == crypto.MD5 { | ||||
| 		return nil, nil, errors.UnsupportedError("insecure hash algorithm: MD5") | ||||
| 	} | ||||
| 	if !hashId.Available() { | ||||
| 		return nil, nil, errors.UnsupportedError("hash not available: " + strconv.Itoa(int(hashId))) | ||||
| 	} | ||||
| 	h := hashId.New() | ||||
| 
 | ||||
| 	switch sigType { | ||||
| 	case packet.SigTypeBinary: | ||||
| 		return h, h, nil | ||||
| 	case packet.SigTypeText: | ||||
| 		return h, NewCanonicalTextHash(h), nil | ||||
| 	} | ||||
| 
 | ||||
| 	return nil, nil, errors.UnsupportedError("unsupported signature type: " + strconv.Itoa(int(sigType))) | ||||
| } | ||||
| 
 | ||||
| // checkReader wraps an io.Reader from a LiteralData packet. When it sees EOF
 | ||||
| // it closes the ReadCloser from any SymmetricallyEncrypted packet to trigger
 | ||||
| // MDC checks.
 | ||||
| type checkReader struct { | ||||
| 	md *MessageDetails | ||||
| } | ||||
| 
 | ||||
| func (cr checkReader) Read(buf []byte) (int, error) { | ||||
| 	n, sensitiveParsingError := cr.md.LiteralData.Body.Read(buf) | ||||
| 	if sensitiveParsingError == io.EOF { | ||||
| 		mdcErr := cr.md.decrypted.Close() | ||||
| 		if mdcErr != nil { | ||||
| 			return n, mdcErr | ||||
| 		} | ||||
| 		return n, io.EOF | ||||
| 	} | ||||
| 
 | ||||
| 	if sensitiveParsingError != nil { | ||||
| 		return n, errors.StructuralError("parsing error") | ||||
| 	} | ||||
| 
 | ||||
| 	return n, nil | ||||
| } | ||||
| 
 | ||||
| // signatureCheckReader wraps an io.Reader from a LiteralData packet and hashes
 | ||||
| // the data as it is read. When it sees an EOF from the underlying io.Reader
 | ||||
| // it parses and checks a trailing Signature packet and triggers any MDC checks.
 | ||||
| type signatureCheckReader struct { | ||||
| 	packets        *packet.Reader | ||||
| 	h, wrappedHash hash.Hash | ||||
| 	md             *MessageDetails | ||||
| 	config         *packet.Config | ||||
| } | ||||
| 
 | ||||
| func (scr *signatureCheckReader) Read(buf []byte) (int, error) { | ||||
| 	n, sensitiveParsingError := scr.md.LiteralData.Body.Read(buf) | ||||
| 
 | ||||
| 	// Hash only if required
 | ||||
| 	if scr.md.SignedBy != nil { | ||||
| 		scr.wrappedHash.Write(buf[:n]) | ||||
| 	} | ||||
| 
 | ||||
| 	if sensitiveParsingError == io.EOF { | ||||
| 		var p packet.Packet | ||||
| 		var readError error | ||||
| 		var sig *packet.Signature | ||||
| 
 | ||||
| 		p, readError = scr.packets.Next() | ||||
| 		for readError == nil { | ||||
| 			var ok bool | ||||
| 			if sig, ok = p.(*packet.Signature); ok { | ||||
| 				if sig.Version == 5 && (sig.SigType == 0x00 || sig.SigType == 0x01) { | ||||
| 					sig.Metadata = scr.md.LiteralData | ||||
| 				} | ||||
| 
 | ||||
| 				// If signature KeyID matches
 | ||||
| 				if scr.md.SignedBy != nil && *sig.IssuerKeyId == scr.md.SignedByKeyId { | ||||
| 					scr.md.Signature = sig | ||||
| 					scr.md.SignatureError = scr.md.SignedBy.PublicKey.VerifySignature(scr.h, scr.md.Signature) | ||||
| 					if scr.md.SignatureError == nil && scr.md.Signature.SigExpired(scr.config.Now()) { | ||||
| 						scr.md.SignatureError = errors.ErrSignatureExpired | ||||
| 					} | ||||
| 				} else { | ||||
| 					scr.md.UnverifiedSignatures = append(scr.md.UnverifiedSignatures, sig) | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			p, readError = scr.packets.Next() | ||||
| 		} | ||||
| 
 | ||||
| 		if scr.md.SignedBy != nil && scr.md.Signature == nil { | ||||
| 			if scr.md.UnverifiedSignatures == nil { | ||||
| 				scr.md.SignatureError = errors.StructuralError("LiteralData not followed by signature") | ||||
| 			} else { | ||||
| 				scr.md.SignatureError = errors.StructuralError("No matching signature found") | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		// The SymmetricallyEncrypted packet, if any, might have an
 | ||||
| 		// unsigned hash of its own. In order to check this we need to
 | ||||
| 		// close that Reader.
 | ||||
| 		if scr.md.decrypted != nil { | ||||
| 			mdcErr := scr.md.decrypted.Close() | ||||
| 			if mdcErr != nil { | ||||
| 				return n, mdcErr | ||||
| 			} | ||||
| 		} | ||||
| 		return n, io.EOF | ||||
| 	} | ||||
| 
 | ||||
| 	if sensitiveParsingError != nil { | ||||
| 		return n, errors.StructuralError("parsing error") | ||||
| 	} | ||||
| 
 | ||||
| 	return n, nil | ||||
| } | ||||
| 
 | ||||
| // CheckDetachedSignature takes a signed file and a detached signature and
 | ||||
| // returns the signer if the signature is valid. If the signer isn't known,
 | ||||
| // ErrUnknownIssuer is returned.
 | ||||
| func CheckDetachedSignature(keyring KeyRing, signed, signature io.Reader, config *packet.Config) (signer *Entity, err error) { | ||||
| 	var expectedHashes []crypto.Hash | ||||
| 	return CheckDetachedSignatureAndHash(keyring, signed, signature, expectedHashes, config) | ||||
| } | ||||
| 
 | ||||
| // CheckDetachedSignatureAndHash performs the same actions as
 | ||||
| // CheckDetachedSignature and checks that the expected hash functions were used.
 | ||||
| func CheckDetachedSignatureAndHash(keyring KeyRing, signed, signature io.Reader, expectedHashes []crypto.Hash, config *packet.Config) (signer *Entity, err error) { | ||||
| 	var issuerKeyId uint64 | ||||
| 	var hashFunc crypto.Hash | ||||
| 	var sigType packet.SignatureType | ||||
| 	var keys []Key | ||||
| 	var p packet.Packet | ||||
| 
 | ||||
| 	expectedHashesLen := len(expectedHashes) | ||||
| 	packets := packet.NewReader(signature) | ||||
| 	var sig *packet.Signature | ||||
| 	for { | ||||
| 		p, err = packets.Next() | ||||
| 		if err == io.EOF { | ||||
| 			return nil, errors.ErrUnknownIssuer | ||||
| 		} | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 
 | ||||
| 		var ok bool | ||||
| 		sig, ok = p.(*packet.Signature) | ||||
| 		if !ok { | ||||
| 			return nil, errors.StructuralError("non signature packet found") | ||||
| 		} | ||||
| 		if sig.IssuerKeyId == nil { | ||||
| 			return nil, errors.StructuralError("signature doesn't have an issuer") | ||||
| 		} | ||||
| 		issuerKeyId = *sig.IssuerKeyId | ||||
| 		hashFunc = sig.Hash | ||||
| 		sigType = sig.SigType | ||||
| 
 | ||||
| 		for i, expectedHash := range expectedHashes { | ||||
| 			if hashFunc == expectedHash { | ||||
| 				break | ||||
| 			} | ||||
| 			if i+1 == expectedHashesLen { | ||||
| 				return nil, errors.StructuralError("hash algorithm mismatch with cleartext message headers") | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		keys = keyring.KeysByIdUsage(issuerKeyId, packet.KeyFlagSign) | ||||
| 		if len(keys) > 0 { | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if len(keys) == 0 { | ||||
| 		panic("unreachable") | ||||
| 	} | ||||
| 
 | ||||
| 	h, wrappedHash, err := hashForSignature(hashFunc, sigType) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	if _, err := io.Copy(wrappedHash, signed); err != nil && err != io.EOF { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	for _, key := range keys { | ||||
| 		err = key.PublicKey.VerifySignature(h, sig) | ||||
| 		if err == nil { | ||||
| 			now := config.Now() | ||||
| 			if sig.SigExpired(now) { | ||||
| 				return key.Entity, errors.ErrSignatureExpired | ||||
| 			} | ||||
| 			if key.PublicKey.KeyExpired(key.SelfSignature, now) { | ||||
| 				return key.Entity, errors.ErrKeyExpired | ||||
| 			} | ||||
| 			return key.Entity, nil | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return nil, err | ||||
| } | ||||
| 
 | ||||
| // CheckArmoredDetachedSignature performs the same actions as
 | ||||
| // CheckDetachedSignature but expects the signature to be armored.
 | ||||
| func CheckArmoredDetachedSignature(keyring KeyRing, signed, signature io.Reader, config *packet.Config) (signer *Entity, err error) { | ||||
| 	body, err := readArmored(signature, SignatureType) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	return CheckDetachedSignature(keyring, signed, body, config) | ||||
| } | ||||
							
								
								
									
										173
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/read_write_test_data.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										173
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/read_write_test_data.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							|  | @ -0,0 +1,367 @@ | |||
| // 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 s2k implements the various OpenPGP string-to-key transforms as
 | ||||
| // specified in RFC 4800 section 3.7.1.
 | ||||
| package s2k // import "github.com/ProtonMail/go-crypto/openpgp/s2k"
 | ||||
| 
 | ||||
| import ( | ||||
| 	"crypto" | ||||
| 	"hash" | ||||
| 	"io" | ||||
| 	"strconv" | ||||
| 
 | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/errors" | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/internal/algorithm" | ||||
| ) | ||||
| 
 | ||||
| // Config collects configuration parameters for s2k key-stretching
 | ||||
| // transformations. A nil *Config is valid and results in all default
 | ||||
| // values. Currently, Config is used only by the Serialize function in
 | ||||
| // this package.
 | ||||
| type Config struct { | ||||
| 	// S2KMode is the mode of s2k function.
 | ||||
| 	// It can be 0 (simple), 1(salted), 3(iterated)
 | ||||
| 	// 2(reserved) 100-110(private/experimental).
 | ||||
| 	S2KMode uint8 | ||||
| 	// Hash is the default hash function to be used. If
 | ||||
| 	// nil, SHA256 is used.
 | ||||
| 	Hash crypto.Hash | ||||
| 	// S2KCount is only used for symmetric encryption. It
 | ||||
| 	// determines the strength of the passphrase stretching when
 | ||||
| 	// the said passphrase is hashed to produce a key. S2KCount
 | ||||
| 	// should be between 65536 and 65011712, inclusive. If Config
 | ||||
| 	// is nil or S2KCount is 0, the value 16777216 used. Not all
 | ||||
| 	// values in the above range can be represented. S2KCount will
 | ||||
| 	// be rounded up to the next representable value if it cannot
 | ||||
| 	// be encoded exactly. See RFC 4880 Section 3.7.1.3.
 | ||||
| 	S2KCount int | ||||
| } | ||||
| 
 | ||||
| // Params contains all the parameters of the s2k packet
 | ||||
| type Params struct { | ||||
| 	// mode is the mode of s2k function.
 | ||||
| 	// It can be 0 (simple), 1(salted), 3(iterated)
 | ||||
| 	// 2(reserved) 100-110(private/experimental).
 | ||||
| 	mode uint8 | ||||
| 	// hashId is the ID of the hash function used in any of the modes
 | ||||
| 	hashId byte | ||||
| 	// salt is a byte array to use as a salt in hashing process
 | ||||
| 	salt []byte | ||||
| 	// countByte is used to determine how many rounds of hashing are to
 | ||||
| 	// be performed in s2k mode 3. See RFC 4880 Section 3.7.1.3.
 | ||||
| 	countByte byte | ||||
| } | ||||
| 
 | ||||
| func (c *Config) hash() crypto.Hash { | ||||
| 	if c == nil || uint(c.Hash) == 0 { | ||||
| 		return crypto.SHA256 | ||||
| 	} | ||||
| 
 | ||||
| 	return c.Hash | ||||
| } | ||||
| 
 | ||||
| // EncodedCount get encoded count
 | ||||
| func (c *Config) EncodedCount() uint8 { | ||||
| 	if c == nil || c.S2KCount == 0 { | ||||
| 		return 224 // The common case. Corresponding to 16777216
 | ||||
| 	} | ||||
| 
 | ||||
| 	i := c.S2KCount | ||||
| 
 | ||||
| 	switch { | ||||
| 	case i < 65536: | ||||
| 		i = 65536 | ||||
| 	case i > 65011712: | ||||
| 		i = 65011712 | ||||
| 	} | ||||
| 
 | ||||
| 	return encodeCount(i) | ||||
| } | ||||
| 
 | ||||
| // encodeCount converts an iterative "count" in the range 1024 to
 | ||||
| // 65011712, inclusive, to an encoded count. The return value is the
 | ||||
| // octet that is actually stored in the GPG file. encodeCount panics
 | ||||
| // if i is not in the above range (encodedCount above takes care to
 | ||||
| // pass i in the correct range). See RFC 4880 Section 3.7.7.1.
 | ||||
| func encodeCount(i int) uint8 { | ||||
| 	if i < 65536 || i > 65011712 { | ||||
| 		panic("count arg i outside the required range") | ||||
| 	} | ||||
| 
 | ||||
| 	for encoded := 96; encoded < 256; encoded++ { | ||||
| 		count := decodeCount(uint8(encoded)) | ||||
| 		if count >= i { | ||||
| 			return uint8(encoded) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return 255 | ||||
| } | ||||
| 
 | ||||
| // decodeCount returns the s2k mode 3 iterative "count" corresponding to
 | ||||
| // the encoded octet c.
 | ||||
| func decodeCount(c uint8) int { | ||||
| 	return (16 + int(c&15)) << (uint32(c>>4) + 6) | ||||
| } | ||||
| 
 | ||||
| // Simple writes to out the result of computing the Simple S2K function (RFC
 | ||||
| // 4880, section 3.7.1.1) using the given hash and input passphrase.
 | ||||
| func Simple(out []byte, h hash.Hash, in []byte) { | ||||
| 	Salted(out, h, in, nil) | ||||
| } | ||||
| 
 | ||||
| var zero [1]byte | ||||
| 
 | ||||
| // Salted writes to out the result of computing the Salted S2K function (RFC
 | ||||
| // 4880, section 3.7.1.2) using the given hash, input passphrase and salt.
 | ||||
| func Salted(out []byte, h hash.Hash, in []byte, salt []byte) { | ||||
| 	done := 0 | ||||
| 	var digest []byte | ||||
| 
 | ||||
| 	for i := 0; done < len(out); i++ { | ||||
| 		h.Reset() | ||||
| 		for j := 0; j < i; j++ { | ||||
| 			h.Write(zero[:]) | ||||
| 		} | ||||
| 		h.Write(salt) | ||||
| 		h.Write(in) | ||||
| 		digest = h.Sum(digest[:0]) | ||||
| 		n := copy(out[done:], digest) | ||||
| 		done += n | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Iterated writes to out the result of computing the Iterated and Salted S2K
 | ||||
| // function (RFC 4880, section 3.7.1.3) using the given hash, input passphrase,
 | ||||
| // salt and iteration count.
 | ||||
| func Iterated(out []byte, h hash.Hash, in []byte, salt []byte, count int) { | ||||
| 	combined := make([]byte, len(in)+len(salt)) | ||||
| 	copy(combined, salt) | ||||
| 	copy(combined[len(salt):], in) | ||||
| 
 | ||||
| 	if count < len(combined) { | ||||
| 		count = len(combined) | ||||
| 	} | ||||
| 
 | ||||
| 	done := 0 | ||||
| 	var digest []byte | ||||
| 	for i := 0; done < len(out); i++ { | ||||
| 		h.Reset() | ||||
| 		for j := 0; j < i; j++ { | ||||
| 			h.Write(zero[:]) | ||||
| 		} | ||||
| 		written := 0 | ||||
| 		for written < count { | ||||
| 			if written+len(combined) > count { | ||||
| 				todo := count - written | ||||
| 				h.Write(combined[:todo]) | ||||
| 				written = count | ||||
| 			} else { | ||||
| 				h.Write(combined) | ||||
| 				written += len(combined) | ||||
| 			} | ||||
| 		} | ||||
| 		digest = h.Sum(digest[:0]) | ||||
| 		n := copy(out[done:], digest) | ||||
| 		done += n | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Generate generates valid parameters from given configuration.
 | ||||
| // It will enforce salted + hashed s2k method
 | ||||
| func Generate(rand io.Reader, c *Config) (*Params, error) { | ||||
| 	hashId, ok := HashToHashId(c.Hash) | ||||
| 	if !ok { | ||||
| 		return nil, errors.UnsupportedError("no such hash") | ||||
| 	} | ||||
| 
 | ||||
| 	params := &Params{ | ||||
| 		mode:      3, // Enforce iterared + salted method
 | ||||
| 		hashId:    hashId, | ||||
| 		salt:      make([]byte, 8), | ||||
| 		countByte: c.EncodedCount(), | ||||
| 	} | ||||
| 
 | ||||
| 	if _, err := io.ReadFull(rand, params.salt); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	return params, nil | ||||
| } | ||||
| 
 | ||||
| // Parse reads a binary specification for a string-to-key transformation from r
 | ||||
| // and returns a function which performs that transform. If the S2K is a special
 | ||||
| // GNU extension that indicates that the private key is missing, then the error
 | ||||
| // returned is errors.ErrDummyPrivateKey.
 | ||||
| func Parse(r io.Reader) (f func(out, in []byte), err error) { | ||||
| 	params, err := ParseIntoParams(r) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	return params.Function() | ||||
| } | ||||
| 
 | ||||
| // ParseIntoParams reads a binary specification for a string-to-key
 | ||||
| // transformation from r and returns a struct describing the s2k parameters.
 | ||||
| func ParseIntoParams(r io.Reader) (params *Params, err error) { | ||||
| 	var buf [9]byte | ||||
| 
 | ||||
| 	_, err = io.ReadFull(r, buf[:2]) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	params = &Params{ | ||||
| 		mode:   buf[0], | ||||
| 		hashId: buf[1], | ||||
| 	} | ||||
| 
 | ||||
| 	switch params.mode { | ||||
| 	case 0: | ||||
| 		return params, nil | ||||
| 	case 1: | ||||
| 		_, err = io.ReadFull(r, buf[:8]) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 
 | ||||
| 		params.salt = buf[:8] | ||||
| 		return params, nil | ||||
| 	case 3: | ||||
| 		_, err = io.ReadFull(r, buf[:9]) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 
 | ||||
| 		params.salt = buf[:8] | ||||
| 		params.countByte = buf[8] | ||||
| 		return params, nil | ||||
| 	case 101: | ||||
| 		// This is a GNU extension. See
 | ||||
| 		// https://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=blob;f=doc/DETAILS;h=fe55ae16ab4e26d8356dc574c9e8bc935e71aef1;hb=23191d7851eae2217ecdac6484349849a24fd94a#l1109
 | ||||
| 		if _, err = io.ReadFull(r, buf[:4]); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		if buf[0] == 'G' && buf[1] == 'N' && buf[2] == 'U' && buf[3] == 1 { | ||||
| 			return params, nil | ||||
| 		} | ||||
| 		return nil, errors.UnsupportedError("GNU S2K extension") | ||||
| 	} | ||||
| 
 | ||||
| 	return nil, errors.UnsupportedError("S2K function") | ||||
| } | ||||
| 
 | ||||
| func (params *Params) Dummy() bool { | ||||
| 	return params != nil && params.mode == 101 | ||||
| } | ||||
| 
 | ||||
| func (params *Params) Function() (f func(out, in []byte), err error) { | ||||
| 	if params.Dummy() { | ||||
| 		return nil, errors.ErrDummyPrivateKey("dummy key found") | ||||
| 	} | ||||
| 	hashObj, ok := HashIdToHash(params.hashId) | ||||
| 	if !ok { | ||||
| 		return nil, errors.UnsupportedError("hash for S2K function: " + strconv.Itoa(int(params.hashId))) | ||||
| 	} | ||||
| 	if !hashObj.Available() { | ||||
| 		return nil, errors.UnsupportedError("hash not available: " + strconv.Itoa(int(hashObj))) | ||||
| 	} | ||||
| 
 | ||||
| 	switch params.mode { | ||||
| 	case 0: | ||||
| 		f := func(out, in []byte) { | ||||
| 			Simple(out, hashObj.New(), in) | ||||
| 		} | ||||
| 
 | ||||
| 		return f, nil | ||||
| 	case 1: | ||||
| 		f := func(out, in []byte) { | ||||
| 			Salted(out, hashObj.New(), in, params.salt) | ||||
| 		} | ||||
| 
 | ||||
| 		return f, nil | ||||
| 	case 3: | ||||
| 		f := func(out, in []byte) { | ||||
| 			Iterated(out, hashObj.New(), in, params.salt, decodeCount(params.countByte)) | ||||
| 		} | ||||
| 
 | ||||
| 		return f, nil | ||||
| 	} | ||||
| 
 | ||||
| 	return nil, errors.UnsupportedError("S2K function") | ||||
| } | ||||
| 
 | ||||
| func (params *Params) Serialize(w io.Writer) (err error) { | ||||
| 	if _, err = w.Write([]byte{params.mode}); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	if _, err = w.Write([]byte{params.hashId}); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	if params.Dummy() { | ||||
| 		_, err = w.Write(append([]byte("GNU"), 1)) | ||||
| 		return | ||||
| 	} | ||||
| 	if params.mode > 0 { | ||||
| 		if _, err = w.Write(params.salt); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		if params.mode == 3 { | ||||
| 			_, err = w.Write([]byte{params.countByte}) | ||||
| 		} | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // Serialize salts and stretches the given passphrase and writes the
 | ||||
| // resulting key into key. It also serializes an S2K descriptor to
 | ||||
| // w. The key stretching can be configured with c, which may be
 | ||||
| // nil. In that case, sensible defaults will be used.
 | ||||
| func Serialize(w io.Writer, key []byte, rand io.Reader, passphrase []byte, c *Config) error { | ||||
| 	params, err := Generate(rand, c) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	err = params.Serialize(w) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	f, err := params.Function() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	f(key, passphrase) | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // 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 := algorithm.HashById[id]; ok { | ||||
| 		return hash.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 := algorithm.HashById[id]; ok { | ||||
| 		return hash.String(), true | ||||
| 	} | ||||
| 	return "", false | ||||
| } | ||||
| 
 | ||||
| // HashIdToHash returns an OpenPGP hash id which corresponds the given Hash.
 | ||||
| func HashToHashId(h crypto.Hash) (id byte, ok bool) { | ||||
| 	for id, hash := range algorithm.HashById { | ||||
| 		if hash.HashFunc() == h { | ||||
| 			return id, true | ||||
| 		} | ||||
| 	} | ||||
| 	return 0, false | ||||
| } | ||||
|  | @ -0,0 +1,568 @@ | |||
| // 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" | ||||
| 	"hash" | ||||
| 	"io" | ||||
| 	"strconv" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/armor" | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/errors" | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/packet" | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/s2k" | ||||
| ) | ||||
| 
 | ||||
| // DetachSign signs message with the private key from signer (which must
 | ||||
| // already have been decrypted) and writes the signature to w.
 | ||||
| // If config is nil, sensible defaults will be used.
 | ||||
| func DetachSign(w io.Writer, signer *Entity, message io.Reader, config *packet.Config) error { | ||||
| 	return detachSign(w, signer, message, packet.SigTypeBinary, config) | ||||
| } | ||||
| 
 | ||||
| // ArmoredDetachSign signs message with the private key from signer (which
 | ||||
| // must already have been decrypted) and writes an armored signature to w.
 | ||||
| // If config is nil, sensible defaults will be used.
 | ||||
| func ArmoredDetachSign(w io.Writer, signer *Entity, message io.Reader, config *packet.Config) (err error) { | ||||
| 	return armoredDetachSign(w, signer, message, packet.SigTypeBinary, config) | ||||
| } | ||||
| 
 | ||||
| // DetachSignText signs message (after canonicalising the line endings) with
 | ||||
| // the private key from signer (which must already have been decrypted) and
 | ||||
| // writes the signature to w.
 | ||||
| // If config is nil, sensible defaults will be used.
 | ||||
| func DetachSignText(w io.Writer, signer *Entity, message io.Reader, config *packet.Config) error { | ||||
| 	return detachSign(w, signer, message, packet.SigTypeText, config) | ||||
| } | ||||
| 
 | ||||
| // ArmoredDetachSignText signs message (after canonicalising the line endings)
 | ||||
| // with the private key from signer (which must already have been decrypted)
 | ||||
| // and writes an armored signature to w.
 | ||||
| // If config is nil, sensible defaults will be used.
 | ||||
| func ArmoredDetachSignText(w io.Writer, signer *Entity, message io.Reader, config *packet.Config) error { | ||||
| 	return armoredDetachSign(w, signer, message, packet.SigTypeText, config) | ||||
| } | ||||
| 
 | ||||
| func armoredDetachSign(w io.Writer, signer *Entity, message io.Reader, sigType packet.SignatureType, config *packet.Config) (err error) { | ||||
| 	out, err := armor.Encode(w, SignatureType, nil) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	err = detachSign(out, signer, message, sigType, config) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	return out.Close() | ||||
| } | ||||
| 
 | ||||
| func detachSign(w io.Writer, signer *Entity, message io.Reader, sigType packet.SignatureType, config *packet.Config) (err error) { | ||||
| 	signingKey, ok := signer.SigningKeyById(config.Now(), config.SigningKey()) | ||||
| 	if !ok { | ||||
| 		return errors.InvalidArgumentError("no valid signing keys") | ||||
| 	} | ||||
| 	if signingKey.PrivateKey == nil { | ||||
| 		return errors.InvalidArgumentError("signing key doesn't have a private key") | ||||
| 	} | ||||
| 	if signingKey.PrivateKey.Encrypted { | ||||
| 		return errors.InvalidArgumentError("signing key is encrypted") | ||||
| 	} | ||||
| 
 | ||||
| 	sig := new(packet.Signature) | ||||
| 	sig.SigType = sigType | ||||
| 	sig.PubKeyAlgo = signingKey.PrivateKey.PubKeyAlgo | ||||
| 	sig.Hash = config.Hash() | ||||
| 	sig.CreationTime = config.Now() | ||||
| 	sigLifetimeSecs := config.SigLifetime() | ||||
| 	sig.SigLifetimeSecs = &sigLifetimeSecs | ||||
| 	sig.IssuerKeyId = &signingKey.PrivateKey.KeyId | ||||
| 
 | ||||
| 	h, wrappedHash, err := hashForSignature(sig.Hash, sig.SigType) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	if _, err = io.Copy(wrappedHash, message); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	err = sig.Sign(h, signingKey.PrivateKey, config) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	return sig.Serialize(w) | ||||
| } | ||||
| 
 | ||||
| // FileHints contains metadata about encrypted files. This metadata is, itself,
 | ||||
| // encrypted.
 | ||||
| type FileHints struct { | ||||
| 	// IsBinary can be set to hint that the contents are binary data.
 | ||||
| 	IsBinary bool | ||||
| 	// FileName hints at the name of the file that should be written. It's
 | ||||
| 	// truncated to 255 bytes if longer. It may be empty to suggest that the
 | ||||
| 	// file should not be written to disk. It may be equal to "_CONSOLE" to
 | ||||
| 	// suggest the data should not be written to disk.
 | ||||
| 	FileName string | ||||
| 	// ModTime contains the modification time of the file, or the zero time if not applicable.
 | ||||
| 	ModTime time.Time | ||||
| } | ||||
| 
 | ||||
| // SymmetricallyEncrypt acts like gpg -c: it encrypts a file with a passphrase.
 | ||||
| // The resulting WriteCloser must be closed after the contents of the file have
 | ||||
| // been written.
 | ||||
| // If config is nil, sensible defaults will be used.
 | ||||
| func SymmetricallyEncrypt(ciphertext io.Writer, passphrase []byte, hints *FileHints, config *packet.Config) (plaintext io.WriteCloser, err error) { | ||||
| 	if hints == nil { | ||||
| 		hints = &FileHints{} | ||||
| 	} | ||||
| 
 | ||||
| 	key, err := packet.SerializeSymmetricKeyEncrypted(ciphertext, passphrase, config) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	var w io.WriteCloser | ||||
| 	if config.AEAD() != nil { | ||||
| 		w, err = packet.SerializeAEADEncrypted(ciphertext, key, config.Cipher(), config.AEAD().Mode(), config) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 	} else { | ||||
| 		w, err = packet.SerializeSymmetricallyEncrypted(ciphertext, config.Cipher(), key, config) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	literalData := w | ||||
| 	if algo := config.Compression(); algo != packet.CompressionNone { | ||||
| 		var compConfig *packet.CompressionConfig | ||||
| 		if config != nil { | ||||
| 			compConfig = config.CompressionConfig | ||||
| 		} | ||||
| 		literalData, err = packet.SerializeCompressed(w, algo, compConfig) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	var epochSeconds uint32 | ||||
| 	if !hints.ModTime.IsZero() { | ||||
| 		epochSeconds = uint32(hints.ModTime.Unix()) | ||||
| 	} | ||||
| 	return packet.SerializeLiteral(literalData, hints.IsBinary, hints.FileName, epochSeconds) | ||||
| } | ||||
| 
 | ||||
| // intersectPreferences mutates and returns a prefix of a that contains only
 | ||||
| // the values in the intersection of a and b. The order of a is preserved.
 | ||||
| func intersectPreferences(a []uint8, b []uint8) (intersection []uint8) { | ||||
| 	var j int | ||||
| 	for _, v := range a { | ||||
| 		for _, v2 := range b { | ||||
| 			if v == v2 { | ||||
| 				a[j] = v | ||||
| 				j++ | ||||
| 				break | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return a[:j] | ||||
| } | ||||
| 
 | ||||
| func hashToHashId(h crypto.Hash) uint8 { | ||||
| 	v, ok := s2k.HashToHashId(h) | ||||
| 	if !ok { | ||||
| 		panic("tried to convert unknown hash") | ||||
| 	} | ||||
| 	return v | ||||
| } | ||||
| 
 | ||||
| // EncryptText encrypts a message to a number of recipients and, optionally,
 | ||||
| // signs it. Optional information is contained in 'hints', also encrypted, that
 | ||||
| // aids the recipients in processing the message. The resulting WriteCloser
 | ||||
| // must be closed after the contents of the file have been written. If config
 | ||||
| // is nil, sensible defaults will be used. The signing is done in text mode.
 | ||||
| func EncryptText(ciphertext io.Writer, to []*Entity, signed *Entity, hints *FileHints, config *packet.Config) (plaintext io.WriteCloser, err error) { | ||||
| 	return encrypt(ciphertext, ciphertext, to, signed, hints, packet.SigTypeText, config) | ||||
| } | ||||
| 
 | ||||
| // Encrypt encrypts a message to a number of recipients and, optionally, signs
 | ||||
| // it. hints contains optional information, that is also encrypted, that aids
 | ||||
| // the recipients in processing the message. The resulting WriteCloser must
 | ||||
| // be closed after the contents of the file have been written.
 | ||||
| // If config is nil, sensible defaults will be used.
 | ||||
| func Encrypt(ciphertext io.Writer, to []*Entity, signed *Entity, hints *FileHints, config *packet.Config) (plaintext io.WriteCloser, err error) { | ||||
| 	return encrypt(ciphertext, ciphertext, to, signed, hints, packet.SigTypeBinary, config) | ||||
| } | ||||
| 
 | ||||
| // EncryptSplit encrypts a message to a number of recipients and, optionally, signs
 | ||||
| // it. hints contains optional information, that is also encrypted, that aids
 | ||||
| // the recipients in processing the message. The resulting WriteCloser must
 | ||||
| // be closed after the contents of the file have been written.
 | ||||
| // If config is nil, sensible defaults will be used.
 | ||||
| func EncryptSplit(keyWriter io.Writer, dataWriter io.Writer, to []*Entity, signed *Entity, hints *FileHints, config *packet.Config) (plaintext io.WriteCloser, err error) { | ||||
| 	return encrypt(keyWriter, dataWriter, to, signed, hints, packet.SigTypeBinary, config) | ||||
| } | ||||
| 
 | ||||
| // EncryptTextSplit encrypts a message to a number of recipients and, optionally, signs
 | ||||
| // it. hints contains optional information, that is also encrypted, that aids
 | ||||
| // the recipients in processing the message. The resulting WriteCloser must
 | ||||
| // be closed after the contents of the file have been written.
 | ||||
| // If config is nil, sensible defaults will be used.
 | ||||
| func EncryptTextSplit(keyWriter io.Writer, dataWriter io.Writer, to []*Entity, signed *Entity, hints *FileHints, config *packet.Config) (plaintext io.WriteCloser, err error) { | ||||
| 	return encrypt(keyWriter, dataWriter, to, signed, hints, packet.SigTypeText, config) | ||||
| } | ||||
| 
 | ||||
| // writeAndSign writes the data as a payload package and, optionally, signs
 | ||||
| // it. hints contains optional information, that is also encrypted,
 | ||||
| // that aids the recipients in processing the message. The resulting
 | ||||
| // WriteCloser must be closed after the contents of the file have been
 | ||||
| // written. If config is nil, sensible defaults will be used.
 | ||||
| func writeAndSign(payload io.WriteCloser, candidateHashes []uint8, signed *Entity, hints *FileHints, sigType packet.SignatureType, config *packet.Config) (plaintext io.WriteCloser, err error) { | ||||
| 	var signer *packet.PrivateKey | ||||
| 	if signed != nil { | ||||
| 		signKey, ok := signed.SigningKeyById(config.Now(), config.SigningKey()) | ||||
| 		if !ok { | ||||
| 			return nil, errors.InvalidArgumentError("no valid signing keys") | ||||
| 		} | ||||
| 		signer = signKey.PrivateKey | ||||
| 		if signer == nil { | ||||
| 			return nil, errors.InvalidArgumentError("no private key in signing key") | ||||
| 		} | ||||
| 		if signer.Encrypted { | ||||
| 			return nil, errors.InvalidArgumentError("signing key must be decrypted") | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	var hash crypto.Hash | ||||
| 	for _, hashId := range candidateHashes { | ||||
| 		if h, ok := s2k.HashIdToHash(hashId); ok && h.Available() { | ||||
| 			hash = h | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// If the hash specified by config is a candidate, we'll use that.
 | ||||
| 	if configuredHash := config.Hash(); configuredHash.Available() { | ||||
| 		for _, hashId := range candidateHashes { | ||||
| 			if h, ok := s2k.HashIdToHash(hashId); ok && h == configuredHash { | ||||
| 				hash = h | ||||
| 				break | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if hash == 0 { | ||||
| 		hashId := candidateHashes[0] | ||||
| 		name, ok := s2k.HashIdToString(hashId) | ||||
| 		if !ok { | ||||
| 			name = "#" + strconv.Itoa(int(hashId)) | ||||
| 		} | ||||
| 		return nil, errors.InvalidArgumentError("cannot encrypt because no candidate hash functions are compiled in. (Wanted " + name + " in this case.)") | ||||
| 	} | ||||
| 
 | ||||
| 	if signer != nil { | ||||
| 		ops := &packet.OnePassSignature{ | ||||
| 			SigType:    sigType, | ||||
| 			Hash:       hash, | ||||
| 			PubKeyAlgo: signer.PubKeyAlgo, | ||||
| 			KeyId:      signer.KeyId, | ||||
| 			IsLast:     true, | ||||
| 		} | ||||
| 		if err := ops.Serialize(payload); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if hints == nil { | ||||
| 		hints = &FileHints{} | ||||
| 	} | ||||
| 
 | ||||
| 	w := payload | ||||
| 	if signer != nil { | ||||
| 		// If we need to write a signature packet after the literal
 | ||||
| 		// data then we need to stop literalData from closing
 | ||||
| 		// encryptedData.
 | ||||
| 		w = noOpCloser{w} | ||||
| 
 | ||||
| 	} | ||||
| 	var epochSeconds uint32 | ||||
| 	if !hints.ModTime.IsZero() { | ||||
| 		epochSeconds = uint32(hints.ModTime.Unix()) | ||||
| 	} | ||||
| 	literalData, err := packet.SerializeLiteral(w, hints.IsBinary, hints.FileName, epochSeconds) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	if signer != nil { | ||||
| 		h, wrappedHash, err := hashForSignature(hash, sigType) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		metadata := &packet.LiteralData{ | ||||
| 			Format:   't', | ||||
| 			FileName: hints.FileName, | ||||
| 			Time:     epochSeconds, | ||||
| 		} | ||||
| 		if hints.IsBinary { | ||||
| 			metadata.Format = 'b' | ||||
| 		} | ||||
| 		return signatureWriter{payload, literalData, hash, wrappedHash, h, signer, sigType, config, metadata}, nil | ||||
| 	} | ||||
| 	return literalData, nil | ||||
| } | ||||
| 
 | ||||
| // encrypt encrypts a message to a number of recipients and, optionally, signs
 | ||||
| // it. hints contains optional information, that is also encrypted, that aids
 | ||||
| // the recipients in processing the message. The resulting WriteCloser must
 | ||||
| // be closed after the contents of the file have been written.
 | ||||
| // If config is nil, sensible defaults will be used.
 | ||||
| func encrypt(keyWriter io.Writer, dataWriter io.Writer, to []*Entity, signed *Entity, hints *FileHints, sigType packet.SignatureType, config *packet.Config) (plaintext io.WriteCloser, err error) { | ||||
| 	if len(to) == 0 { | ||||
| 		return nil, errors.InvalidArgumentError("no encryption recipient provided") | ||||
| 	} | ||||
| 
 | ||||
| 	// These are the possible ciphers that we'll use for the message.
 | ||||
| 	candidateCiphers := []uint8{ | ||||
| 		uint8(packet.CipherAES128), | ||||
| 		uint8(packet.CipherAES256), | ||||
| 		uint8(packet.CipherCAST5), | ||||
| 	} | ||||
| 	// These are the possible hash functions that we'll use for the signature.
 | ||||
| 	candidateHashes := []uint8{ | ||||
| 		hashToHashId(crypto.SHA256), | ||||
| 		hashToHashId(crypto.SHA384), | ||||
| 		hashToHashId(crypto.SHA512), | ||||
| 		hashToHashId(crypto.SHA1), | ||||
| 		hashToHashId(crypto.RIPEMD160), | ||||
| 	} | ||||
| 	candidateAeadModes := []uint8{ | ||||
| 		uint8(packet.AEADModeEAX), | ||||
| 		uint8(packet.AEADModeOCB), | ||||
| 		uint8(packet.AEADModeExperimentalGCM), | ||||
| 	} | ||||
| 	candidateCompression := []uint8{ | ||||
| 		uint8(packet.CompressionNone), | ||||
| 		uint8(packet.CompressionZIP), | ||||
| 		uint8(packet.CompressionZLIB), | ||||
| 	} | ||||
| 	// In the event that a recipient doesn't specify any supported ciphers
 | ||||
| 	// or hash functions, these are the ones that we assume that every
 | ||||
| 	// implementation supports.
 | ||||
| 	defaultCiphers := candidateCiphers[0:1] | ||||
| 	defaultHashes := candidateHashes[0:1] | ||||
| 	defaultAeadModes := candidateAeadModes[0:1] | ||||
| 	defaultCompression := candidateCompression[0:1] | ||||
| 
 | ||||
| 	encryptKeys := make([]Key, len(to)) | ||||
| 	// AEAD is used only if every key supports it.
 | ||||
| 	aeadSupported := true | ||||
| 
 | ||||
| 	for i := range to { | ||||
| 		var ok bool | ||||
| 		encryptKeys[i], ok = to[i].EncryptionKey(config.Now()) | ||||
| 		if !ok { | ||||
| 			return nil, errors.InvalidArgumentError("cannot encrypt a message to key id " + strconv.FormatUint(to[i].PrimaryKey.KeyId, 16) + " because it has no encryption keys") | ||||
| 		} | ||||
| 
 | ||||
| 		sig := to[i].PrimaryIdentity().SelfSignature | ||||
| 		if sig.AEAD == false { | ||||
| 			aeadSupported = false | ||||
| 		} | ||||
| 
 | ||||
| 		preferredSymmetric := sig.PreferredSymmetric | ||||
| 		if len(preferredSymmetric) == 0 { | ||||
| 			preferredSymmetric = defaultCiphers | ||||
| 		} | ||||
| 		preferredHashes := sig.PreferredHash | ||||
| 		if len(preferredHashes) == 0 { | ||||
| 			preferredHashes = defaultHashes | ||||
| 		} | ||||
| 		preferredAeadModes := sig.PreferredAEAD | ||||
| 		if len(preferredAeadModes) == 0 { | ||||
| 			preferredAeadModes = defaultAeadModes | ||||
| 		} | ||||
| 		preferredCompression := sig.PreferredCompression | ||||
| 		if len(preferredCompression) == 0 { | ||||
| 			preferredCompression = defaultCompression | ||||
| 		} | ||||
| 		candidateCiphers = intersectPreferences(candidateCiphers, preferredSymmetric) | ||||
| 		candidateHashes = intersectPreferences(candidateHashes, preferredHashes) | ||||
| 		candidateAeadModes = intersectPreferences(candidateAeadModes, preferredAeadModes) | ||||
| 		candidateCompression = intersectPreferences(candidateCompression, preferredCompression) | ||||
| 	} | ||||
| 
 | ||||
| 	if len(candidateCiphers) == 0 || len(candidateHashes) == 0 || len(candidateAeadModes) == 0 { | ||||
| 		return nil, errors.InvalidArgumentError("cannot encrypt because recipient set shares no common algorithms") | ||||
| 	} | ||||
| 
 | ||||
| 	cipher := packet.CipherFunction(candidateCiphers[0]) | ||||
| 	mode := packet.AEADMode(candidateAeadModes[0]) | ||||
| 	// If the cipher specified by config is a candidate, we'll use that.
 | ||||
| 	configuredCipher := config.Cipher() | ||||
| 	for _, c := range candidateCiphers { | ||||
| 		cipherFunc := packet.CipherFunction(c) | ||||
| 		if cipherFunc == configuredCipher { | ||||
| 			cipher = cipherFunc | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	symKey := make([]byte, cipher.KeySize()) | ||||
| 	if _, err := io.ReadFull(config.Random(), symKey); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	for _, key := range encryptKeys { | ||||
| 		if err := packet.SerializeEncryptedKey(keyWriter, key.PublicKey, cipher, symKey, config); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	var payload io.WriteCloser | ||||
| 	if aeadSupported { | ||||
| 		payload, err = packet.SerializeAEADEncrypted(dataWriter, symKey, cipher, mode, config) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 	} else { | ||||
| 		payload, err = packet.SerializeSymmetricallyEncrypted(dataWriter, cipher, symKey, config) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 	payload, err = handleCompression(payload, candidateCompression, config) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	return writeAndSign(payload, candidateHashes, signed, hints, sigType, config) | ||||
| } | ||||
| 
 | ||||
| // Sign signs a message. The resulting WriteCloser must be closed after the
 | ||||
| // contents of the file have been written.  hints contains optional information
 | ||||
| // that aids the recipients in processing the message.
 | ||||
| // If config is nil, sensible defaults will be used.
 | ||||
| func Sign(output io.Writer, signed *Entity, hints *FileHints, config *packet.Config) (input io.WriteCloser, err error) { | ||||
| 	if signed == nil { | ||||
| 		return nil, errors.InvalidArgumentError("no signer provided") | ||||
| 	} | ||||
| 
 | ||||
| 	// These are the possible hash functions that we'll use for the signature.
 | ||||
| 	candidateHashes := []uint8{ | ||||
| 		hashToHashId(crypto.SHA256), | ||||
| 		hashToHashId(crypto.SHA384), | ||||
| 		hashToHashId(crypto.SHA512), | ||||
| 		hashToHashId(crypto.SHA1), | ||||
| 		hashToHashId(crypto.RIPEMD160), | ||||
| 	} | ||||
| 	defaultHashes := candidateHashes[0:1] | ||||
| 	preferredHashes := signed.PrimaryIdentity().SelfSignature.PreferredHash | ||||
| 	if len(preferredHashes) == 0 { | ||||
| 		preferredHashes = defaultHashes | ||||
| 	} | ||||
| 	candidateHashes = intersectPreferences(candidateHashes, preferredHashes) | ||||
| 	if len(candidateHashes) == 0 { | ||||
| 		return nil, errors.InvalidArgumentError("cannot sign because signing key shares no common algorithms with candidate hashes") | ||||
| 	} | ||||
| 
 | ||||
| 	return writeAndSign(noOpCloser{output}, candidateHashes, signed, hints, packet.SigTypeBinary, config) | ||||
| } | ||||
| 
 | ||||
| // signatureWriter hashes the contents of a message while passing it along to
 | ||||
| // literalData. When closed, it closes literalData, writes a signature packet
 | ||||
| // to encryptedData and then also closes encryptedData.
 | ||||
| type signatureWriter struct { | ||||
| 	encryptedData io.WriteCloser | ||||
| 	literalData   io.WriteCloser | ||||
| 	hashType      crypto.Hash | ||||
| 	wrappedHash   hash.Hash | ||||
| 	h             hash.Hash | ||||
| 	signer        *packet.PrivateKey | ||||
| 	sigType       packet.SignatureType | ||||
| 	config        *packet.Config | ||||
| 	metadata      *packet.LiteralData // V5 signatures protect document metadata
 | ||||
| } | ||||
| 
 | ||||
| func (s signatureWriter) Write(data []byte) (int, error) { | ||||
| 	s.wrappedHash.Write(data) | ||||
| 	switch s.sigType { | ||||
| 	case packet.SigTypeBinary: | ||||
| 		return s.literalData.Write(data) | ||||
| 	case packet.SigTypeText: | ||||
| 		flag := 0 | ||||
| 		return writeCanonical(s.literalData, data, &flag) | ||||
| 	} | ||||
| 	return 0, errors.UnsupportedError("unsupported signature type: " + strconv.Itoa(int(s.sigType))) | ||||
| } | ||||
| 
 | ||||
| func (s signatureWriter) Close() error { | ||||
| 	sig := &packet.Signature{ | ||||
| 		Version:      s.signer.Version, | ||||
| 		SigType:      s.sigType, | ||||
| 		PubKeyAlgo:   s.signer.PubKeyAlgo, | ||||
| 		Hash:         s.hashType, | ||||
| 		CreationTime: s.config.Now(), | ||||
| 		IssuerKeyId:  &s.signer.KeyId, | ||||
| 		Metadata:     s.metadata, | ||||
| 	} | ||||
| 
 | ||||
| 	if err := sig.Sign(s.h, s.signer, s.config); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if err := s.literalData.Close(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if err := sig.Serialize(s.encryptedData); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return s.encryptedData.Close() | ||||
| } | ||||
| 
 | ||||
| // noOpCloser is like an ioutil.NopCloser, but for an io.Writer.
 | ||||
| // TODO: we have two of these in OpenPGP packages alone. This probably needs
 | ||||
| // to be promoted somewhere more common.
 | ||||
| type noOpCloser struct { | ||||
| 	w io.Writer | ||||
| } | ||||
| 
 | ||||
| func (c noOpCloser) Write(data []byte) (n int, err error) { | ||||
| 	return c.w.Write(data) | ||||
| } | ||||
| 
 | ||||
| func (c noOpCloser) Close() error { | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func handleCompression(compressed io.WriteCloser, candidateCompression []uint8, config *packet.Config) (data io.WriteCloser, err error) { | ||||
| 	data = compressed | ||||
| 	confAlgo := config.Compression() | ||||
| 	if confAlgo == packet.CompressionNone { | ||||
| 		return | ||||
| 	} | ||||
| 	finalAlgo := packet.CompressionNone | ||||
| 	// if compression specified by config available we will use it
 | ||||
| 	for _, c := range candidateCompression { | ||||
| 		if uint8(confAlgo) == c { | ||||
| 			finalAlgo = confAlgo | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if finalAlgo != packet.CompressionNone { | ||||
| 		var compConfig *packet.CompressionConfig | ||||
| 		if config != nil { | ||||
| 			compConfig = config.CompressionConfig | ||||
| 		} | ||||
| 		data, err = packet.SerializeCompressed(compressed, finalAlgo, compConfig) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 	return data, nil | ||||
| } | ||||
|  | @ -1,3 +1,6 @@ | |||
| arch: | ||||
|     - amd64 | ||||
|     - ppc64le | ||||
| language: go | ||||
| 
 | ||||
| go: | ||||
|  | @ -15,3 +18,27 @@ go: | |||
|     - 1.13.x | ||||
|     - tip | ||||
| 
 | ||||
| jobs: | ||||
|  exclude: | ||||
|     - arch: ppc64le | ||||
|       go: 1.2.x | ||||
|     - arch: ppc64le | ||||
|       go: 1.3.x | ||||
|     - arch: ppc64le | ||||
|       go: 1.4.x | ||||
|     - arch: ppc64le | ||||
|       go: 1.5.x | ||||
|     - arch: ppc64le | ||||
|       go: 1.6.x | ||||
|     - arch: ppc64le | ||||
|       go: 1.7.x | ||||
|     - arch: ppc64le | ||||
|       go: 1.8.x | ||||
|     - arch: ppc64le | ||||
|       go: 1.9.x | ||||
|     - arch: ppc64le | ||||
|       go: 1.10.x | ||||
|     - arch: ppc64le | ||||
|       go: 1.11.x | ||||
|     - arch: ppc64le | ||||
|       go: 1.12.x | ||||
|  |  | |||
|  | @ -37,6 +37,8 @@ Please note that because of the net/html dependency, goquery requires Go1.1+. | |||
| 
 | ||||
| **Note that goquery's API is now stable, and will not break.** | ||||
| 
 | ||||
| *    **2021-01-11 (v1.6.1)** : Fix panic when calling `{Prepend,Append,Set}Html` on a `Selection` that contains non-Element nodes. | ||||
| *    **2020-10-08 (v1.6.0)** : Parse html in context of the container node for all functions that deal with html strings (`AfterHtml`, `AppendHtml`, etc.). Thanks to [@thiemok][thiemok] and [@davidjwilkins][djw] for their work on this. | ||||
| *    **2020-02-04 (v1.5.1)** : Update module dependencies. | ||||
| *    **2018-11-15 (v1.5.0)** : Go module support (thanks @Zaba505). | ||||
| *    **2018-06-07 (v1.4.1)** : Add `NewDocumentFromReader` examples. | ||||
|  | @ -145,6 +147,8 @@ func main() { | |||
| - [tacusci/berrycms](https://github.com/tacusci/berrycms), a modern simple to use CMS with easy to write plugins | ||||
| - [Dataflow kit](https://github.com/slotix/dataflowkit), Web Scraping framework for Gophers. | ||||
| - [Geziyor](https://github.com/geziyor/geziyor), a fast web crawling & scraping framework for Go. Supports JS rendering. | ||||
| - [Pagser](https://github.com/foolin/pagser), a simple, easy, extensible, configurable HTML parser to struct based on goquery and struct tags. | ||||
| - [stitcherd](https://github.com/vhodges/stitcherd), A server for doing server side includes using css selectors and DOM updates. | ||||
| 
 | ||||
| ## Support | ||||
| 
 | ||||
|  | @ -181,3 +185,5 @@ The [BSD 3-Clause license][bsd], the same as the [Go language][golic]. Cascadia' | |||
| [thatguystone]: https://github.com/thatguystone | ||||
| [piotr]: https://github.com/piotrkowalczuk | ||||
| [goq]: https://github.com/andrewstuart/goq | ||||
| [thiemok]: https://github.com/thiemok | ||||
| [djw]: https://github.com/davidjwilkins | ||||
|  |  | |||
|  | @ -39,8 +39,15 @@ func (s *Selection) AfterSelection(sel *Selection) *Selection { | |||
| // AfterHtml parses the html and inserts it after the set of matched elements.
 | ||||
| //
 | ||||
| // This follows the same rules as Selection.Append.
 | ||||
| func (s *Selection) AfterHtml(html string) *Selection { | ||||
| 	return s.AfterNodes(parseHtml(html)...) | ||||
| func (s *Selection) AfterHtml(htmlStr string) *Selection { | ||||
| 	return s.eachNodeHtml(htmlStr, true, func(node *html.Node, nodes []*html.Node) { | ||||
| 		nextSibling := node.NextSibling | ||||
| 		for _, n := range nodes { | ||||
| 			if node.Parent != nil { | ||||
| 				node.Parent.InsertBefore(n, nextSibling) | ||||
| 			} | ||||
| 		} | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| // AfterNodes inserts the nodes after each element in the set of matched elements.
 | ||||
|  | @ -85,8 +92,12 @@ func (s *Selection) AppendSelection(sel *Selection) *Selection { | |||
| } | ||||
| 
 | ||||
| // AppendHtml parses the html and appends it to the set of matched elements.
 | ||||
| func (s *Selection) AppendHtml(html string) *Selection { | ||||
| 	return s.AppendNodes(parseHtml(html)...) | ||||
| func (s *Selection) AppendHtml(htmlStr string) *Selection { | ||||
| 	return s.eachNodeHtml(htmlStr, false, func(node *html.Node, nodes []*html.Node) { | ||||
| 		for _, n := range nodes { | ||||
| 			node.AppendChild(n) | ||||
| 		} | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| // AppendNodes appends the specified nodes to each node in the set of matched elements.
 | ||||
|  | @ -123,8 +134,14 @@ func (s *Selection) BeforeSelection(sel *Selection) *Selection { | |||
| // BeforeHtml parses the html and inserts it before the set of matched elements.
 | ||||
| //
 | ||||
| // This follows the same rules as Selection.Append.
 | ||||
| func (s *Selection) BeforeHtml(html string) *Selection { | ||||
| 	return s.BeforeNodes(parseHtml(html)...) | ||||
| func (s *Selection) BeforeHtml(htmlStr string) *Selection { | ||||
| 	return s.eachNodeHtml(htmlStr, true, func(node *html.Node, nodes []*html.Node) { | ||||
| 		for _, n := range nodes { | ||||
| 			if node.Parent != nil { | ||||
| 				node.Parent.InsertBefore(n, node) | ||||
| 			} | ||||
| 		} | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| // BeforeNodes inserts the nodes before each element in the set of matched elements.
 | ||||
|  | @ -184,8 +201,13 @@ func (s *Selection) PrependSelection(sel *Selection) *Selection { | |||
| } | ||||
| 
 | ||||
| // PrependHtml parses the html and prepends it to the set of matched elements.
 | ||||
| func (s *Selection) PrependHtml(html string) *Selection { | ||||
| 	return s.PrependNodes(parseHtml(html)...) | ||||
| func (s *Selection) PrependHtml(htmlStr string) *Selection { | ||||
| 	return s.eachNodeHtml(htmlStr, false, func(node *html.Node, nodes []*html.Node) { | ||||
| 		firstChild := node.FirstChild | ||||
| 		for _, n := range nodes { | ||||
| 			node.InsertBefore(n, firstChild) | ||||
| 		} | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| // PrependNodes prepends the specified nodes to each node in the set of
 | ||||
|  | @ -212,14 +234,19 @@ func (s *Selection) Remove() *Selection { | |||
| 	return s | ||||
| } | ||||
| 
 | ||||
| // RemoveFiltered removes the set of matched elements by selector.
 | ||||
| // It returns the Selection of removed nodes.
 | ||||
| // RemoveFiltered removes from the current set of matched elements those that
 | ||||
| // match the selector filter. It returns the Selection of removed nodes.
 | ||||
| //
 | ||||
| // For example if the selection s contains "<h1>", "<h2>" and "<h3>"
 | ||||
| // and s.RemoveFiltered("h2") is called, only the "<h2>" node is removed
 | ||||
| // (and returned), while "<h1>" and "<h3>" are kept in the document.
 | ||||
| func (s *Selection) RemoveFiltered(selector string) *Selection { | ||||
| 	return s.RemoveMatcher(compileMatcher(selector)) | ||||
| } | ||||
| 
 | ||||
| // RemoveMatcher removes the set of matched elements.
 | ||||
| // It returns the Selection of removed nodes.
 | ||||
| // RemoveMatcher removes from the current set of matched elements those that
 | ||||
| // match the Matcher filter. It returns the Selection of removed nodes.
 | ||||
| // See RemoveFiltered for additional information.
 | ||||
| func (s *Selection) RemoveMatcher(m Matcher) *Selection { | ||||
| 	return s.FilterMatcher(m).Remove() | ||||
| } | ||||
|  | @ -256,8 +283,16 @@ func (s *Selection) ReplaceWithSelection(sel *Selection) *Selection { | |||
| // It returns the removed elements.
 | ||||
| //
 | ||||
| // This follows the same rules as Selection.Append.
 | ||||
| func (s *Selection) ReplaceWithHtml(html string) *Selection { | ||||
| 	return s.ReplaceWithNodes(parseHtml(html)...) | ||||
| func (s *Selection) ReplaceWithHtml(htmlStr string) *Selection { | ||||
| 	s.eachNodeHtml(htmlStr, true, func(node *html.Node, nodes []*html.Node) { | ||||
| 		nextSibling := node.NextSibling | ||||
| 		for _, n := range nodes { | ||||
| 			if node.Parent != nil { | ||||
| 				node.Parent.InsertBefore(n, nextSibling) | ||||
| 			} | ||||
| 		} | ||||
| 	}) | ||||
| 	return s.Remove() | ||||
| } | ||||
| 
 | ||||
| // ReplaceWithNodes replaces each element in the set of matched elements with
 | ||||
|  | @ -272,8 +307,17 @@ func (s *Selection) ReplaceWithNodes(ns ...*html.Node) *Selection { | |||
| 
 | ||||
| // SetHtml sets the html content of each element in the selection to
 | ||||
| // specified html string.
 | ||||
| func (s *Selection) SetHtml(html string) *Selection { | ||||
| 	return setHtmlNodes(s, parseHtml(html)...) | ||||
| func (s *Selection) SetHtml(htmlStr string) *Selection { | ||||
| 	for _, context := range s.Nodes { | ||||
| 		for c := context.FirstChild; c != nil; c = context.FirstChild { | ||||
| 			context.RemoveChild(c) | ||||
| 		} | ||||
| 	} | ||||
| 	return s.eachNodeHtml(htmlStr, false, func(node *html.Node, nodes []*html.Node) { | ||||
| 		for _, n := range nodes { | ||||
| 			node.AppendChild(n) | ||||
| 		} | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| // SetText sets the content of each element in the selection to specified content.
 | ||||
|  | @ -329,8 +373,23 @@ func (s *Selection) WrapSelection(sel *Selection) *Selection { | |||
| // most child of the given HTML.
 | ||||
| //
 | ||||
| // It returns the original set of elements.
 | ||||
| func (s *Selection) WrapHtml(html string) *Selection { | ||||
| 	return s.wrapNodes(parseHtml(html)...) | ||||
| func (s *Selection) WrapHtml(htmlStr string) *Selection { | ||||
| 	nodesMap := make(map[string][]*html.Node) | ||||
| 	for _, context := range s.Nodes { | ||||
| 		var parent *html.Node | ||||
| 		if context.Parent != nil { | ||||
| 			parent = context.Parent | ||||
| 		} else { | ||||
| 			parent = &html.Node{Type: html.ElementNode} | ||||
| 		} | ||||
| 		nodes, found := nodesMap[nodeName(parent)] | ||||
| 		if !found { | ||||
| 			nodes = parseHtmlWithContext(htmlStr, parent) | ||||
| 			nodesMap[nodeName(parent)] = nodes | ||||
| 		} | ||||
| 		newSingleSelection(context, s.document).wrapAllNodes(cloneNodes(nodes)...) | ||||
| 	} | ||||
| 	return s | ||||
| } | ||||
| 
 | ||||
| // WrapNode wraps each element in the set of matched elements inside the inner-
 | ||||
|  | @ -382,8 +441,18 @@ func (s *Selection) WrapAllSelection(sel *Selection) *Selection { | |||
| // document.
 | ||||
| //
 | ||||
| // It returns the original set of elements.
 | ||||
| func (s *Selection) WrapAllHtml(html string) *Selection { | ||||
| 	return s.wrapAllNodes(parseHtml(html)...) | ||||
| func (s *Selection) WrapAllHtml(htmlStr string) *Selection { | ||||
| 	var context *html.Node | ||||
| 	var nodes []*html.Node | ||||
| 	if len(s.Nodes) > 0 { | ||||
| 		context = s.Nodes[0] | ||||
| 		if context.Parent != nil { | ||||
| 			nodes = parseHtmlWithContext(htmlStr, context) | ||||
| 		} else { | ||||
| 			nodes = parseHtml(htmlStr) | ||||
| 		} | ||||
| 	} | ||||
| 	return s.wrapAllNodes(nodes...) | ||||
| } | ||||
| 
 | ||||
| func (s *Selection) wrapAllNodes(ns ...*html.Node) *Selection { | ||||
|  | @ -452,8 +521,17 @@ func (s *Selection) WrapInnerSelection(sel *Selection) *Selection { | |||
| // cloned before being inserted into the document.
 | ||||
| //
 | ||||
| // It returns the original set of elements.
 | ||||
| func (s *Selection) WrapInnerHtml(html string) *Selection { | ||||
| 	return s.wrapInnerNodes(parseHtml(html)...) | ||||
| func (s *Selection) WrapInnerHtml(htmlStr string) *Selection { | ||||
| 	nodesMap := make(map[string][]*html.Node) | ||||
| 	for _, context := range s.Nodes { | ||||
| 		nodes, found := nodesMap[nodeName(context)] | ||||
| 		if !found { | ||||
| 			nodes = parseHtmlWithContext(htmlStr, context) | ||||
| 			nodesMap[nodeName(context)] = nodes | ||||
| 		} | ||||
| 		newSingleSelection(context, s.document).wrapInnerNodes(cloneNodes(nodes)...) | ||||
| 	} | ||||
| 	return s | ||||
| } | ||||
| 
 | ||||
| // WrapInnerNode wraps an HTML structure, matched by the given selector, around
 | ||||
|  | @ -493,16 +571,14 @@ func parseHtml(h string) []*html.Node { | |||
| 	return nodes | ||||
| } | ||||
| 
 | ||||
| func setHtmlNodes(s *Selection, ns ...*html.Node) *Selection { | ||||
| 	for _, n := range s.Nodes { | ||||
| 		for c := n.FirstChild; c != nil; c = n.FirstChild { | ||||
| 			n.RemoveChild(c) | ||||
| func parseHtmlWithContext(h string, context *html.Node) []*html.Node { | ||||
| 	// Errors are only returned when the io.Reader returns any error besides
 | ||||
| 	// EOF, but strings.Reader never will
 | ||||
| 	nodes, err := html.ParseFragment(strings.NewReader(h), context) | ||||
| 	if err != nil { | ||||
| 		panic("goquery: failed to parse HTML: " + err.Error()) | ||||
| 	} | ||||
| 		for _, c := range ns { | ||||
| 			n.AppendChild(cloneNode(c)) | ||||
| 		} | ||||
| 	} | ||||
| 	return s | ||||
| 	return nodes | ||||
| } | ||||
| 
 | ||||
| // Get the first child that is an ElementNode
 | ||||
|  | @ -572,3 +648,32 @@ func (s *Selection) manipulateNodes(ns []*html.Node, reverse bool, | |||
| 
 | ||||
| 	return s | ||||
| } | ||||
| 
 | ||||
| // eachNodeHtml parses the given html string and inserts the resulting nodes in the dom with the mergeFn.
 | ||||
| // The parsed nodes are inserted for each element of the selection.
 | ||||
| // isParent can be used to indicate that the elements of the selection should be treated as the parent for the parsed html.
 | ||||
| // A cache is used to avoid parsing the html multiple times should the elements of the selection result in the same context.
 | ||||
| func (s *Selection) eachNodeHtml(htmlStr string, isParent bool, mergeFn func(n *html.Node, nodes []*html.Node)) *Selection { | ||||
| 	// cache to avoid parsing the html for the same context multiple times
 | ||||
| 	nodeCache := make(map[string][]*html.Node) | ||||
| 	var context *html.Node | ||||
| 	for _, n := range s.Nodes { | ||||
| 		if isParent { | ||||
| 			context = n.Parent | ||||
| 		} else { | ||||
| 			if n.Type != html.ElementNode { | ||||
| 				continue | ||||
| 			} | ||||
| 			context = n | ||||
| 		} | ||||
| 		if context != nil { | ||||
| 			nodes, found := nodeCache[nodeName(context)] | ||||
| 			if !found { | ||||
| 				nodes = parseHtmlWithContext(htmlStr, context) | ||||
| 				nodeCache[nodeName(context)] = nodes | ||||
| 			} | ||||
| 			mergeFn(n, cloneNodes(nodes)) | ||||
| 		} | ||||
| 	} | ||||
| 	return s | ||||
| } | ||||
|  |  | |||
|  | @ -36,12 +36,22 @@ func NodeName(s *Selection) string { | |||
| 	if s.Length() == 0 { | ||||
| 		return "" | ||||
| 	} | ||||
| 	switch n := s.Get(0); n.Type { | ||||
| 	return nodeName(s.Get(0)) | ||||
| } | ||||
| 
 | ||||
| // nodeName returns the node name of the given html node.
 | ||||
| // See NodeName for additional details on behaviour.
 | ||||
| func nodeName(node *html.Node) string { | ||||
| 	if node == nil { | ||||
| 		return "" | ||||
| 	} | ||||
| 
 | ||||
| 	switch node.Type { | ||||
| 	case html.ElementNode, html.DoctypeNode: | ||||
| 		return n.Data | ||||
| 		return node.Data | ||||
| 	default: | ||||
| 		if n.Type >= 0 && int(n.Type) < len(nodeNames) { | ||||
| 			return nodeNames[n.Type] | ||||
| 		if node.Type >= 0 && int(node.Type) < len(nodeNames) { | ||||
| 			return nodeNames[node.Type] | ||||
| 		} | ||||
| 		return "" | ||||
| 	} | ||||
|  |  | |||
|  | @ -64,7 +64,7 @@ qa: fmtcheck test vet lint | |||
| # Get the dependencies
 | ||||
| deps: | ||||
| 	GOPATH=$(GOPATH) go get github.com/stretchr/testify | ||||
| 	GOPATH=$(GOPATH) go get github.com/willf/bitset | ||||
| 	GOPATH=$(GOPATH) go get github.com/bits-and-blooms/bitset | ||||
| 	GOPATH=$(GOPATH) go get github.com/golang/lint/golint | ||||
| 	GOPATH=$(GOPATH) go get github.com/mschoch/smat | ||||
| 	GOPATH=$(GOPATH) go get github.com/dvyukov/go-fuzz/go-fuzz | ||||
|  |  | |||
|  | @ -1,4 +1,4 @@ | |||
| roaring [](https://travis-ci.org/RoaringBitmap/roaring) [](https://godoc.org/github.com/RoaringBitmap/roaring) [](https://godoc.org/github.com/RoaringBitmap/roaring/roaring64) [](https://goreportcard.com/report/github.com/RoaringBitmap/roaring) | ||||
| roaring [](https://travis-ci.org/RoaringBitmap/roaring) [](https://godoc.org/github.com/RoaringBitmap/roaring/roaring64) [](https://goreportcard.com/report/github.com/RoaringBitmap/roaring) | ||||
| [](https://cloud.drone.io/RoaringBitmap/roaring) | ||||
|  | ||||
|  | ||||
|  | @ -84,7 +84,7 @@ When the bitset approach is applicable, it can be orders of | |||
| magnitude faster than other possible implementation of a set (e.g., as a hash set) | ||||
| while using several times less memory. | ||||
| 
 | ||||
| However, a bitset, even a compressed one is not always applicable. For example, if the | ||||
| However, a bitset, even a compressed one is not always applicable. For example, if | ||||
| you have 1000 random-looking integers, then a simple array might be the best representation. | ||||
| We refer to this case as the "sparse" scenario. | ||||
| 
 | ||||
|  | @ -158,7 +158,7 @@ http://arxiv.org/abs/1402.6407 This paper used data from http://lemire.me/data/r | |||
| Dependencies are fetched automatically by giving the `-t` flag to `go get`. | ||||
| 
 | ||||
| they include | ||||
|   - github.com/willf/bitset | ||||
|   - github.com/bits-and-blooms/bitset | ||||
|   - github.com/mschoch/smat | ||||
|   - github.com/glycerine/go-unsnap-stream | ||||
|   - github.com/philhofer/fwd | ||||
|  | @ -384,12 +384,14 @@ You can help us test further the library with fuzzy testing: | |||
|          go get github.com/dvyukov/go-fuzz/go-fuzz-build | ||||
|          go test -tags=gofuzz -run=TestGenerateSmatCorpus | ||||
|          go-fuzz-build github.com/RoaringBitmap/roaring | ||||
|          go-fuzz -bin=./roaring-fuzz.zip -workdir=workdir/ -timeout=200 | ||||
|          go-fuzz -bin=./roaring-fuzz.zip -workdir=workdir/ -timeout=200 -func FuzzSmat | ||||
| 
 | ||||
| Let it run, and if the # of crashers is > 0, check out the reports in | ||||
| the workdir where you should be able to find the panic goroutine stack | ||||
| traces. | ||||
| 
 | ||||
| You may also replace `-func FuzzSmat`  by `-func FuzzSerializationBuffer` or `-func FuzzSerializationStream`. | ||||
| 
 | ||||
| ### Alternative in Go | ||||
| 
 | ||||
| There is a Go version wrapping the C/C++ implementation https://github.com/RoaringBitmap/gocroaring | ||||
|  |  | |||
|  | @ -16,10 +16,11 @@ func (ac *arrayContainer) String() string { | |||
| 	return s + "}" | ||||
| } | ||||
| 
 | ||||
| func (ac *arrayContainer) fillLeastSignificant16bits(x []uint32, i int, mask uint32) { | ||||
| func (ac *arrayContainer) fillLeastSignificant16bits(x []uint32, i int, mask uint32) int { | ||||
| 	for k := 0; k < len(ac.content); k++ { | ||||
| 		x[k+i] = uint32(ac.content[k]) | mask | ||||
| 	} | ||||
| 	return i + len(ac.content) | ||||
| } | ||||
| 
 | ||||
| func (ac *arrayContainer) iterate(cb func(x uint16) bool) bool { | ||||
|  | @ -394,11 +395,19 @@ func (ac *arrayContainer) iorBitmap(bc2 *bitmapContainer) container { | |||
| } | ||||
| 
 | ||||
| func (ac *arrayContainer) iorRun16(rc *runContainer16) container { | ||||
| 	bc1 := ac.toBitmapContainer() | ||||
| 	bc2 := rc.toBitmapContainer() | ||||
| 	bc1.iorBitmap(bc2) | ||||
| 	*ac = *newArrayContainerFromBitmap(bc1) | ||||
| 	return ac | ||||
| 	runCardinality := rc.getCardinality() | ||||
| 	// heuristic for if the container should maybe be an
 | ||||
| 	// array container.
 | ||||
| 	if runCardinality < ac.getCardinality() && | ||||
| 		runCardinality+ac.getCardinality() < arrayDefaultMaxSize { | ||||
| 		var result container | ||||
| 		result = ac | ||||
| 		for _, run := range rc.iv { | ||||
| 			result = result.iaddRange(int(run.start), int(run.start)+int(run.length)) | ||||
| 		} | ||||
| 		return result | ||||
| 	} | ||||
| 	return rc.orArray(ac) | ||||
| } | ||||
| 
 | ||||
| func (ac *arrayContainer) lazyIOR(a container) container { | ||||
|  | @ -843,6 +852,10 @@ func (ac *arrayContainer) getCardinality() int { | |||
| 	return len(ac.content) | ||||
| } | ||||
| 
 | ||||
| func (ac *arrayContainer) isEmpty() bool { | ||||
| 	return len(ac.content) == 0 | ||||
| } | ||||
| 
 | ||||
| func (ac *arrayContainer) rank(x uint16) int { | ||||
| 	answer := binarySearch(ac.content, x) | ||||
| 	if answer >= 0 { | ||||
|  | @ -882,7 +895,7 @@ func (ac *arrayContainer) resetTo(a container) { | |||
| 		x.fillArray(ac.content) | ||||
| 
 | ||||
| 	case *runContainer16: | ||||
| 		card := int(x.cardinality()) | ||||
| 		card := int(x.getCardinality()) | ||||
| 		ac.realloc(card) | ||||
| 		cur := 0 | ||||
| 		for _, r := range x.iv { | ||||
|  | @ -956,10 +969,10 @@ func (ac *arrayContainer) numberOfRuns() (nr int) { | |||
| 				runlen++ | ||||
| 			} else { | ||||
| 				if cur < prev { | ||||
| 					panic("then fundamental arrayContainer assumption of sorted ac.content was broken") | ||||
| 					panic("the fundamental arrayContainer assumption of sorted ac.content was broken") | ||||
| 				} | ||||
| 				if cur == prev { | ||||
| 					panic("then fundamental arrayContainer assumption of deduplicated content was broken") | ||||
| 					panic("the fundamental arrayContainer assumption of deduplicated content was broken") | ||||
| 				} else { | ||||
| 					nr++ | ||||
| 					runlen = 0 | ||||
|  |  | |||
|  | @ -264,7 +264,7 @@ func bitmapEquals(a, b []uint64) bool { | |||
| 	return true | ||||
| } | ||||
| 
 | ||||
| func (bc *bitmapContainer) fillLeastSignificant16bits(x []uint32, i int, mask uint32) { | ||||
| func (bc *bitmapContainer) fillLeastSignificant16bits(x []uint32, i int, mask uint32) int { | ||||
| 	// TODO: should be written as optimized assembly
 | ||||
| 	pos := i | ||||
| 	base := mask | ||||
|  | @ -278,6 +278,7 @@ func (bc *bitmapContainer) fillLeastSignificant16bits(x []uint32, i int, mask ui | |||
| 		} | ||||
| 		base += 64 | ||||
| 	} | ||||
| 	return pos | ||||
| } | ||||
| 
 | ||||
| func (bc *bitmapContainer) equals(o container) bool { | ||||
|  | @ -349,6 +350,11 @@ func (bc *bitmapContainer) getCardinality() int { | |||
| 	return bc.cardinality | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| func (bc *bitmapContainer) isEmpty() bool { | ||||
| 	return bc.cardinality == 0 | ||||
| } | ||||
| 
 | ||||
| func (bc *bitmapContainer) clone() container { | ||||
| 	ptr := bitmapContainer{bc.cardinality, make([]uint64, len(bc.bitmap))} | ||||
| 	copy(ptr.bitmap, bc.bitmap[:]) | ||||
|  | @ -1132,16 +1138,12 @@ func (bc *bitmapContainer) addOffset(x uint16) []container { | |||
| 		low.bitmap[b] = bc.bitmap[0] << i | ||||
| 		for k := uint32(1); k < end; k++ { | ||||
| 			newval := bc.bitmap[k] << i | ||||
| 			if newval == 0 { | ||||
| 				newval = bc.bitmap[k-1] >> (64 - i) | ||||
| 			} | ||||
| 			newval |= bc.bitmap[k-1] >> (64 - i) | ||||
| 			low.bitmap[b+k] = newval | ||||
| 		} | ||||
| 		for k := end; k < 1024; k++ { | ||||
| 			newval := bc.bitmap[k] << i | ||||
| 			if newval == 0 { | ||||
| 				newval = bc.bitmap[k-1] >> (64 - i) | ||||
| 			} | ||||
| 			newval |= bc.bitmap[k-1] >> (64 - i) | ||||
| 			high.bitmap[k-end] = newval | ||||
| 		} | ||||
| 		high.bitmap[b] = bc.bitmap[1023] >> (64 - i) | ||||
|  |  | |||
|  | @ -301,9 +301,6 @@ func (x1 *Bitmap) AndAny(bitmaps ...*Bitmap) { | |||
| 					tmpBitmap = newBitmapContainer() | ||||
| 				} | ||||
| 				tmpBitmap.resetTo(keyContainers[0]) | ||||
| 				for _, c := range keyContainers[1:] { | ||||
| 					tmpBitmap.ior(c) | ||||
| 				} | ||||
| 				ored = tmpBitmap | ||||
| 			} else { | ||||
| 				if tmpArray == nil { | ||||
|  | @ -311,15 +308,15 @@ func (x1 *Bitmap) AndAny(bitmaps ...*Bitmap) { | |||
| 				} | ||||
| 				tmpArray.realloc(maxPossibleOr) | ||||
| 				tmpArray.resetTo(keyContainers[0]) | ||||
| 				for _, c := range keyContainers[1:] { | ||||
| 					tmpArray.ior(c) | ||||
| 				} | ||||
| 				ored = tmpArray | ||||
| 			} | ||||
| 			for _, c := range keyContainers[1:] { | ||||
| 				ored = ored.ior(c) | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		result := x1.highlowcontainer.getWritableContainerAtIndex(basePos).iand(ored) | ||||
| 		if result.getCardinality() > 0 { | ||||
| 		if !result.isEmpty() { | ||||
| 			x1.highlowcontainer.replaceKeyAndContainerAtIndex(intersections, baseKey, result, false) | ||||
| 			intersections++ | ||||
| 		} | ||||
|  |  | |||
|  | @ -3,15 +3,18 @@ module github.com/RoaringBitmap/roaring | |||
| go 1.14 | ||||
| 
 | ||||
| require ( | ||||
| 	github.com/bits-and-blooms/bitset v1.2.0 | ||||
| 	github.com/dvyukov/go-fuzz v0.0.0-20210429054444-fca39067bc72 // indirect | ||||
| 	github.com/elazarl/go-bindata-assetfs v1.0.1 // indirect | ||||
| 	github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2 | ||||
| 	github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31 // indirect | ||||
| 	github.com/golang/snappy v0.0.1 // indirect | ||||
| 	github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99 // indirect | ||||
| 	github.com/jtolds/gls v4.20.0+incompatible // indirect | ||||
| 	github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae | ||||
| 	github.com/mschoch/smat v0.2.0 | ||||
| 	github.com/philhofer/fwd v1.0.0 // indirect | ||||
| 	github.com/stephens2424/writerset v1.0.2 // indirect | ||||
| 	github.com/stretchr/testify v1.4.0 | ||||
| 	github.com/willf/bitset v1.1.10 | ||||
| 	golang.org/x/lint v0.0.0-20200302205851-738671d3881b // indirect | ||||
| 	golang.org/x/tools v0.0.0-20200928182047-19e03678916f // indirect | ||||
| ) | ||||
|  |  | |||
|  | @ -1,5 +1,12 @@ | |||
| github.com/Julusian/godocdown v0.0.0-20170816220326-6d19f8ff2df8/go.mod h1:INZr5t32rG59/5xeltqoCJoNY7e5x/3xoY9WSWVWg74= | ||||
| github.com/bits-and-blooms/bitset v1.2.0 h1:Kn4yilvwNtMACtf1eYDlG8H77R07mZSPbMjLyS07ChA= | ||||
| github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= | ||||
| 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/dvyukov/go-fuzz v0.0.0-20210429054444-fca39067bc72 h1:XiR1YwcWcRFzxjAhWK29HQL4nocj0QWJjpeRi/YASV0= | ||||
| github.com/dvyukov/go-fuzz v0.0.0-20210429054444-fca39067bc72/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw= | ||||
| github.com/elazarl/go-bindata-assetfs v1.0.1 h1:m0kkaHRKEu7tUIUFVwhGGGYClXvyl4RE03qmvRTNfbw= | ||||
| github.com/elazarl/go-bindata-assetfs v1.0.1/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4= | ||||
| github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2 h1:Ujru1hufTHVb++eG6OuNDKMxZnGIvF6o/u8q/8h2+I4= | ||||
| github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= | ||||
| github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31 h1:gclg6gY70GLy3PbkQ1AERPfmLMMagS60DKF78eWwLn8= | ||||
|  | @ -12,16 +19,20 @@ github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7 | |||
| github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= | ||||
| github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae h1:VeRdUYdCw49yizlSbMEn2SZ+gT+3IUKx8BqxyQdz+BY= | ||||
| github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg= | ||||
| github.com/mschoch/smat v0.2.0 h1:8imxQsjDm8yFEAVBe7azKmKSgzSkZXDuKkSq9374khM= | ||||
| github.com/mschoch/smat v0.2.0/go.mod h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOlotKw= | ||||
| 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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||||
| github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||||
| github.com/robertkrimen/godocdown v0.0.0-20130622164427-0bfa04905481/go.mod h1:C9WhFzY47SzYBIvzFqSvHIR6ROgDo4TtdTuRaOMjF/s= | ||||
| github.com/stephens2424/writerset v1.0.2 h1:znRLgU6g8RS5euYRcy004XeE4W+Tu44kALzy7ghPif8= | ||||
| github.com/stephens2424/writerset v1.0.2/go.mod h1:aS2JhsMn6eA7e82oNmW4rfsgAOp9COBTTl8mzkwADnc= | ||||
| github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= | ||||
| 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/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= | ||||
| github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= | ||||
| github.com/willf/bitset v1.1.10 h1:NotGKqX0KwQ72NUzqrjZq5ipPNDQex9lo3WpaS8L2sc= | ||||
| github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= | ||||
| github.com/yuin/goldmark v1.2.1/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= | ||||
|  | @ -29,6 +40,7 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh | |||
| golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= | ||||
| golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= | ||||
| golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= | ||||
| 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/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= | ||||
|  | @ -46,6 +58,7 @@ golang.org/x/tools v0.0.0-20200928182047-19e03678916f h1:VwGa2Wf+rHGIxvsssCkUNIy | |||
| golang.org/x/tools v0.0.0-20200928182047-19e03678916f/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= | ||||
| 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-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= | ||||
| golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||||
| 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= | ||||
|  |  | |||
|  | @ -285,14 +285,14 @@ func ParAnd(parallelism int, bitmaps ...*Bitmap) *Bitmap { | |||
| 		for input := range inputChan { | ||||
| 			c := input.containers[0].and(input.containers[1]) | ||||
| 			for _, next := range input.containers[2:] { | ||||
| 				if c.getCardinality() == 0 { | ||||
| 				if c.isEmpty() { | ||||
| 					break | ||||
| 				} | ||||
| 				c = c.iand(next) | ||||
| 			} | ||||
| 
 | ||||
| 			// Send a nil explicitly if the result of the intersection is an empty container
 | ||||
| 			if c.getCardinality() == 0 { | ||||
| 			if c.isEmpty() { | ||||
| 				c = nil | ||||
| 			} | ||||
| 
 | ||||
|  | @ -357,7 +357,7 @@ func ParOr(parallelism int, bitmaps ...*Bitmap) *Bitmap { | |||
| 		return bitmaps[0] | ||||
| 	} | ||||
| 
 | ||||
| 	keyRange := hKey - lKey + 1 | ||||
| 	keyRange := int(hKey) - int(lKey) + 1 | ||||
| 	if keyRange == 1 { | ||||
| 		// revert to FastOr. Since the key range is 0
 | ||||
| 		// no container-level aggregation parallelism is achievable
 | ||||
|  |  | |||
|  | @ -151,8 +151,7 @@ func (rb *Bitmap) ToArray() []uint32 { | |||
| 		hs := uint32(rb.highlowcontainer.getKeyAtIndex(pos)) << 16 | ||||
| 		c := rb.highlowcontainer.getContainerAtIndex(pos) | ||||
| 		pos++ | ||||
| 		c.fillLeastSignificant16bits(array, pos2, hs) | ||||
| 		pos2 += c.getCardinality() | ||||
| 		pos2 = c.fillLeastSignificant16bits(array, pos2, hs) | ||||
| 	} | ||||
| 	return array | ||||
| } | ||||
|  | @ -542,7 +541,7 @@ func AddOffset64(x *Bitmap, offset int64) (answer *Bitmap) { | |||
| 			c := x.highlowcontainer.getContainerAtIndex(pos) | ||||
| 			offsetted := c.addOffset(inOffset) | ||||
| 
 | ||||
| 			if offsetted[0].getCardinality() > 0 && (key >= 0 && key <= MaxUint16) { | ||||
| 			if !offsetted[0].isEmpty() && (key >= 0 && key <= MaxUint16) { | ||||
| 				curSize := answer.highlowcontainer.size() | ||||
| 				lastkey := int32(0) | ||||
| 
 | ||||
|  | @ -559,7 +558,7 @@ func AddOffset64(x *Bitmap, offset int64) (answer *Bitmap) { | |||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			if offsetted[1].getCardinality() > 0 && ((key+1) >= 0 && (key+1) <= MaxUint16) { | ||||
| 			if !offsetted[1].isEmpty() && ((key+1) >= 0 && (key+1) <= MaxUint16) { | ||||
| 				answer.highlowcontainer.appendContainer(uint16(key+1), offsetted[1], false) | ||||
| 			} | ||||
| 		} | ||||
|  | @ -630,13 +629,13 @@ func (rb *Bitmap) Remove(x uint32) { | |||
| 	if i >= 0 { | ||||
| 		c := rb.highlowcontainer.getWritableContainerAtIndex(i).iremoveReturnMinimized(lowbits(x)) | ||||
| 		rb.highlowcontainer.setContainerAtIndex(i, c) | ||||
| 		if rb.highlowcontainer.getContainerAtIndex(i).getCardinality() == 0 { | ||||
| 		if rb.highlowcontainer.getContainerAtIndex(i).isEmpty() { | ||||
| 			rb.highlowcontainer.removeAtIndex(i) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // CheckedRemove removes the integer x from the bitmap and return true if the integer was effectively remove (and false if the integer was not present)
 | ||||
| // CheckedRemove removes the integer x from the bitmap and return true if the integer was effectively removed (and false if the integer was not present)
 | ||||
| func (rb *Bitmap) CheckedRemove(x uint32) bool { | ||||
| 	// TODO: add unit tests for this method
 | ||||
| 	hb := highbits(x) | ||||
|  | @ -646,7 +645,7 @@ func (rb *Bitmap) CheckedRemove(x uint32) bool { | |||
| 		oldcard := C.getCardinality() | ||||
| 		C = C.iremoveReturnMinimized(lowbits(x)) | ||||
| 		rb.highlowcontainer.setContainerAtIndex(i, C) | ||||
| 		if rb.highlowcontainer.getContainerAtIndex(i).getCardinality() == 0 { | ||||
| 		if rb.highlowcontainer.getContainerAtIndex(i).isEmpty() { | ||||
| 			rb.highlowcontainer.removeAtIndex(i) | ||||
| 			return true | ||||
| 		} | ||||
|  | @ -701,8 +700,9 @@ func (rb *Bitmap) Select(x uint32) (uint32, error) { | |||
| 	remaining := x | ||||
| 	for i := 0; i < rb.highlowcontainer.size(); i++ { | ||||
| 		c := rb.highlowcontainer.getContainerAtIndex(i) | ||||
| 		if remaining >= uint32(c.getCardinality()) { | ||||
| 			remaining -= uint32(c.getCardinality()) | ||||
| 		card := uint32(c.getCardinality()) | ||||
| 		if remaining >= card { | ||||
| 			remaining -= card | ||||
| 		} else { | ||||
| 			key := rb.highlowcontainer.getKeyAtIndex(i) | ||||
| 			return uint32(key)<<16 + uint32(c.selectInt(uint16(remaining))), nil | ||||
|  | @ -729,7 +729,7 @@ main: | |||
| 					c1 := rb.highlowcontainer.getWritableContainerAtIndex(pos1) | ||||
| 					c2 := x2.highlowcontainer.getContainerAtIndex(pos2) | ||||
| 					diff := c1.iand(c2) | ||||
| 					if diff.getCardinality() > 0 { | ||||
| 					if !diff.isEmpty() { | ||||
| 						rb.highlowcontainer.replaceKeyAndContainerAtIndex(intersectionsize, s1, diff, false) | ||||
| 						intersectionsize++ | ||||
| 					} | ||||
|  | @ -931,7 +931,7 @@ func (rb *Bitmap) Xor(x2 *Bitmap) { | |||
| 			} else { | ||||
| 				// TODO: couple be computed in-place for reduced memory usage
 | ||||
| 				c := rb.highlowcontainer.getContainerAtIndex(pos1).xor(x2.highlowcontainer.getContainerAtIndex(pos2)) | ||||
| 				if c.getCardinality() > 0 { | ||||
| 				if !c.isEmpty() { | ||||
| 					rb.highlowcontainer.setContainerAtIndex(pos1, c) | ||||
| 					pos1++ | ||||
| 				} else { | ||||
|  | @ -1011,7 +1011,7 @@ main: | |||
| 					c1 := rb.highlowcontainer.getWritableContainerAtIndex(pos1) | ||||
| 					c2 := x2.highlowcontainer.getContainerAtIndex(pos2) | ||||
| 					diff := c1.iandNot(c2) | ||||
| 					if diff.getCardinality() > 0 { | ||||
| 					if !diff.isEmpty() { | ||||
| 						rb.highlowcontainer.replaceKeyAndContainerAtIndex(intersectionsize, s1, diff, false) | ||||
| 						intersectionsize++ | ||||
| 					} | ||||
|  | @ -1120,7 +1120,7 @@ main: | |||
| 				C := x1.highlowcontainer.getContainerAtIndex(pos1) | ||||
| 				C = C.and(x2.highlowcontainer.getContainerAtIndex(pos2)) | ||||
| 
 | ||||
| 				if C.getCardinality() > 0 { | ||||
| 				if !C.isEmpty() { | ||||
| 					answer.highlowcontainer.appendContainer(s1, C, false) | ||||
| 				} | ||||
| 				pos1++ | ||||
|  | @ -1167,7 +1167,7 @@ func Xor(x1, x2 *Bitmap) *Bitmap { | |||
| 				pos2++ | ||||
| 			} else { | ||||
| 				c := x1.highlowcontainer.getContainerAtIndex(pos1).xor(x2.highlowcontainer.getContainerAtIndex(pos2)) | ||||
| 				if c.getCardinality() > 0 { | ||||
| 				if !c.isEmpty() { | ||||
| 					answer.highlowcontainer.appendContainer(s1, c, false) | ||||
| 				} | ||||
| 				pos1++ | ||||
|  | @ -1210,7 +1210,7 @@ main: | |||
| 					c1 := x1.highlowcontainer.getContainerAtIndex(pos1) | ||||
| 					c2 := x2.highlowcontainer.getContainerAtIndex(pos2) | ||||
| 					diff := c1.andNot(c2) | ||||
| 					if diff.getCardinality() > 0 { | ||||
| 					if !diff.isEmpty() { | ||||
| 						answer.highlowcontainer.appendContainer(s1, diff, false) | ||||
| 					} | ||||
| 					pos1++ | ||||
|  | @ -1300,7 +1300,7 @@ func (rb *Bitmap) Flip(rangeStart, rangeEnd uint64) { | |||
| 
 | ||||
| 		if i >= 0 { | ||||
| 			c := rb.highlowcontainer.getWritableContainerAtIndex(i).inot(int(containerStart), int(containerLast)+1) | ||||
| 			if c.getCardinality() > 0 { | ||||
| 			if !c.isEmpty() { | ||||
| 				rb.highlowcontainer.setContainerAtIndex(i, c) | ||||
| 			} else { | ||||
| 				rb.highlowcontainer.removeAtIndex(i) | ||||
|  | @ -1381,7 +1381,7 @@ func (rb *Bitmap) RemoveRange(rangeStart, rangeEnd uint64) { | |||
| 			return | ||||
| 		} | ||||
| 		c := rb.highlowcontainer.getWritableContainerAtIndex(i).iremoveRange(int(lbStart), int(lbLast+1)) | ||||
| 		if c.getCardinality() > 0 { | ||||
| 		if !c.isEmpty() { | ||||
| 			rb.highlowcontainer.setContainerAtIndex(i, c) | ||||
| 		} else { | ||||
| 			rb.highlowcontainer.removeAtIndex(i) | ||||
|  | @ -1394,7 +1394,7 @@ func (rb *Bitmap) RemoveRange(rangeStart, rangeEnd uint64) { | |||
| 	if ifirst >= 0 { | ||||
| 		if lbStart != 0 { | ||||
| 			c := rb.highlowcontainer.getWritableContainerAtIndex(ifirst).iremoveRange(int(lbStart), int(max+1)) | ||||
| 			if c.getCardinality() > 0 { | ||||
| 			if !c.isEmpty() { | ||||
| 				rb.highlowcontainer.setContainerAtIndex(ifirst, c) | ||||
| 				ifirst++ | ||||
| 			} | ||||
|  | @ -1405,7 +1405,7 @@ func (rb *Bitmap) RemoveRange(rangeStart, rangeEnd uint64) { | |||
| 	if ilast >= 0 { | ||||
| 		if lbLast != max { | ||||
| 			c := rb.highlowcontainer.getWritableContainerAtIndex(ilast).iremoveRange(int(0), int(lbLast+1)) | ||||
| 			if c.getCardinality() > 0 { | ||||
| 			if !c.isEmpty() { | ||||
| 				rb.highlowcontainer.setContainerAtIndex(ilast, c) | ||||
| 			} else { | ||||
| 				ilast++ | ||||
|  | @ -1461,7 +1461,7 @@ func Flip(bm *Bitmap, rangeStart, rangeEnd uint64) *Bitmap { | |||
| 
 | ||||
| 		if i >= 0 { | ||||
| 			c := bm.highlowcontainer.getContainerAtIndex(i).not(int(containerStart), int(containerLast)+1) | ||||
| 			if c.getCardinality() > 0 { | ||||
| 			if !c.isEmpty() { | ||||
| 				answer.highlowcontainer.insertNewKeyValueAt(-j-1, uint16(hb), c) | ||||
| 			} | ||||
| 
 | ||||
|  |  | |||
|  | @ -17,6 +17,7 @@ type container interface { | |||
| 	iand(container) container // i stands for inplace
 | ||||
| 	andNot(container) container | ||||
| 	iandNot(container) container // i stands for inplace
 | ||||
| 	isEmpty() bool | ||||
| 	getCardinality() int | ||||
| 	// rank returns the number of integers that are
 | ||||
| 	// smaller or equal to x. rank(infinity) would be getCardinality().
 | ||||
|  | @ -47,7 +48,7 @@ type container interface { | |||
| 	// any of the implementations.
 | ||||
| 	equals(r container) bool | ||||
| 
 | ||||
| 	fillLeastSignificant16bits(array []uint32, i int, mask uint32) | ||||
| 	fillLeastSignificant16bits(array []uint32, i int, mask uint32) int | ||||
| 	or(r container) container | ||||
| 	orCardinality(r container) int | ||||
| 	isFull() bool | ||||
|  | @ -645,7 +646,6 @@ func (ra *roaringArray) readFrom(stream internal.ByteInput, cookieHeader ...byte | |||
| 
 | ||||
| 			nb := runContainer16{ | ||||
| 				iv:   byteSliceAsInterval16Slice(buf), | ||||
| 				card: int64(card), | ||||
| 			} | ||||
| 
 | ||||
| 			ra.containers[i] = &nb | ||||
|  |  | |||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							|  | @ -63,7 +63,7 @@ import ( | |||
| 	"sort" | ||||
| 
 | ||||
| 	"github.com/mschoch/smat" | ||||
| 	"github.com/willf/bitset" | ||||
| 	"github.com/bits-and-blooms/bitset" | ||||
| ) | ||||
| 
 | ||||
| // fuzz test using state machine driven by byte stream.
 | ||||
|  |  | |||
|  | @ -0,0 +1,42 @@ | |||
| # bufpipe: Buffered Pipe | ||||
| 
 | ||||
| [](https://circleci.com/gh/acomagu/bufpipe) [](https://godoc.org/github.com/acomagu/bufpipe) | ||||
| 
 | ||||
| The buffered version of io.Pipe. It's safe for concurrent use. | ||||
| 
 | ||||
| ## How does it differ from io.Pipe? | ||||
| 
 | ||||
| Writes never block because the pipe has variable-sized buffer. | ||||
| 
 | ||||
| ```Go | ||||
| r, w := bufpipe.New(nil) | ||||
| io.WriteString(w, "abc") // No blocking. | ||||
| io.WriteString(w, "def") // No blocking, too. | ||||
| w.Close() | ||||
| io.Copy(os.Stdout, r) | ||||
| // Output: abcdef | ||||
| ``` | ||||
| 
 | ||||
| [Playground](https://play.golang.org/p/PdyBAS3pVob) | ||||
| 
 | ||||
| ## How does it differ from bytes.Buffer? | ||||
| 
 | ||||
| Reads block if the internal buffer is empty until the writer is closed. | ||||
| 
 | ||||
| ```Go | ||||
| r, w := bufpipe.New(nil) | ||||
| 
 | ||||
| done := make(chan struct{}) | ||||
| go func() { | ||||
| 	io.Copy(os.Stdout, r) // The reads block until the writer is closed. | ||||
| 	done <- struct{}{} | ||||
| }() | ||||
| 
 | ||||
| io.WriteString(w, "abc") | ||||
| io.WriteString(w, "def") | ||||
| w.Close() | ||||
| <-done | ||||
| // Output: abcdef | ||||
| ``` | ||||
| 
 | ||||
| [Playground](https://play.golang.org/p/UppmyLeRgX6) | ||||
|  | @ -0,0 +1,128 @@ | |||
| package bufpipe | ||||
| 
 | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"errors" | ||||
| 	"io" | ||||
| 	"sync" | ||||
| ) | ||||
| 
 | ||||
| // ErrClosedPipe is the error used for read or write operations on a closed pipe.
 | ||||
| var ErrClosedPipe = errors.New("bufpipe: read/write on closed pipe") | ||||
| 
 | ||||
| type pipe struct { | ||||
| 	cond       *sync.Cond | ||||
| 	buf        *bytes.Buffer | ||||
| 	rerr, werr error | ||||
| } | ||||
| 
 | ||||
| // A PipeReader is the read half of a pipe.
 | ||||
| type PipeReader struct { | ||||
| 	*pipe | ||||
| } | ||||
| 
 | ||||
| // A PipeWriter is the write half of a pipe.
 | ||||
| type PipeWriter struct { | ||||
| 	*pipe | ||||
| } | ||||
| 
 | ||||
| // New creates a synchronous pipe using buf as its initial contents. It can be
 | ||||
| // used to connect code expecting an io.Reader with code expecting an io.Writer.
 | ||||
| //
 | ||||
| // Unlike io.Pipe, writes never block because the internal buffer has variable
 | ||||
| // size. Reads block only when the buffer is empty.
 | ||||
| //
 | ||||
| // It is safe to call Read and Write in parallel with each other or with Close.
 | ||||
| // Parallel calls to Read and parallel calls to Write are also safe: the
 | ||||
| // individual calls will be gated sequentially.
 | ||||
| //
 | ||||
| // The new pipe takes ownership of buf, and the caller should not use buf after
 | ||||
| // this call. New is intended to prepare a PipeReader to read existing data. It
 | ||||
| // can also be used to set the initial size of the internal buffer for writing.
 | ||||
| // To do that, buf should have the desired capacity but a length of zero.
 | ||||
| func New(buf []byte) (*PipeReader, *PipeWriter) { | ||||
| 	p := &pipe{ | ||||
| 		buf:  bytes.NewBuffer(buf), | ||||
| 		cond: sync.NewCond(new(sync.Mutex)), | ||||
| 	} | ||||
| 	return &PipeReader{ | ||||
| 			pipe: p, | ||||
| 		}, &PipeWriter{ | ||||
| 			pipe: p, | ||||
| 		} | ||||
| } | ||||
| 
 | ||||
| // Read implements the standard Read interface: it reads data from the pipe,
 | ||||
| // reading from the internal buffer, otherwise blocking until a writer arrives
 | ||||
| // or the write end is closed. If the write end is closed with an error, that
 | ||||
| // error is returned as err; otherwise err is io.EOF.
 | ||||
| func (r *PipeReader) Read(data []byte) (int, error) { | ||||
| 	r.cond.L.Lock() | ||||
| 	defer r.cond.L.Unlock() | ||||
| 
 | ||||
| RETRY: | ||||
| 	n, err := r.buf.Read(data) | ||||
| 	// If not closed and no read, wait for writing.
 | ||||
| 	if err == io.EOF && r.rerr == nil && n == 0 { | ||||
| 		r.cond.Wait() | ||||
| 		goto RETRY | ||||
| 	} | ||||
| 	if err == io.EOF { | ||||
| 		return n, r.rerr | ||||
| 	} | ||||
| 	return n, err | ||||
| } | ||||
| 
 | ||||
| // Close closes the reader; subsequent writes from the write half of the pipe
 | ||||
| // will return error ErrClosedPipe.
 | ||||
| func (r *PipeReader) Close() error { | ||||
| 	return r.CloseWithError(nil) | ||||
| } | ||||
| 
 | ||||
| // CloseWithError closes the reader; subsequent writes to the write half of the
 | ||||
| // pipe will return the error err.
 | ||||
| func (r *PipeReader) CloseWithError(err error) error { | ||||
| 	r.cond.L.Lock() | ||||
| 	defer r.cond.L.Unlock() | ||||
| 
 | ||||
| 	if err == nil { | ||||
| 		err = ErrClosedPipe | ||||
| 	} | ||||
| 	r.werr = err | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // Write implements the standard Write interface: it writes data to the internal
 | ||||
| // buffer. If the read end is closed with an error, that err is returned as err;
 | ||||
| // otherwise err is ErrClosedPipe.
 | ||||
| func (w *PipeWriter) Write(data []byte) (int, error) { | ||||
| 	w.cond.L.Lock() | ||||
| 	defer w.cond.L.Unlock() | ||||
| 
 | ||||
| 	if w.werr != nil { | ||||
| 		return 0, w.werr | ||||
| 	} | ||||
| 
 | ||||
| 	n, err := w.buf.Write(data) | ||||
| 	w.cond.Signal() | ||||
| 	return n, err | ||||
| } | ||||
| 
 | ||||
| // Close closes the writer; subsequent reads from the read half of the pipe will
 | ||||
| // return io.EOF once the internal buffer get empty.
 | ||||
| func (w *PipeWriter) Close() error { | ||||
| 	return w.CloseWithError(nil) | ||||
| } | ||||
| 
 | ||||
| // Close closes the writer; subsequent reads from the read half of the pipe will
 | ||||
| // return err once the internal buffer get empty.
 | ||||
| func (w *PipeWriter) CloseWithError(err error) error { | ||||
| 	w.cond.L.Lock() | ||||
| 	defer w.cond.L.Unlock() | ||||
| 
 | ||||
| 	if err == nil { | ||||
| 		err = io.EOF | ||||
| 	} | ||||
| 	w.rerr = err | ||||
| 	return nil | ||||
| } | ||||
|  | @ -0,0 +1,2 @@ | |||
| // Package bufpipe provides a IO pipe, has variable-sized buffer.
 | ||||
| package bufpipe | ||||
|  | @ -0,0 +1,5 @@ | |||
| module github.com/acomagu/bufpipe | ||||
| 
 | ||||
| go 1.12 | ||||
| 
 | ||||
| require github.com/matryer/is v1.2.0 | ||||
|  | @ -0,0 +1,2 @@ | |||
| github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A= | ||||
| github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= | ||||
|  | @ -1,5 +1,7 @@ | |||
| .PHONY: chromad upload all | ||||
| 
 | ||||
| VERSION ?= $(shell git describe --tags --dirty  --always) | ||||
| 
 | ||||
| all: README.md tokentype_string.go | ||||
| 
 | ||||
| README.md: lexers/*/*.go | ||||
|  | @ -9,10 +11,8 @@ tokentype_string.go: types.go | |||
| 	go generate | ||||
| 
 | ||||
| chromad: | ||||
| 	(cd ./cmd/chromad && go get github.com/GeertJohan/go.rice/rice@master && go install github.com/GeertJohan/go.rice/rice) | ||||
| 	rm -f chromad | ||||
| 	(export CGOENABLED=0 GOOS=linux ; cd ./cmd/chromad && go build -o ../../chromad .) | ||||
| 	rice append -i ./cmd/chromad --exec=./chromad | ||||
| 	(export CGOENABLED=0 GOOS=linux ; cd ./cmd/chromad && go build -ldflags="-X 'main.version=$(VERSION)'" -o ../../chromad .) | ||||
| 
 | ||||
| upload: chromad | ||||
| 	scp chromad root@swapoff.org: && \
 | ||||
|  |  | |||
|  | @ -1,4 +1,4 @@ | |||
| # Chroma — A general purpose syntax highlighter in pure Go [](https://godoc.org/github.com/alecthomas/chroma) [](https://circleci.com/gh/alecthomas/chroma) [](https://goreportcard.com/report/github.com/alecthomas/chroma) [](https://gophers.slack.com/messages/CN9DS8YF3) | ||||
| # Chroma — A general purpose syntax highlighter in pure Go [](https://godoc.org/github.com/alecthomas/chroma) [](https://circleci.com/gh/alecthomas/chroma) [](https://goreportcard.com/report/github.com/alecthomas/chroma) [](https://invite.slack.golangbridge.org/) | ||||
| 
 | ||||
| > **NOTE:** As Chroma has just been released, its API is still in flux. That said, the high-level interface should not change significantly. | ||||
| 
 | ||||
|  | @ -38,7 +38,7 @@ Prefix | Language | |||
| A | ABAP, ABNF, ActionScript, ActionScript 3, Ada, Angular2, ANTLR, ApacheConf, APL, AppleScript, Arduino, Awk | ||||
| B | Ballerina, Base Makefile, Bash, Batchfile, BibTeX, BlitzBasic, BNF, Brainfuck | ||||
| C | C, C#, C++, Caddyfile, Caddyfile Directives, Cap'n Proto, Cassandra CQL, Ceylon, CFEngine3, cfstatement, ChaiScript, Cheetah, Clojure, CMake, COBOL, CoffeeScript, Common Lisp, Coq, Crystal, CSS, Cython | ||||
| D | D, Dart, Diff, Django/Jinja, Docker, DTD | ||||
| D | D, Dart, Diff, Django/Jinja, Docker, DTD, Dylan | ||||
| E | EBNF, Elixir, Elm, EmacsLisp, Erlang | ||||
| F | Factor, Fish, Forth, Fortran, FSharp | ||||
| G | GAS, GDScript, Genshi, Genshi HTML, Genshi Text, Gherkin, GLSL, Gnuplot, Go, Go HTML Template, Go Text Template, GraphQL, Groovy | ||||
|  | @ -216,7 +216,7 @@ python3 ~/Projects/chroma/_tools/pygments2chroma.py \ | |||
|   && gofmt -s -w ~/Projects/chroma/lexers/*.go | ||||
| ``` | ||||
| 
 | ||||
| See notes in [pygments-lexers.go](https://github.com/alecthomas/chroma/blob/master/pygments-lexers.txt) | ||||
| See notes in [pygments-lexers.txt](https://github.com/alecthomas/chroma/blob/master/pygments-lexers.txt) | ||||
| for a list of lexers, and notes on some of the issues importing them. | ||||
| 
 | ||||
| <a id="markdown-formatters" name="formatters"></a> | ||||
|  |  | |||
|  | @ -8,7 +8,7 @@ require ( | |||
| 	github.com/alecthomas/kong v0.2.4 | ||||
| 	github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897 // indirect | ||||
| 	github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 | ||||
| 	github.com/dlclark/regexp2 v1.2.0 | ||||
| 	github.com/dlclark/regexp2 v1.4.0 | ||||
| 	github.com/mattn/go-colorable v0.1.6 | ||||
| 	github.com/mattn/go-isatty v0.0.12 | ||||
| 	github.com/pkg/errors v0.9.1 // indirect | ||||
|  |  | |||
|  | @ -13,6 +13,8 @@ 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/dlclark/regexp2 v1.2.0 h1:8sAhBGEM0dRWogWqWyQeIJnxjWO6oIjl8FKqREDsGfk= | ||||
| github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= | ||||
| github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E= | ||||
| github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= | ||||
| github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE= | ||||
| github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= | ||||
| github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= | ||||
|  |  | |||
|  | @ -4,7 +4,7 @@ import "strings" | |||
| 
 | ||||
| // An Iterator across tokens.
 | ||||
| //
 | ||||
| // nil will be returned at the end of the Token stream.
 | ||||
| // EOF will be returned at the end of the Token stream.
 | ||||
| //
 | ||||
| // If an error occurs within an Iterator, it may propagate this in a panic. Formatters should recover.
 | ||||
| type Iterator func() Token | ||||
|  |  | |||
|  | @ -6,7 +6,7 @@ import ( | |||
| ) | ||||
| 
 | ||||
| // ABAP lexer.
 | ||||
| var Abap = internal.Register(MustNewLexer( | ||||
| var Abap = internal.Register(MustNewLazyLexer( | ||||
| 	&Config{ | ||||
| 		Name:            "ABAP", | ||||
| 		Aliases:         []string{"abap"}, | ||||
|  | @ -14,7 +14,11 @@ var Abap = internal.Register(MustNewLexer( | |||
| 		MimeTypes:       []string{"text/x-abap"}, | ||||
| 		CaseInsensitive: true, | ||||
| 	}, | ||||
| 	Rules{ | ||||
| 	abapRules, | ||||
| )) | ||||
| 
 | ||||
| func abapRules() Rules { | ||||
| 	return Rules{ | ||||
| 		"common": { | ||||
| 			{`\s+`, Text, nil}, | ||||
| 			{`^\*.*$`, CommentSingle, nil}, | ||||
|  | @ -52,5 +56,5 @@ var Abap = internal.Register(MustNewLexer( | |||
| 			{`[/;:()\[\],.]`, Punctuation, nil}, | ||||
| 			{`(!)(\w+)`, ByGroups(Operator, Name), nil}, | ||||
| 		}, | ||||
| 	}, | ||||
| )) | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -6,14 +6,18 @@ import ( | |||
| ) | ||||
| 
 | ||||
| // Abnf lexer.
 | ||||
| var Abnf = internal.Register(MustNewLexer( | ||||
| var Abnf = internal.Register(MustNewLazyLexer( | ||||
| 	&Config{ | ||||
| 		Name:      "ABNF", | ||||
| 		Aliases:   []string{"abnf"}, | ||||
| 		Filenames: []string{"*.abnf"}, | ||||
| 		MimeTypes: []string{"text/x-abnf"}, | ||||
| 	}, | ||||
| 	Rules{ | ||||
| 	abnfRules, | ||||
| )) | ||||
| 
 | ||||
| func abnfRules() Rules { | ||||
| 	return Rules{ | ||||
| 		"root": { | ||||
| 			{`;.*$`, CommentSingle, nil}, | ||||
| 			{`(%[si])?"[^"]*"`, Literal, nil}, | ||||
|  | @ -34,5 +38,5 @@ var Abnf = internal.Register(MustNewLexer( | |||
| 			{`\s+`, Text, nil}, | ||||
| 			{`.`, Text, nil}, | ||||
| 		}, | ||||
| 	}, | ||||
| )) | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -6,7 +6,7 @@ import ( | |||
| ) | ||||
| 
 | ||||
| // Actionscript lexer.
 | ||||
| var Actionscript = internal.Register(MustNewLexer( | ||||
| var Actionscript = internal.Register(MustNewLazyLexer( | ||||
| 	&Config{ | ||||
| 		Name:         "ActionScript", | ||||
| 		Aliases:      []string{"as", "actionscript"}, | ||||
|  | @ -15,7 +15,11 @@ var Actionscript = internal.Register(MustNewLexer( | |||
| 		NotMultiline: true, | ||||
| 		DotAll:       true, | ||||
| 	}, | ||||
| 	Rules{ | ||||
| 	actionscriptRules, | ||||
| )) | ||||
| 
 | ||||
| func actionscriptRules() Rules { | ||||
| 	return Rules{ | ||||
| 		"root": { | ||||
| 			{`\s+`, Text, nil}, | ||||
| 			{`//.*?\n`, CommentSingle, nil}, | ||||
|  | @ -35,5 +39,5 @@ var Actionscript = internal.Register(MustNewLexer( | |||
| 			{`"(\\\\|\\"|[^"])*"`, LiteralStringDouble, nil}, | ||||
| 			{`'(\\\\|\\'|[^'])*'`, LiteralStringSingle, nil}, | ||||
| 		}, | ||||
| 	}, | ||||
| )) | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -6,7 +6,7 @@ import ( | |||
| ) | ||||
| 
 | ||||
| // Actionscript 3 lexer.
 | ||||
| var Actionscript3 = internal.Register(MustNewLexer( | ||||
| var Actionscript3 = internal.Register(MustNewLazyLexer( | ||||
| 	&Config{ | ||||
| 		Name:      "ActionScript 3", | ||||
| 		Aliases:   []string{"as3", "actionscript3"}, | ||||
|  | @ -14,7 +14,11 @@ var Actionscript3 = internal.Register(MustNewLexer( | |||
| 		MimeTypes: []string{"application/x-actionscript3", "text/x-actionscript3", "text/actionscript3"}, | ||||
| 		DotAll:    true, | ||||
| 	}, | ||||
| 	Rules{ | ||||
| 	actionscript3Rules, | ||||
| )) | ||||
| 
 | ||||
| func actionscript3Rules() Rules { | ||||
| 	return Rules{ | ||||
| 		"root": { | ||||
| 			{`\s+`, Text, nil}, | ||||
| 			{`(function\s+)([$a-zA-Z_]\w*)(\s*)(\()`, ByGroups(KeywordDeclaration, NameFunction, Text, Operator), Push("funcparams")}, | ||||
|  | @ -52,5 +56,5 @@ var Actionscript3 = internal.Register(MustNewLexer( | |||
| 			{`,`, Operator, Pop(1)}, | ||||
| 			Default(Pop(1)), | ||||
| 		}, | ||||
| 	}, | ||||
| )) | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -6,7 +6,7 @@ import ( | |||
| ) | ||||
| 
 | ||||
| // Ada lexer.
 | ||||
| var Ada = internal.Register(MustNewLexer( | ||||
| var Ada = internal.Register(MustNewLazyLexer( | ||||
| 	&Config{ | ||||
| 		Name:            "Ada", | ||||
| 		Aliases:         []string{"ada", "ada95", "ada2005"}, | ||||
|  | @ -14,7 +14,11 @@ var Ada = internal.Register(MustNewLexer( | |||
| 		MimeTypes:       []string{"text/x-ada"}, | ||||
| 		CaseInsensitive: true, | ||||
| 	}, | ||||
| 	Rules{ | ||||
| 	adaRules, | ||||
| )) | ||||
| 
 | ||||
| func adaRules() Rules { | ||||
| 	return Rules{ | ||||
| 		"root": { | ||||
| 			{`[^\S\n]+`, Text, nil}, | ||||
| 			{`--.*?\n`, CommentSingle, nil}, | ||||
|  | @ -110,5 +114,5 @@ var Ada = internal.Register(MustNewLexer( | |||
| 			{`\)`, Punctuation, Pop(1)}, | ||||
| 			Include("root"), | ||||
| 		}, | ||||
| 	}, | ||||
| )) | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -0,0 +1,48 @@ | |||
| package a | ||||
| 
 | ||||
| import ( | ||||
| 	. "github.com/alecthomas/chroma" // nolint
 | ||||
| 	"github.com/alecthomas/chroma/lexers/internal" | ||||
| ) | ||||
| 
 | ||||
| // Al lexer.
 | ||||
| var Al = internal.Register(MustNewLazyLexer( | ||||
| 	&Config{ | ||||
| 		Name:            "AL", | ||||
| 		Aliases:         []string{"al"}, | ||||
| 		Filenames:       []string{"*.al", "*.dal"}, | ||||
| 		MimeTypes:       []string{"text/x-al"}, | ||||
| 		DotAll:          true, | ||||
| 		CaseInsensitive: true, | ||||
| 	}, | ||||
| 	alRules, | ||||
| )) | ||||
| 
 | ||||
| // https://github.com/microsoft/AL/blob/master/grammar/alsyntax.tmlanguage
 | ||||
| func alRules() Rules { | ||||
| 	return Rules{ | ||||
| 		"root": { | ||||
| 			{`\s+`, TextWhitespace, nil}, | ||||
| 			{`(?s)\/\*.*?\\*\*\/`, CommentMultiline, nil}, | ||||
| 			{`(?s)//.*?\n`, CommentSingle, nil}, | ||||
| 			{`\"([^\"])*\"`, Text, nil}, | ||||
| 			{`'([^'])*'`, LiteralString, nil}, | ||||
| 			{`\b(?i:(ARRAY|ASSERTERROR|BEGIN|BREAK|CASE|DO|DOWNTO|ELSE|END|EVENT|EXIT|FOR|FOREACH|FUNCTION|IF|IMPLEMENTS|IN|INDATASET|INTERFACE|INTERNAL|LOCAL|OF|PROCEDURE|PROGRAM|PROTECTED|REPEAT|RUNONCLIENT|SECURITYFILTERING|SUPPRESSDISPOSE|TEMPORARY|THEN|TO|TRIGGER|UNTIL|VAR|WHILE|WITH|WITHEVENTS))\b`, Keyword, nil}, | ||||
| 			{`\b(?i:(AND|DIV|MOD|NOT|OR|XOR))\b`, OperatorWord, nil}, | ||||
| 			{`\b(?i:(AVERAGE|CONST|COUNT|EXIST|FIELD|FILTER|LOOKUP|MAX|MIN|ORDER|SORTING|SUM|TABLEDATA|UPPERLIMIT|WHERE|ASCENDING|DESCENDING))\b`, Keyword, nil}, | ||||
| 			// Added new objects types of BC 2021 wave 1 (REPORTEXTENSION|Entitlement|PermissionSet|PermissionSetExtension)
 | ||||
| 			{`\b(?i:(CODEUNIT|PAGE|PAGEEXTENSION|PAGECUSTOMIZATION|DOTNET|ENUM|ENUMEXTENSION|VALUE|QUERY|REPORT|TABLE|TABLEEXTENSION|XMLPORT|PROFILE|CONTROLADDIN|REPORTEXTENSION|Entitlement|PermissionSet|PermissionSetExtension))\b`, Keyword, nil}, | ||||
| 			{`\b(?i:(Action|Array|Automation|BigInteger|BigText|Blob|Boolean|Byte|Char|ClientType|Code|Codeunit|CompletionTriggerErrorLevel|ConnectionType|Database|DataClassification|DataScope|Date|DateFormula|DateTime|Decimal|DefaultLayout|Dialog|Dictionary|DotNet|DotNetAssembly|DotNetTypeDeclaration|Duration|Enum|ErrorInfo|ErrorType|ExecutionContext|ExecutionMode|FieldClass|FieldRef|FieldType|File|FilterPageBuilder|Guid|InStream|Integer|Joker|KeyRef|List|ModuleDependencyInfo|ModuleInfo|None|Notification|NotificationScope|ObjectType|Option|OutStream|Page|PageResult|Query|Record|RecordId|RecordRef|Report|ReportFormat|SecurityFilter|SecurityFiltering|Table|TableConnectionType|TableFilter|TestAction|TestField|TestFilterField|TestPage|TestPermissions|TestRequestPage|Text|TextBuilder|TextConst|TextEncoding|Time|TransactionModel|TransactionType|Variant|Verbosity|Version|XmlPort|HttpContent|HttpHeaders|HttpClient|HttpRequestMessage|HttpResponseMessage|JsonToken|JsonValue|JsonArray|JsonObject|View|Views|XmlAttribute|XmlAttributeCollection|XmlComment|XmlCData|XmlDeclaration|XmlDocument|XmlDocumentType|XmlElement|XmlNamespaceManager|XmlNameTable|XmlNode|XmlNodeList|XmlProcessingInstruction|XmlReadOptions|XmlText|XmlWriteOptions|WebServiceActionContext|WebServiceActionResultCode|SessionSettings))\b`, Keyword, nil}, | ||||
| 			{`\b([<>]=|<>|<|>)\b?`, Operator, nil}, | ||||
| 			{`\b(\-|\+|\/|\*)\b`, Operator, nil}, | ||||
| 			{`\s*(\:=|\+=|-=|\/=|\*=)\s*?`, Operator, nil}, | ||||
| 			{`\b(?i:(ADDFIRST|ADDLAST|ADDAFTER|ADDBEFORE|ACTION|ACTIONS|AREA|ASSEMBLY|CHARTPART|CUEGROUP|CUSTOMIZES|COLUMN|DATAITEM|DATASET|ELEMENTS|EXTENDS|FIELD|FIELDGROUP|FIELDATTRIBUTE|FIELDELEMENT|FIELDGROUPS|FIELDS|FILTER|FIXED|GRID|GROUP|MOVEAFTER|MOVEBEFORE|KEY|KEYS|LABEL|LABELS|LAYOUT|MODIFY|MOVEFIRST|MOVELAST|MOVEBEFORE|MOVEAFTER|PART|REPEATER|USERCONTROL|REQUESTPAGE|SCHEMA|SEPARATOR|SYSTEMPART|TABLEELEMENT|TEXTATTRIBUTE|TEXTELEMENT|TYPE))\b`, Keyword, nil}, | ||||
| 			{`\s*[(\.\.)&\|]\s*`, Operator, nil}, | ||||
| 			{`\b((0(x|X)[0-9a-fA-F]*)|(([0-9]+\.?[0-9]*)|(\.[0-9]+))((e|E)(\+|-)?[0-9]+)?)(L|l|UL|ul|u|U|F|f|ll|LL|ull|ULL)?\b`, LiteralNumber, nil}, | ||||
| 			{`[;:,]`, Punctuation, nil}, | ||||
| 			{`#[ \t]*(if|else|elif|endif|define|undef|region|endregion|pragma)\b.*?\n`, CommentPreproc, nil}, | ||||
| 			{`\w+`, Text, nil}, | ||||
| 			{`.`, Text, nil}, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
|  | @ -6,14 +6,18 @@ import ( | |||
| ) | ||||
| 
 | ||||
| // Angular2 lexer.
 | ||||
| var Angular2 = internal.Register(MustNewLexer( | ||||
| var Angular2 = internal.Register(MustNewLazyLexer( | ||||
| 	&Config{ | ||||
| 		Name:      "Angular2", | ||||
| 		Aliases:   []string{"ng2"}, | ||||
| 		Filenames: []string{}, | ||||
| 		MimeTypes: []string{}, | ||||
| 	}, | ||||
| 	Rules{ | ||||
| 	angular2Rules, | ||||
| )) | ||||
| 
 | ||||
| func angular2Rules() Rules { | ||||
| 	return Rules{ | ||||
| 		"root": { | ||||
| 			{`[^{([*#]+`, Other, nil}, | ||||
| 			{`(\{\{)(\s*)`, ByGroups(CommentPreproc, Text), Push("ngExpression")}, | ||||
|  | @ -38,5 +42,5 @@ var Angular2 = internal.Register(MustNewLexer( | |||
| 			{`'.*?'`, LiteralString, Pop(1)}, | ||||
| 			{`[^\s>]+`, LiteralString, Pop(1)}, | ||||
| 		}, | ||||
| 	}, | ||||
| )) | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -6,14 +6,18 @@ import ( | |||
| ) | ||||
| 
 | ||||
| // ANTLR lexer.
 | ||||
| var ANTLR = internal.Register(MustNewLexer( | ||||
| var ANTLR = internal.Register(MustNewLazyLexer( | ||||
| 	&Config{ | ||||
| 		Name:      "ANTLR", | ||||
| 		Aliases:   []string{"antlr"}, | ||||
| 		Filenames: []string{}, | ||||
| 		MimeTypes: []string{}, | ||||
| 	}, | ||||
| 	Rules{ | ||||
| 	antlrRules, | ||||
| )) | ||||
| 
 | ||||
| func antlrRules() Rules { | ||||
| 	return Rules{ | ||||
| 		"whitespace": { | ||||
| 			{`\s+`, TextWhitespace, nil}, | ||||
| 		}, | ||||
|  | @ -97,5 +101,5 @@ var ANTLR = internal.Register(MustNewLexer( | |||
| 			{`(\$[a-zA-Z]+)(\.?)(text|value)?`, ByGroups(NameVariable, Punctuation, NameProperty), nil}, | ||||
| 			{`(\\\\|\\\]|\\\[|[^\[\]])+`, Other, nil}, | ||||
| 		}, | ||||
| 	}, | ||||
| )) | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -6,7 +6,7 @@ import ( | |||
| ) | ||||
| 
 | ||||
| // Apacheconf lexer.
 | ||||
| var Apacheconf = internal.Register(MustNewLexer( | ||||
| var Apacheconf = internal.Register(MustNewLazyLexer( | ||||
| 	&Config{ | ||||
| 		Name:            "ApacheConf", | ||||
| 		Aliases:         []string{"apacheconf", "aconf", "apache"}, | ||||
|  | @ -14,7 +14,11 @@ var Apacheconf = internal.Register(MustNewLexer( | |||
| 		MimeTypes:       []string{"text/x-apacheconf"}, | ||||
| 		CaseInsensitive: true, | ||||
| 	}, | ||||
| 	Rules{ | ||||
| 	apacheconfRules, | ||||
| )) | ||||
| 
 | ||||
| func apacheconfRules() Rules { | ||||
| 	return Rules{ | ||||
| 		"root": { | ||||
| 			{`\s+`, Text, nil}, | ||||
| 			{`(#.*?)$`, Comment, nil}, | ||||
|  | @ -34,5 +38,5 @@ var Apacheconf = internal.Register(MustNewLexer( | |||
| 			{`"([^"\\]*(?:\\.[^"\\]*)*)"`, LiteralStringDouble, nil}, | ||||
| 			{`[^\s"\\]+`, Text, nil}, | ||||
| 		}, | ||||
| 	}, | ||||
| )) | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -6,14 +6,18 @@ import ( | |||
| ) | ||||
| 
 | ||||
| // Apl lexer.
 | ||||
| var Apl = internal.Register(MustNewLexer( | ||||
| var Apl = internal.Register(MustNewLazyLexer( | ||||
| 	&Config{ | ||||
| 		Name:      "APL", | ||||
| 		Aliases:   []string{"apl"}, | ||||
| 		Filenames: []string{"*.apl"}, | ||||
| 		MimeTypes: []string{}, | ||||
| 	}, | ||||
| 	Rules{ | ||||
| 	aplRules, | ||||
| )) | ||||
| 
 | ||||
| func aplRules() Rules { | ||||
| 	return Rules{ | ||||
| 		"root": { | ||||
| 			{`\s+`, Text, nil}, | ||||
| 			{`[⍝#].*$`, CommentSingle, nil}, | ||||
|  | @ -32,5 +36,5 @@ var Apl = internal.Register(MustNewLexer( | |||
| 			{`[⍺⍵⍶⍹∇:]`, NameBuiltinPseudo, nil}, | ||||
| 			{`[{}]`, KeywordType, nil}, | ||||
| 		}, | ||||
| 	}, | ||||
| )) | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -6,7 +6,7 @@ import ( | |||
| ) | ||||
| 
 | ||||
| // Applescript lexer.
 | ||||
| var Applescript = internal.Register(MustNewLexer( | ||||
| var Applescript = internal.Register(MustNewLazyLexer( | ||||
| 	&Config{ | ||||
| 		Name:      "AppleScript", | ||||
| 		Aliases:   []string{"applescript"}, | ||||
|  | @ -14,7 +14,11 @@ var Applescript = internal.Register(MustNewLexer( | |||
| 		MimeTypes: []string{}, | ||||
| 		DotAll:    true, | ||||
| 	}, | ||||
| 	Rules{ | ||||
| 	applescriptRules, | ||||
| )) | ||||
| 
 | ||||
| func applescriptRules() Rules { | ||||
| 	return Rules{ | ||||
| 		"root": { | ||||
| 			{`\s+`, Text, nil}, | ||||
| 			{`¬\n`, LiteralStringEscape, nil}, | ||||
|  | @ -51,5 +55,5 @@ var Applescript = internal.Register(MustNewLexer( | |||
| 			{`[^*(]+`, CommentMultiline, nil}, | ||||
| 			{`[*(]`, CommentMultiline, nil}, | ||||
| 		}, | ||||
| 	}, | ||||
| )) | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -6,7 +6,7 @@ import ( | |||
| ) | ||||
| 
 | ||||
| // Arduino lexer.
 | ||||
| var Arduino = internal.Register(MustNewLexer( | ||||
| var Arduino = internal.Register(MustNewLazyLexer( | ||||
| 	&Config{ | ||||
| 		Name:      "Arduino", | ||||
| 		Aliases:   []string{"arduino"}, | ||||
|  | @ -14,7 +14,11 @@ var Arduino = internal.Register(MustNewLexer( | |||
| 		MimeTypes: []string{"text/x-arduino"}, | ||||
| 		EnsureNL:  true, | ||||
| 	}, | ||||
| 	Rules{ | ||||
| 	arduinoRules, | ||||
| )) | ||||
| 
 | ||||
| func arduinoRules() Rules { | ||||
| 	return Rules{ | ||||
| 		"statements": { | ||||
| 			{Words(``, `\b`, `catch`, `const_cast`, `delete`, `dynamic_cast`, `explicit`, `export`, `friend`, `mutable`, `namespace`, `new`, `operator`, `private`, `protected`, `public`, `reinterpret_cast`, `restrict`, `static_cast`, `template`, `this`, `throw`, `throws`, `try`, `typeid`, `typename`, `using`, `virtual`, `constexpr`, `nullptr`, `decltype`, `thread_local`, `alignas`, `alignof`, `static_assert`, `noexcept`, `override`, `final`), Keyword, nil}, | ||||
| 			{`char(16_t|32_t)\b`, KeywordType, nil}, | ||||
|  | @ -106,5 +110,5 @@ var Arduino = internal.Register(MustNewLexer( | |||
| 			{`^\s*#endif.*?(?<!\\)\n`, CommentPreproc, Pop(1)}, | ||||
| 			{`.*?\n`, Comment, nil}, | ||||
| 		}, | ||||
| 	}, | ||||
| )) | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -6,14 +6,18 @@ import ( | |||
| ) | ||||
| 
 | ||||
| // Awk lexer.
 | ||||
| var Awk = internal.Register(MustNewLexer( | ||||
| var Awk = internal.Register(MustNewLazyLexer( | ||||
| 	&Config{ | ||||
| 		Name:      "Awk", | ||||
| 		Aliases:   []string{"awk", "gawk", "mawk", "nawk"}, | ||||
| 		Filenames: []string{"*.awk"}, | ||||
| 		MimeTypes: []string{"application/x-awk"}, | ||||
| 	}, | ||||
| 	Rules{ | ||||
| 	awkRules, | ||||
| )) | ||||
| 
 | ||||
| func awkRules() Rules { | ||||
| 	return Rules{ | ||||
| 		"commentsandwhitespace": { | ||||
| 			{`\s+`, Text, nil}, | ||||
| 			{`#.*$`, CommentSingle, nil}, | ||||
|  | @ -44,5 +48,5 @@ var Awk = internal.Register(MustNewLexer( | |||
| 			{`"(\\\\|\\"|[^"])*"`, LiteralStringDouble, nil}, | ||||
| 			{`'(\\\\|\\'|[^'])*'`, LiteralStringSingle, nil}, | ||||
| 		}, | ||||
| 	}, | ||||
| )) | ||||
| 	} | ||||
| } | ||||
|  |  | |||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
		Reference in New Issue