mirror of
				https://gitea.com/gitea/tea.git
				synced 2025-10-31 09:15:26 +01:00 
			
		
		
		
	Update Dependencies (#390)
Co-authored-by: Norwin Roosen <git@nroo.de> Co-authored-by: Norwin <git@nroo.de> Reviewed-on: https://gitea.com/gitea/tea/pulls/390 Reviewed-by: 6543 <6543@obermui.de> Reviewed-by: Andrew Thornton <art27@cantab.net> Co-authored-by: Norwin <noerw@noreply.gitea.io> Co-committed-by: Norwin <noerw@noreply.gitea.io>
This commit is contained in:
		
							
								
								
									
										43
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										43
									
								
								go.mod
									
									
									
									
									
								
							| @@ -6,34 +6,35 @@ require ( | |||||||
| 	code.gitea.io/gitea-vet v0.2.1 | 	code.gitea.io/gitea-vet v0.2.1 | ||||||
| 	code.gitea.io/sdk/gitea v0.15.0 | 	code.gitea.io/sdk/gitea v0.15.0 | ||||||
| 	gitea.com/noerw/unidiff-comments v0.0.0-20201219085024-64aec5658f2b | 	gitea.com/noerw/unidiff-comments v0.0.0-20201219085024-64aec5658f2b | ||||||
| 	github.com/AlecAivazis/survey/v2 v2.2.8 | 	github.com/AlecAivazis/survey/v2 v2.3.1 | ||||||
| 	github.com/Microsoft/go-winio v0.4.16 // indirect | 	github.com/ProtonMail/go-crypto v0.0.0-20210707164159-52430bf6b52c // indirect | ||||||
| 	github.com/adrg/xdg v0.3.1 | 	github.com/adrg/xdg v0.3.3 | ||||||
| 	github.com/araddon/dateparse v0.0.0-20210207001429-0eec95c9db7e | 	github.com/alecthomas/chroma v0.9.2 // indirect | ||||||
| 	github.com/charmbracelet/glamour v0.2.0 | 	github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de | ||||||
| 	github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect | 	github.com/charmbracelet/glamour v0.3.0 | ||||||
| 	github.com/go-git/go-git/v5 v5.2.0 | 	github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect | ||||||
|  | 	github.com/go-git/go-git/v5 v5.4.2 | ||||||
| 	github.com/hashicorp/go-version v1.3.0 // indirect | 	github.com/hashicorp/go-version v1.3.0 // indirect | ||||||
| 	github.com/imdario/mergo v0.3.11 // indirect | 	github.com/kevinburke/ssh_config v1.1.0 // indirect | ||||||
| 	github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect |  | ||||||
| 	github.com/lucasb-eyer/go-colorful v1.2.0 // indirect |  | ||||||
| 	github.com/mattn/go-colorable v0.1.8 // indirect | 	github.com/mattn/go-colorable v0.1.8 // indirect | ||||||
| 	github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect | 	github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect | ||||||
| 	github.com/muesli/termenv v0.7.4 | 	github.com/microcosm-cc/bluemonday v1.0.15 // indirect | ||||||
|  | 	github.com/muesli/reflow v0.3.0 // indirect | ||||||
|  | 	github.com/muesli/termenv v0.9.0 | ||||||
| 	github.com/olekukonko/tablewriter v0.0.5 | 	github.com/olekukonko/tablewriter v0.0.5 | ||||||
| 	github.com/rivo/uniseg v0.2.0 // indirect | 	github.com/sergi/go-diff v1.2.0 // indirect | ||||||
| 	github.com/russross/blackfriday/v2 v2.1.0 // indirect |  | ||||||
| 	github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 | 	github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 | ||||||
| 	github.com/stretchr/testify v1.7.0 | 	github.com/stretchr/testify v1.7.0 | ||||||
| 	github.com/urfave/cli/v2 v2.3.0 | 	github.com/urfave/cli/v2 v2.3.0 | ||||||
| 	github.com/xanzy/ssh-agent v0.3.0 // indirect | 	github.com/xanzy/ssh-agent v0.3.1 // indirect | ||||||
| 	golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 | 	github.com/yuin/goldmark v1.4.0 // indirect | ||||||
| 	golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 // indirect | 	golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 | ||||||
| 	golang.org/x/sys v0.0.0-20210305034016-7844c3c200c3 // indirect | 	golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d // indirect | ||||||
| 	golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d // indirect | 	golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf // indirect | ||||||
| 	golang.org/x/text v0.3.5 // indirect | 	golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b // indirect | ||||||
| 	golang.org/x/tools v0.1.0 // indirect | 	golang.org/x/text v0.3.7 // indirect | ||||||
|  | 	golang.org/x/tools v0.1.5 // indirect | ||||||
| 	gopkg.in/yaml.v2 v2.4.0 | 	gopkg.in/yaml.v2 v2.4.0 | ||||||
| ) | ) | ||||||
|  |  | ||||||
| replace github.com/charmbracelet/glamour => github.com/noerw/glamour v0.2.1-0.20210305125354-f0a29f1de0c2 | replace github.com/charmbracelet/glamour => github.com/noerw/glamour v0.3.0-patch | ||||||
|   | |||||||
							
								
								
									
										169
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										169
									
								
								go.sum
									
									
									
									
									
								
							| @@ -4,22 +4,27 @@ code.gitea.io/sdk/gitea v0.15.0 h1:tsNhxDM/2N1Ohv1Xq5UWrht/esg0WmtRj4wsHVHriTg= | |||||||
| code.gitea.io/sdk/gitea v0.15.0/go.mod h1:klY2LVI3s3NChzIk/MzMn7G1FHrfU7qd63iSMVoHRBA= | code.gitea.io/sdk/gitea v0.15.0/go.mod h1:klY2LVI3s3NChzIk/MzMn7G1FHrfU7qd63iSMVoHRBA= | ||||||
| gitea.com/noerw/unidiff-comments v0.0.0-20201219085024-64aec5658f2b h1:CLYsMGcGLohESQDMth+RgJ4cB3CCHToxnj0zBbvB3sE= | gitea.com/noerw/unidiff-comments v0.0.0-20201219085024-64aec5658f2b h1:CLYsMGcGLohESQDMth+RgJ4cB3CCHToxnj0zBbvB3sE= | ||||||
| gitea.com/noerw/unidiff-comments v0.0.0-20201219085024-64aec5658f2b/go.mod h1:Fc8iyPm4NINRWujeIk2bTfcbGc4ZYY29/oMAAGcr4qI= | gitea.com/noerw/unidiff-comments v0.0.0-20201219085024-64aec5658f2b/go.mod h1:Fc8iyPm4NINRWujeIk2bTfcbGc4ZYY29/oMAAGcr4qI= | ||||||
| github.com/AlecAivazis/survey/v2 v2.2.8 h1:TgxCwybKdBckmC+/P9/5h49rw/nAHe/itZL0dgHs+Q0= | github.com/AlecAivazis/survey/v2 v2.3.1 h1:lzkuHA60pER7L4eYL8qQJor4bUWlJe4V0gqAT19tdOA= | ||||||
| github.com/AlecAivazis/survey/v2 v2.2.8/go.mod h1:9DYvHgXtiXm6nCn+jXnOXLKbH+Yo9u8fAS/SduGdoPk= | github.com/AlecAivazis/survey/v2 v2.3.1/go.mod h1:TH2kPCDU3Kqq7pLbnCWwZXDBjnhZtmsCle5EiYDJ2fg= | ||||||
| github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= | ||||||
| github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= | github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= | ||||||
| github.com/Microsoft/go-winio v0.4.16 h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/cFDk= |  | ||||||
| github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= | github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= | ||||||
|  | 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/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8 h1:xzYJEypr/85nBpB11F9br+3HUrpgb+fcm5iADzXXYEw= | github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8 h1:xzYJEypr/85nBpB11F9br+3HUrpgb+fcm5iADzXXYEw= | ||||||
| github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc= | github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc= | ||||||
| github.com/adrg/xdg v0.3.1 h1:uIyL9BYfXaFgDyVRKE8wjtm6ETQULweQqTofphEFJYY= | github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= | ||||||
| github.com/adrg/xdg v0.3.1/go.mod h1:7I2hH/IT30IsupOpKZ5ue7/qNi3CoKzD6tL3HwpaRMQ= | github.com/ProtonMail/go-crypto v0.0.0-20210707164159-52430bf6b52c h1:FP7mMdsXy0ybzar1sJeIcZtaJka0U/ZmLTW4wRpolYk= | ||||||
| github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs= | github.com/ProtonMail/go-crypto v0.0.0-20210707164159-52430bf6b52c/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= | ||||||
| github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= | 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/adrg/xdg v0.3.3 h1:s/tV7MdqQnzB1nKY8aqHvAMD+uCiuEDzVB5HLRY849U= | ||||||
|  | github.com/adrg/xdg v0.3.3/go.mod h1:61xAR2VZcggl2St4O9ohF5qCKe08+JDmE4VNzPFQvOQ= | ||||||
| github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38 h1:smF2tmSOzy2Mm+0dGI2AIUHY+w0BUc+4tn40djz7+6U= | 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/assert v0.0.0-20170929043011-405dbfeb8e38/go.mod h1:r7bzyVFMNntcxPZXK3/+KdruV1H5KSlyVY0gc+NgInI= | ||||||
| github.com/alecthomas/chroma v0.8.1 h1:ym20sbvyC6RXz45u4qDglcgr8E313oPROshcuCHqiEE= | github.com/alecthomas/chroma v0.8.2/go.mod h1:sko8vR34/90zvl5QdcUdvzL3J8NKjAUx9va9jPuFNoM= | ||||||
| github.com/alecthomas/chroma v0.8.1/go.mod h1:sko8vR34/90zvl5QdcUdvzL3J8NKjAUx9va9jPuFNoM= | github.com/alecthomas/chroma v0.9.2 h1:yU1sE2+TZbLIQPMk30SolL2Hn53SR/Pv750f7qZ/XMs= | ||||||
|  | github.com/alecthomas/chroma v0.9.2/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 h1:JHZL0hZKJ1VENNfmXvHbgYlbUOvpzYzvy2aZU5gXVeo= | ||||||
| github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721/go.mod h1:QO9JBoKquHd+jz9nshCh40fOfO+JzsoXy8qTHF68zU0= | github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721/go.mod h1:QO9JBoKquHd+jz9nshCh40fOfO+JzsoXy8qTHF68zU0= | ||||||
| github.com/alecthomas/kong v0.2.4/go.mod h1:kQOmtJgV+Lb4aj+I2LEn40cbtawdWJ9Y8QLq+lElKxE= | github.com/alecthomas/kong v0.2.4/go.mod h1:kQOmtJgV+Lb4aj+I2LEn40cbtawdWJ9Y8QLq+lElKxE= | ||||||
| @@ -27,25 +32,25 @@ github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897 h1:p9Sln00KOTlrYkx | |||||||
| github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ= | github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ= | ||||||
| github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA= | github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA= | ||||||
| github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= | github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= | ||||||
| github.com/araddon/dateparse v0.0.0-20210207001429-0eec95c9db7e h1:OjdSMCht0ZVX7IH0nTdf00xEustvbtUGRgMh3gbdmOg= | github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de h1:FxWPpzIjnTlhPwqqXc4/vE0f7GvRjuAsbW+HOIe8KnA= | ||||||
| github.com/araddon/dateparse v0.0.0-20210207001429-0eec95c9db7e/go.mod h1:DCaWoUhZrYW9p1lxo/cm8EmUOOzAPSEZNGF2DK1dJgw= | github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de/go.mod h1:DCaWoUhZrYW9p1lxo/cm8EmUOOzAPSEZNGF2DK1dJgw= | ||||||
| github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= | 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/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= | ||||||
|  | github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= | ||||||
| github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= | 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/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= | ||||||
| github.com/chris-ramon/douceur v0.2.0 h1:IDMEdxlEUUBYBKE4z/mJnFyVXox+MjuEVDJNN27glkU= |  | ||||||
| github.com/chris-ramon/douceur v0.2.0/go.mod h1:wDW5xjJdeoMm1mRt4sD4c/LbF/mWdEpRXQKjTR8nIBE= |  | ||||||
| github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= | github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= | ||||||
| github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM= | github.com/cpuguy83/go-md2man/v2 v2.0.1 h1:r/myEWzV9lfsM1tFLgDyu0atFtJ1fXn261LKYj/3DxU= | ||||||
| github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= | github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= | ||||||
| github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= | github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= | ||||||
| github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 h1:y5HC9v93H5EPKqaS1UYVg1uYah5Xf51mBfIoWehClUQ= | 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/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.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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||||||
| github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | 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.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/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= | github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= | ||||||
| github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= | github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= | ||||||
| github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ= | github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ= | ||||||
| @@ -54,12 +59,13 @@ github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0= | |||||||
| github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= | github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= | ||||||
| github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= | 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/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= | ||||||
| github.com/go-git/go-billy/v5 v5.0.0 h1:7NQHvd9FVid8VL4qVUMm8XifBK+2xCoZ2lSk0agRrHM= | github.com/go-git/go-billy/v5 v5.2.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= | ||||||
| github.com/go-git/go-billy/v5 v5.0.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-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12 h1:PbKy9zOy4aAKrJ5pibIRpVO2BXnK1Tlcg+caKI7Ox5M= | 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.0.2-0.20200613231340-f56387b50c12/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw= | github.com/go-git/go-git-fixtures/v4 v4.2.1 h1:n9gGL1Ct/yIw+nfsfr8s4+sbhT+Ncu2SubfXjIWgci8= | ||||||
| github.com/go-git/go-git/v5 v5.2.0 h1:YPBLG/3UK1we1ohRkncLjaXWLW+HKp5QNM/jTli2JgI= | 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.2.0/go.mod h1:kh02eMX+wdqqxgNMEyq8YgwlIOsDOa9homkUq1PoTMs= | 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/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= | github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= | ||||||
| github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= | ||||||
| github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= | github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= | ||||||
| @@ -69,55 +75,60 @@ github.com/hashicorp/go-version v1.3.0 h1:McDWVJIU/y+u1BRV06dPaLfLCaT7fUTJLp5r04 | |||||||
| github.com/hashicorp/go-version v1.3.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= | github.com/hashicorp/go-version v1.3.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= | ||||||
| github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174 h1:WlZsjVhE8Af9IcZDGgJGQpNflI3+MJSBhsgT5PCtzBQ= | github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174 h1:WlZsjVhE8Af9IcZDGgJGQpNflI3+MJSBhsgT5PCtzBQ= | ||||||
| github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A= | github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A= | ||||||
| github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= | github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= | ||||||
| github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA= | github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= | ||||||
| github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= |  | ||||||
| github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= | 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/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/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= | ||||||
| github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= | github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= | ||||||
| github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= | github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= | ||||||
| github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= |  | ||||||
| github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 h1:DowS9hvgyYSX4TO5NpyC606/Z4SxnNYbT+WX27or6Ck= |  | ||||||
| github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= | github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= | ||||||
|  | github.com/kevinburke/ssh_config v1.1.0 h1:pH/t1WS9NzT8go394IqZeJTMHVm6Cr6ZJ6AQ+mdNo/o= | ||||||
|  | github.com/kevinburke/ssh_config v1.1.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= | ||||||
| github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= | ||||||
| github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= | ||||||
|  | github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= | ||||||
|  | github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= | ||||||
| github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= | ||||||
| github.com/kr/pty v1.1.4 h1:5Myjjh3JY/NaAi4IsUbHADytDyl1VE1Y9PXDlL+P/VQ= | github.com/kr/pty v1.1.4 h1:5Myjjh3JY/NaAi4IsUbHADytDyl1VE1Y9PXDlL+P/VQ= | ||||||
| github.com/kr/pty v1.1.4/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= | github.com/kr/pty v1.1.4/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= | ||||||
| github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= | ||||||
| github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= | ||||||
| github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= | ||||||
| github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= |  | ||||||
| github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= | github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= | ||||||
| github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= | github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= | ||||||
|  | github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A= | ||||||
|  | github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= | ||||||
| github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= | github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= | ||||||
| github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= | github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= | ||||||
| github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= | github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= | ||||||
| github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= | github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= | ||||||
| github.com/mattn/go-isatty v0.0.8/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.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= |  | ||||||
| github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= | ||||||
| github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= | 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.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= | ||||||
| github.com/mattn/go-runewidth v0.0.10 h1:CoZ3S2P7pvtP45xOtBw+/mDL2z0RKI576gSkzRRpdGg= |  | ||||||
| github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= | github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= | ||||||
|  | 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/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= | github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= | ||||||
| github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI= | github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI= | ||||||
| github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= | github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= | ||||||
| github.com/microcosm-cc/bluemonday v1.0.4 h1:p0L+CTpo/PLFdkoPcJemLXG+fpMD7pYOoDEq1axMbGg= | github.com/microcosm-cc/bluemonday v1.0.6/go.mod h1:HOT/6NaBlR0f9XlxD3zolN6Z3N8Lp4pvhp+jLS5ihnI= | ||||||
| github.com/microcosm-cc/bluemonday v1.0.4/go.mod h1:8iwZnFn2CDDNZ0r6UXhF4xawGvzaqzCRa1n3/lO3W2w= | github.com/microcosm-cc/bluemonday v1.0.15 h1:J4uN+qPng9rvkBZBoBb8YGR+ijuklIMpSOZZLjYpbeY= | ||||||
|  | github.com/microcosm-cc/bluemonday v1.0.15/go.mod h1:ZLvAzeakRwrGnzQEvstVzVt3ZpqOF2+sdFr0Om+ce30= | ||||||
| github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= | github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= | ||||||
| github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= | github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= | ||||||
| github.com/muesli/reflow v0.2.0 h1:2o0UBJPHHH4fa2GCXU4Rg4DwOtWPMekCeyc5EWbAQp0= |  | ||||||
| github.com/muesli/reflow v0.2.0/go.mod h1:qT22vjVmM9MIUeLgsVYe/Ye7eZlbv9dZjL3dVhUqLX8= | github.com/muesli/reflow v0.2.0/go.mod h1:qT22vjVmM9MIUeLgsVYe/Ye7eZlbv9dZjL3dVhUqLX8= | ||||||
| github.com/muesli/termenv v0.7.4 h1:/pBqvU5CpkY53tU0vVn+xgs2ZTX63aH5nY+SSps5Xa8= | github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= | ||||||
| github.com/muesli/termenv v0.7.4/go.mod h1:pZ7qY9l3F7e5xsAOS0zCew2tME+p7bWeBkotCEcIIcc= | github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8= | ||||||
| github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= | github.com/muesli/termenv v0.8.1/go.mod h1:kzt/D/4a88RoheZmwfqorY3A+tnsSMA9HJC/fQSFKo0= | ||||||
|  | github.com/muesli/termenv v0.9.0 h1:wnbOaGz+LUR3jNT0zOzinPnyDaCZUQRZj9GxK8eRVl8= | ||||||
|  | github.com/muesli/termenv v0.9.0/go.mod h1:R/LzAKf+suGs4IsO95y7+7DpFHO0KABgnZqtlyx2mBw= | ||||||
| github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= | github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= | ||||||
| github.com/noerw/glamour v0.2.1-0.20210305125354-f0a29f1de0c2 h1:ACjOTGUGi7rt3JQU9GIFFs8sueFGShy6GcGjQhMmKjs= | github.com/noerw/glamour v0.3.0-patch h1:yc3wdbUIySok6KYeX5BtWnlj+PvP1uYeCeTSwq2rtSw= | ||||||
| github.com/noerw/glamour v0.2.1-0.20210305125354-f0a29f1de0c2/go.mod h1:WIVFX8Y2VIK1Y/1qtXYL/Vvzqlcbo3VgVop9i2piPkE= | github.com/noerw/glamour v0.3.0-patch/go.mod h1:TzF0koPZhqq0YVBNL100cPHznAAjVj7fksX2RInwjGw= | ||||||
| github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA= |  | ||||||
| github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= | 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/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= | ||||||
| github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= | ||||||
| @@ -135,10 +146,12 @@ github.com/scylladb/termtables v0.0.0-20191203121021-c4c0b6d42ff4/go.mod h1:C1a7 | |||||||
| github.com/seletskiy/tplutil v0.0.0-20200921103632-f880f6245597 h1:nZY1S2jo+VtDrUfjO9XYI137O41hhRkxZNV5Fb5ixCA= | github.com/seletskiy/tplutil v0.0.0-20200921103632-f880f6245597 h1:nZY1S2jo+VtDrUfjO9XYI137O41hhRkxZNV5Fb5ixCA= | ||||||
| github.com/seletskiy/tplutil v0.0.0-20200921103632-f880f6245597/go.mod h1:F8CBHSOjnzjx9EeXyWJTAzJyVxN+Y8JH2WjLMn4utiw= | github.com/seletskiy/tplutil v0.0.0-20200921103632-f880f6245597/go.mod h1:F8CBHSOjnzjx9EeXyWJTAzJyVxN+Y8JH2WjLMn4utiw= | ||||||
| github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= | github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= | ||||||
| github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= |  | ||||||
| github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= | github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= | ||||||
|  | github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= | ||||||
|  | github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= | ||||||
| github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= | github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= | ||||||
| github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= | github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= | ||||||
|  | github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= | ||||||
| github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA= | github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA= | ||||||
| github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog= | github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog= | ||||||
| github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||||||
| @@ -147,74 +160,83 @@ github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf | |||||||
| github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= | ||||||
| github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= | ||||||
| github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= | ||||||
| github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= |  | ||||||
| github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= | ||||||
| github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | ||||||
| github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M= | github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M= | ||||||
| github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= | github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= | ||||||
| github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= |  | ||||||
| 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/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0= | ||||||
|  | github.com/xanzy/ssh-agent v0.3.1 h1:AmzO1SSWxw73zxFZPRwaMN1MohDw8UyHnmuxyceTEGo= | ||||||
|  | github.com/xanzy/ssh-agent v0.3.1/go.mod h1:QIE4lCeL7nkC25x+yA3LBIYfwCc1TFziCtG7cBAac6w= | ||||||
| github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= | github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= | ||||||
| github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= | github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= | ||||||
| github.com/yuin/goldmark v1.3.1 h1:eVwehsLsZlCJCwXyGLgg+Q4iFWE/eTIMG0e8waCmm/I= | github.com/yuin/goldmark v1.3.3/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= | ||||||
| github.com/yuin/goldmark v1.3.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= | github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= | ||||||
|  | github.com/yuin/goldmark v1.4.0 h1:OtISOGfH6sOWa1/qXqqAiOIAO6Z5J3AEAE18WAq6BiQ= | ||||||
|  | github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= | ||||||
| github.com/yuin/goldmark-emoji v1.0.1 h1:ctuWEyzGBwiucEqxzwe0SOYDXPAucOrE9NQC18Wa1os= | github.com/yuin/goldmark-emoji v1.0.1 h1:ctuWEyzGBwiucEqxzwe0SOYDXPAucOrE9NQC18Wa1os= | ||||||
| github.com/yuin/goldmark-emoji v1.0.1/go.mod h1:2w1E6FEWLcDQkoTE+7HU6QF1F6SLlNGjRIBbIZQFqkQ= | github.com/yuin/goldmark-emoji v1.0.1/go.mod h1:2w1E6FEWLcDQkoTE+7HU6QF1F6SLlNGjRIBbIZQFqkQ= | ||||||
| golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= | golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= | ||||||
| golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | ||||||
| golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | ||||||
| golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | ||||||
| golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= | golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= | ||||||
| golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= | golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= | ||||||
| golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 h1:/ZScEX8SfEmUGRHs0gxpqteO5nfNW6axyZbBdw9A12g= | golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= | ||||||
| golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= | golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ= | ||||||
|  | golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= | ||||||
| golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= | golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= | ||||||
| golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= | golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= | ||||||
| golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= | golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= | ||||||
| golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |  | ||||||
| golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | ||||||
| golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | ||||||
| golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | ||||||
| golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= |  | ||||||
| golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= |  | ||||||
| golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw= |  | ||||||
| golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= | 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-20210331212208-0fccb6fa2b5c/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= | ||||||
|  | golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= | ||||||
|  | golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= | ||||||
|  | golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d h1:LO7XpTYMwTqxjLcGWPijK3vRXg1aWdlNOVOHRq45d7c= | ||||||
|  | golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= | ||||||
| golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||||
| golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/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-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||||
| golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||||
| golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||||
| golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |  | ||||||
| golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||||
| golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||||
| golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||||
| golang.org/x/sys v0.0.0-20190530182044-ad28b68e88f1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |  | ||||||
| golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||||
| golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||||
| golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||||
| golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||||
| golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||||
| golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/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-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||||
| 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-20210305034016-7844c3c200c3 h1:RdE7htvBru4I4VZQofQjCZk5W9+aLNlSF5n0zgVwm8s= | golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||||
| golang.org/x/sys v0.0.0-20210305034016-7844c3c200c3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||||
| golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= | golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/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-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||||
|  | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||||
|  | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||||
|  | golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf h1:2ucpDCmfkl8Bd/FsLtiD653Wf96cW37s+iGx93zsu4k= | ||||||
|  | golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||||
| golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= | ||||||
| golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE= | golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY= | ||||||
| golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= | golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b h1:9zKuko04nR4gjZ4+DNjHqRlAJqbJETHwiNKDqTfOjfE= | ||||||
|  | golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= | ||||||
| golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | ||||||
| golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= |  | ||||||
| golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | ||||||
| golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ= | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | ||||||
| golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= | ||||||
|  | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= | ||||||
| golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/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-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= | ||||||
| golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= | golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= | ||||||
| golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY= | golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= | ||||||
| golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= | golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= | ||||||
| golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | 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-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||||||
| golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||||||
| @@ -222,8 +244,9 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1N | |||||||
| golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||||||
| gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||||||
| gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||||||
| gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= |  | ||||||
| gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | gopkg.in/check.v1 v1.0.0-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/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= | gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= | ||||||
| gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= | gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= | ||||||
| gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | ||||||
|   | |||||||
							
								
								
									
										12
									
								
								vendor/github.com/AlecAivazis/survey/v2/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										12
									
								
								vendor/github.com/AlecAivazis/survey/v2/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -3,7 +3,7 @@ | |||||||
| [](https://travis-ci.org/AlecAivazis/survey) | [](https://travis-ci.org/AlecAivazis/survey) | ||||||
| [](https://pkg.go.dev/github.com/AlecAivazis/survey/v2) | [](https://pkg.go.dev/github.com/AlecAivazis/survey/v2) | ||||||
|  |  | ||||||
| A library for building interactive prompts. | A library for building interactive and accessible prompts on terminals supporting ANSI escape sequences. | ||||||
|  |  | ||||||
| <img width="550" src="https://thumbs.gfycat.com/VillainousGraciousKouprey-size_restricted.gif"/> | <img width="550" src="https://thumbs.gfycat.com/VillainousGraciousKouprey-size_restricted.gif"/> | ||||||
|  |  | ||||||
| @@ -343,10 +343,12 @@ survey.AskOne(prompt, &color, survey.WithValidator(survey.Required)) | |||||||
| validators include: | validators include: | ||||||
|  |  | ||||||
| | name         | valid types    | description                                                      | notes                                                                                 | | | name         | valid types    | description                                                      | notes                                                                                 | | ||||||
| | ------------ | ----------- | ----------------------------------------------------------- | ------------------------------------------------------------------------------------- | | | ------------ | -------------- | ---------------------------------------------------------------- | ------------------------------------------------------------------------------------- | | ||||||
| | Required     | any            | Rejects zero values of the response type                         | Boolean values pass straight through since the zero value (false) is a valid response | | | Required     | any            | Rejects zero values of the response type                         | Boolean values pass straight through since the zero value (false) is a valid response | | ||||||
| | MinLength(n) | string         | Enforces that a response is at least the given length            |                                                                                       | | | MinLength(n) | string         | Enforces that a response is at least the given length            |                                                                                       | | ||||||
| | MaxLength(n) | string         | Enforces that a response is no longer than the given length      |                                                                                       | | | MaxLength(n) | string         | Enforces that a response is no longer than the given length      |                                                                                       | | ||||||
|  | | MaxItems(n)  | []OptionAnswer | Enforces that a response has no more selections of the indicated |                                                                                       | | ||||||
|  | | MinItems(n)  | []OptionAnswer | Enforces that a response has no less selections of the indicated |                                                                                       | | ||||||
|  |  | ||||||
| ## Help Text | ## Help Text | ||||||
|  |  | ||||||
| @@ -456,6 +458,12 @@ For some examples, you can see any of the tests in this repo. | |||||||
|  |  | ||||||
| ## FAQ | ## FAQ | ||||||
|  |  | ||||||
|  | ### What kinds of IO are supported by `survey`? | ||||||
|  |  | ||||||
|  | survey aims to support most terminal emulators; it expects support for ANSI escape sequences. | ||||||
|  | This means that reading from piped stdin or writing to piped stdout is **not supported**, | ||||||
|  | and likely to break your application in these situations. See [#337](https://github.com/AlecAivazis/survey/pull/337#issue-581351617) | ||||||
|  |  | ||||||
| ### Why isn't sending a SIGINT (aka. CTRL-C) signal working? | ### Why isn't sending a SIGINT (aka. CTRL-C) signal working? | ||||||
|  |  | ||||||
| When you send an interrupt signal to the process, it only interrupts the current prompt instead of the entire process. This manifests in a `github.com/AlecAivazis/survey/v2/terminal.InterruptErr` being returned from `Ask` and `AskOne`. If you want to stop the process, handle the returned error in your code: | When you send an interrupt signal to the process, it only interrupts the current prompt instead of the entire process. This manifests in a `github.com/AlecAivazis/survey/v2/terminal.InterruptErr` being returned from `Ask` and `AskOne`. If you want to stop the process, handle the returned error in your code: | ||||||
|   | |||||||
							
								
								
									
										8
									
								
								vendor/github.com/AlecAivazis/survey/v2/_tasks.hcl
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								vendor/github.com/AlecAivazis/survey/v2/_tasks.hcl
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,19 +1,19 @@ | |||||||
| task "install-deps" { | task "install-deps" { | ||||||
|     description = "Install all of package dependencies" |     description = "Install all of package dependencies" | ||||||
|     pipeline = [ |     pipeline = [ | ||||||
|         "go get {{.files}}", |         "go get -v {{.files}}", | ||||||
|     ] |     ] | ||||||
| } | } | ||||||
|  |  | ||||||
| task "tests" { | task "tests" { | ||||||
|     description = "Run the test suite" |     description = "Run the test suite" | ||||||
|     command = "go test {{.files}}" |     command = "go test -v {{.files}}" | ||||||
|     environment { |     environment = { | ||||||
|         GOFLAGS = "-mod=vendor" |         GOFLAGS = "-mod=vendor" | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| variables { | variables = { | ||||||
|     files = "$(go list -v ./... | grep -iEv \"tests|examples\")" |     files = "$(go list -v ./... | grep -iEv \"tests|examples\")" | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										6
									
								
								vendor/github.com/AlecAivazis/survey/v2/core/template.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								vendor/github.com/AlecAivazis/survey/v2/core/template.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -29,7 +29,7 @@ var TemplateFuncsNoColor = map[string]interface{}{ | |||||||
| //for colored output. The second string does not contain escape codes | //for colored output. The second string does not contain escape codes | ||||||
| //and can be used by the renderer for layout purposes. | //and can be used by the renderer for layout purposes. | ||||||
| func RunTemplate(tmpl string, data interface{}) (string, string, error) { | func RunTemplate(tmpl string, data interface{}) (string, string, error) { | ||||||
| 	tPair, err := getTemplatePair(tmpl) | 	tPair, err := GetTemplatePair(tmpl) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return "", "", err | 		return "", "", err | ||||||
| 	} | 	} | ||||||
| @@ -52,12 +52,12 @@ var ( | |||||||
| 	memoMutex = &sync.RWMutex{} | 	memoMutex = &sync.RWMutex{} | ||||||
| ) | ) | ||||||
|  |  | ||||||
| //getTemplatePair returns a pair of compiled templates where the | //GetTemplatePair returns a pair of compiled templates where the | ||||||
| //first template is generated for user-facing output and the | //first template is generated for user-facing output and the | ||||||
| //second is generated for use by the renderer. The second | //second is generated for use by the renderer. The second | ||||||
| //template does not contain any color escape codes, whereas | //template does not contain any color escape codes, whereas | ||||||
| //the first template may or may not depending on DisableColor. | //the first template may or may not depending on DisableColor. | ||||||
| func getTemplatePair(tmpl string) ([2]*template.Template, error) { | func GetTemplatePair(tmpl string) ([2]*template.Template, error) { | ||||||
| 	memoMutex.RLock() | 	memoMutex.RLock() | ||||||
| 	if t, ok := memoizedGetTemplate[tmpl]; ok { | 	if t, ok := memoizedGetTemplate[tmpl]; ok { | ||||||
| 		memoMutex.RUnlock() | 		memoMutex.RUnlock() | ||||||
|   | |||||||
							
								
								
									
										54
									
								
								vendor/github.com/AlecAivazis/survey/v2/core/write.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										54
									
								
								vendor/github.com/AlecAivazis/survey/v2/core/write.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -24,6 +24,11 @@ type OptionAnswer struct { | |||||||
| 	Index int | 	Index int | ||||||
| } | } | ||||||
|  |  | ||||||
|  | type reflectField struct { | ||||||
|  | 	value     reflect.Value | ||||||
|  | 	fieldType reflect.StructField | ||||||
|  | } | ||||||
|  |  | ||||||
| func OptionAnswerList(incoming []string) []OptionAnswer { | func OptionAnswerList(incoming []string) []OptionAnswer { | ||||||
| 	list := []OptionAnswer{} | 	list := []OptionAnswer{} | ||||||
| 	for i, opt := range incoming { | 	for i, opt := range incoming { | ||||||
| @@ -63,13 +68,12 @@ func WriteAnswer(t interface{}, name string, v interface{}) (err error) { | |||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		// get the name of the field that matches the string we  were given | 		// get the name of the field that matches the string we  were given | ||||||
| 		fieldIndex, err := findFieldIndex(elem, name) | 		field, _, err := findField(elem, name) | ||||||
| 		// if something went wrong | 		// if something went wrong | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			// bubble up | 			// bubble up | ||||||
| 			return err | 			return err | ||||||
| 		} | 		} | ||||||
| 		field := elem.Field(fieldIndex) |  | ||||||
| 		// handle references to the Settable interface aswell | 		// handle references to the Settable interface aswell | ||||||
| 		if s, ok := field.Interface().(Settable); ok { | 		if s, ok := field.Interface().(Settable); ok { | ||||||
| 			// use the interface method | 			// use the interface method | ||||||
| @@ -156,37 +160,51 @@ func IsFieldNotMatch(err error) (string, bool) { | |||||||
|  |  | ||||||
| // BUG(AlecAivazis): the current implementation might cause weird conflicts if there are | // BUG(AlecAivazis): the current implementation might cause weird conflicts if there are | ||||||
| // two fields with same name that only differ by casing. | // two fields with same name that only differ by casing. | ||||||
| func findFieldIndex(s reflect.Value, name string) (int, error) { | func findField(s reflect.Value, name string) (reflect.Value, reflect.StructField, error) { | ||||||
| 	// the type of the value |  | ||||||
| 	sType := s.Type() | 	fields := flattenFields(s) | ||||||
|  |  | ||||||
| 	// first look for matching tags so we can overwrite matching field names | 	// first look for matching tags so we can overwrite matching field names | ||||||
| 	for i := 0; i < sType.NumField(); i++ { | 	for _, f := range fields { | ||||||
| 		// the field we are current scanning |  | ||||||
| 		field := sType.Field(i) |  | ||||||
|  |  | ||||||
| 		// the value of the survey tag | 		// the value of the survey tag | ||||||
| 		tag := field.Tag.Get(tagName) | 		tag := f.fieldType.Tag.Get(tagName) | ||||||
| 		// if the tag matches the name we are looking for | 		// if the tag matches the name we are looking for | ||||||
| 		if tag != "" && tag == name { | 		if tag != "" && tag == name { | ||||||
| 			// then we found our index | 			// then we found our index | ||||||
| 			return i, nil | 			return f.value, f.fieldType, nil | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// then look for matching names | 	// then look for matching names | ||||||
| 	for i := 0; i < sType.NumField(); i++ { | 	for _, f := range fields { | ||||||
| 		// the field we are current scanning |  | ||||||
| 		field := sType.Field(i) |  | ||||||
|  |  | ||||||
| 		// if the name of the field matches what we're looking for | 		// if the name of the field matches what we're looking for | ||||||
| 		if strings.ToLower(field.Name) == strings.ToLower(name) { | 		if strings.ToLower(f.fieldType.Name) == strings.ToLower(name) { | ||||||
| 			return i, nil | 			return f.value, f.fieldType, nil | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// we didn't find the field | 	// we didn't find the field | ||||||
| 	return -1, errFieldNotMatch{name} | 	return reflect.Value{}, reflect.StructField{}, errFieldNotMatch{name} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func flattenFields(s reflect.Value) []reflectField { | ||||||
|  | 	sType := s.Type() | ||||||
|  | 	numField := sType.NumField() | ||||||
|  | 	fields := make([]reflectField, 0, numField) | ||||||
|  | 	for i := 0; i < numField; i++ { | ||||||
|  | 		fieldType := sType.Field(i) | ||||||
|  | 		field := s.Field(i) | ||||||
|  |  | ||||||
|  | 		if field.Kind() == reflect.Struct && fieldType.Anonymous { | ||||||
|  | 			// field is a promoted structure | ||||||
|  | 			for _, f := range flattenFields(field) { | ||||||
|  | 				fields = append(fields, f) | ||||||
|  | 			} | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		fields = append(fields, reflectField{field, fieldType}) | ||||||
|  | 	} | ||||||
|  | 	return fields | ||||||
| } | } | ||||||
|  |  | ||||||
| // isList returns true if the element is something we can Len() | // isList returns true if the element is something we can Len() | ||||||
|   | |||||||
							
								
								
									
										6
									
								
								vendor/github.com/AlecAivazis/survey/v2/go.mod
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								vendor/github.com/AlecAivazis/survey/v2/go.mod
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -11,9 +11,9 @@ require ( | |||||||
| 	github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b | 	github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b | ||||||
| 	github.com/pmezard/go-difflib v1.0.0 // indirect | 	github.com/pmezard/go-difflib v1.0.0 // indirect | ||||||
| 	github.com/stretchr/testify v1.2.1 | 	github.com/stretchr/testify v1.2.1 | ||||||
| 	golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5 | 	golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5 // indirect | ||||||
| 	golang.org/x/sys v0.0.0-20190530182044-ad28b68e88f1 // indirect | 	golang.org/x/term v0.0.0-20210503060354-a79de5458b56 | ||||||
| 	golang.org/x/text v0.3.0 | 	golang.org/x/text v0.3.3 | ||||||
| ) | ) | ||||||
|  |  | ||||||
| go 1.13 | go 1.13 | ||||||
|   | |||||||
							
								
								
									
										10
									
								
								vendor/github.com/AlecAivazis/survey/v2/go.sum
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								vendor/github.com/AlecAivazis/survey/v2/go.sum
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -25,7 +25,11 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn | |||||||
| golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||||
| golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||||
| golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||||
| golang.org/x/sys v0.0.0-20190530182044-ad28b68e88f1 h1:R4dVlxdmKenVdMRS/tTspEpSTRWINYrHD8ySIU9yCIU= | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw= | ||||||
| golang.org/x/sys v0.0.0-20190530182044-ad28b68e88f1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||||
| golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= | golang.org/x/term v0.0.0-20210503060354-a79de5458b56 h1:b8jxX3zqjpqb2LklXPzKSGJhzyxCOZSz8ncv8Nv+y7w= | ||||||
|  | golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY= | ||||||
| golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | ||||||
|  | golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= | ||||||
|  | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | ||||||
|  | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | ||||||
|   | |||||||
							
								
								
									
										89
									
								
								vendor/github.com/AlecAivazis/survey/v2/input.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										89
									
								
								vendor/github.com/AlecAivazis/survey/v2/input.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,6 +1,8 @@ | |||||||
| package survey | package survey | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
|  | 	"errors" | ||||||
|  |  | ||||||
| 	"github.com/AlecAivazis/survey/v2/core" | 	"github.com/AlecAivazis/survey/v2/core" | ||||||
| 	"github.com/AlecAivazis/survey/v2/terminal" | 	"github.com/AlecAivazis/survey/v2/terminal" | ||||||
| ) | ) | ||||||
| @@ -19,8 +21,8 @@ type Input struct { | |||||||
| 	Default       string | 	Default       string | ||||||
| 	Help          string | 	Help          string | ||||||
| 	Suggest       func(toComplete string) []string | 	Suggest       func(toComplete string) []string | ||||||
| 	typedAnswer   string |  | ||||||
| 	answer        string | 	answer        string | ||||||
|  | 	typedAnswer   string | ||||||
| 	options       []core.OptionAnswer | 	options       []core.OptionAnswer | ||||||
| 	selectedIndex int | 	selectedIndex int | ||||||
| 	showingHelp   bool | 	showingHelp   bool | ||||||
| @@ -58,24 +60,14 @@ var InputQuestionTemplate = ` | |||||||
|     {{- if and .Suggest }}{{color "cyan"}}{{ print .Config.SuggestInput }} for suggestions{{end -}} |     {{- if and .Suggest }}{{color "cyan"}}{{ print .Config.SuggestInput }} for suggestions{{end -}} | ||||||
|   ]{{color "reset"}} {{end}} |   ]{{color "reset"}} {{end}} | ||||||
|   {{- if .Default}}{{color "white"}}({{.Default}}) {{color "reset"}}{{end}} |   {{- if .Default}}{{color "white"}}({{.Default}}) {{color "reset"}}{{end}} | ||||||
|   {{- .Answer -}} |  | ||||||
| {{- end}}` | {{- end}}` | ||||||
|  |  | ||||||
| func (i *Input) OnChange(key rune, config *PromptConfig) (bool, error) { | func (i *Input) onRune(config *PromptConfig) terminal.OnRuneFn { | ||||||
| 	if key == terminal.KeyEnter || key == '\n' { | 	return terminal.OnRuneFn(func(key rune, line []rune) ([]rune, bool, error) { | ||||||
| 		if i.answer != config.HelpInput || i.Help == "" { | 		if i.options != nil && (key == terminal.KeyEnter || key == '\n') { | ||||||
| 			// we're done | 			return []rune(i.answer), true, nil | ||||||
| 			return true, nil | 		} else if i.options != nil && key == terminal.KeyEscape { | ||||||
| 		} else { |  | ||||||
| 			i.answer = "" |  | ||||||
| 			i.showingHelp = true |  | ||||||
| 		} |  | ||||||
| 	} else if key == terminal.KeyDeleteWord || key == terminal.KeyDeleteLine { |  | ||||||
| 		i.answer = "" |  | ||||||
| 	} else if key == terminal.KeyEscape && i.Suggest != nil { |  | ||||||
| 		if len(i.options) > 0 { |  | ||||||
| 			i.answer = i.typedAnswer | 			i.answer = i.typedAnswer | ||||||
| 		} |  | ||||||
| 			i.options = nil | 			i.options = nil | ||||||
| 		} else if key == terminal.KeyArrowUp && len(i.options) > 0 { | 		} else if key == terminal.KeyArrowUp && len(i.options) > 0 { | ||||||
| 			if i.selectedIndex == 0 { | 			if i.selectedIndex == 0 { | ||||||
| @@ -92,25 +84,31 @@ func (i *Input) OnChange(key rune, config *PromptConfig) (bool, error) { | |||||||
| 			} | 			} | ||||||
| 			i.answer = i.options[i.selectedIndex].Value | 			i.answer = i.options[i.selectedIndex].Value | ||||||
| 		} else if key == terminal.KeyTab && i.Suggest != nil { | 		} else if key == terminal.KeyTab && i.Suggest != nil { | ||||||
|  | 			i.answer = string(line) | ||||||
|  | 			i.typedAnswer = i.answer | ||||||
| 			options := i.Suggest(i.answer) | 			options := i.Suggest(i.answer) | ||||||
| 			i.selectedIndex = 0 | 			i.selectedIndex = 0 | ||||||
| 		i.typedAnswer = i.answer | 			if len(options) == 0 { | ||||||
| 		if len(options) > 0 { | 				return line, false, nil | ||||||
|  | 			} | ||||||
|  |  | ||||||
| 			i.answer = options[0] | 			i.answer = options[0] | ||||||
| 			if len(options) == 1 { | 			if len(options) == 1 { | ||||||
|  | 				i.typedAnswer = i.answer | ||||||
| 				i.options = nil | 				i.options = nil | ||||||
| 			} else { | 			} else { | ||||||
| 				i.options = core.OptionAnswerList(options) | 				i.options = core.OptionAnswerList(options) | ||||||
| 			} | 			} | ||||||
|  | 		} else { | ||||||
|  | 			if i.options == nil { | ||||||
|  | 				return line, false, nil | ||||||
| 			} | 			} | ||||||
| 	} else if key == terminal.KeyDelete || key == terminal.KeyBackspace { |  | ||||||
| 		if i.answer != "" { | 			if key >= terminal.KeySpace { | ||||||
| 			runeAnswer := []rune(i.answer) |  | ||||||
| 			i.answer = string(runeAnswer[0 : len(runeAnswer)-1]) |  | ||||||
| 		} |  | ||||||
| 	} else if key >= terminal.KeySpace { |  | ||||||
| 				i.answer += string(key) | 				i.answer += string(key) | ||||||
|  | 			} | ||||||
| 			i.typedAnswer = i.answer | 			i.typedAnswer = i.answer | ||||||
|  |  | ||||||
| 			i.options = nil | 			i.options = nil | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| @@ -128,9 +126,16 @@ func (i *Input) OnChange(key rune, config *PromptConfig) (bool, error) { | |||||||
| 			}, | 			}, | ||||||
| 		) | 		) | ||||||
|  |  | ||||||
| 	return err != nil, err | 		if err == nil { | ||||||
|  | 			err = readLineAgain | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		return []rune(i.typedAnswer), true, err | ||||||
|  | 	}) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | var readLineAgain = errors.New("read line again") | ||||||
|  |  | ||||||
| func (i *Input) Prompt(config *PromptConfig) (interface{}, error) { | func (i *Input) Prompt(config *PromptConfig) (interface{}, error) { | ||||||
| 	// render the template | 	// render the template | ||||||
| 	err := i.Render( | 	err := i.Render( | ||||||
| @@ -138,6 +143,7 @@ func (i *Input) Prompt(config *PromptConfig) (interface{}, error) { | |||||||
| 		InputTemplateData{ | 		InputTemplateData{ | ||||||
| 			Input:    *i, | 			Input:    *i, | ||||||
| 			Config:   config, | 			Config:   config, | ||||||
|  | 			ShowHelp: i.showingHelp, | ||||||
| 		}, | 		}, | ||||||
| 	) | 	) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| @@ -150,30 +156,39 @@ func (i *Input) Prompt(config *PromptConfig) (interface{}, error) { | |||||||
| 	defer rr.RestoreTermMode() | 	defer rr.RestoreTermMode() | ||||||
|  |  | ||||||
| 	cursor := i.NewCursor() | 	cursor := i.NewCursor() | ||||||
|  | 	if !config.ShowCursor { | ||||||
| 		cursor.Hide()       // hide the cursor | 		cursor.Hide()       // hide the cursor | ||||||
| 		defer cursor.Show() // show the cursor when we're done | 		defer cursor.Show() // show the cursor when we're done | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var line []rune | ||||||
|  |  | ||||||
| 	// start waiting for input |  | ||||||
| 	for { | 	for { | ||||||
| 		r, _, err := rr.ReadRune() | 		if i.options != nil { | ||||||
| 		if err != nil { | 			line = []rune{} | ||||||
| 			return "", err | 		} | ||||||
| 		} |  | ||||||
| 		if r == terminal.KeyInterrupt { | 		line, err = rr.ReadLineWithDefault(0, line, i.onRune(config)) | ||||||
| 			return "", terminal.InterruptErr | 		if err == readLineAgain { | ||||||
| 		} | 			continue | ||||||
| 		if r == terminal.KeyEndTransmission { |  | ||||||
| 			break |  | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		b, err := i.OnChange(r, config) |  | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return "", err | 			return "", err | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if b { |  | ||||||
| 		break | 		break | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	i.answer = string(line) | ||||||
|  | 	// readline print an empty line, go up before we render the follow up | ||||||
|  | 	cursor.Up(1) | ||||||
|  |  | ||||||
|  | 	// if we ran into the help string | ||||||
|  | 	if i.answer == config.HelpInput && i.Help != "" { | ||||||
|  | 		// show the help and prompt again | ||||||
|  | 		i.showingHelp = true | ||||||
|  | 		return i.Prompt(config) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// if the line is empty | 	// if the line is empty | ||||||
|   | |||||||
							
								
								
									
										47
									
								
								vendor/github.com/AlecAivazis/survey/v2/multiselect.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										47
									
								
								vendor/github.com/AlecAivazis/survey/v2/multiselect.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -45,9 +45,27 @@ type MultiSelectTemplateData struct { | |||||||
| 	ShowHelp      bool | 	ShowHelp      bool | ||||||
| 	PageEntries   []core.OptionAnswer | 	PageEntries   []core.OptionAnswer | ||||||
| 	Config        *PromptConfig | 	Config        *PromptConfig | ||||||
|  |  | ||||||
|  | 	// These fields are used when rendering an individual option | ||||||
|  | 	CurrentOpt   core.OptionAnswer | ||||||
|  | 	CurrentIndex int | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // IterateOption sets CurrentOpt and CurrentIndex appropriately so a multiselect option can be rendered individually | ||||||
|  | func (m MultiSelectTemplateData) IterateOption(ix int, opt core.OptionAnswer) interface{} { | ||||||
|  | 	copy := m | ||||||
|  | 	copy.CurrentIndex = ix | ||||||
|  | 	copy.CurrentOpt = opt | ||||||
|  | 	return copy | ||||||
| } | } | ||||||
|  |  | ||||||
| var MultiSelectQuestionTemplate = ` | var MultiSelectQuestionTemplate = ` | ||||||
|  | {{- define "option"}} | ||||||
|  |     {{- if eq .SelectedIndex .CurrentIndex }}{{color .Config.Icons.SelectFocus.Format }}{{ .Config.Icons.SelectFocus.Text }}{{color "reset"}}{{else}} {{end}} | ||||||
|  |     {{- if index .Checked .CurrentOpt.Index }}{{color .Config.Icons.MarkedOption.Format }} {{ .Config.Icons.MarkedOption.Text }} {{else}}{{color .Config.Icons.UnmarkedOption.Format }} {{ .Config.Icons.UnmarkedOption.Text }} {{end}} | ||||||
|  |     {{- color "reset"}} | ||||||
|  |     {{- " "}}{{- .CurrentOpt.Value}} | ||||||
|  | {{end}} | ||||||
| {{- if .ShowHelp }}{{- color .Config.Icons.Help.Format }}{{ .Config.Icons.Help.Text }} {{ .Help }}{{color "reset"}}{{"\n"}}{{end}} | {{- if .ShowHelp }}{{- color .Config.Icons.Help.Format }}{{ .Config.Icons.Help.Text }} {{ .Help }}{{color "reset"}}{{"\n"}}{{end}} | ||||||
| {{- color .Config.Icons.Question.Format }}{{ .Config.Icons.Question.Text }} {{color "reset"}} | {{- color .Config.Icons.Question.Format }}{{ .Config.Icons.Question.Text }} {{color "reset"}} | ||||||
| {{- color "default+hb"}}{{ .Message }}{{ .FilterMessage }}{{color "reset"}} | {{- color "default+hb"}}{{ .Message }}{{ .FilterMessage }}{{color "reset"}} | ||||||
| @@ -56,10 +74,7 @@ var MultiSelectQuestionTemplate = ` | |||||||
| 	{{- "  "}}{{- color "cyan"}}[Use arrows to move, space to select, <right> to all, <left> to none, type to filter{{- if and .Help (not .ShowHelp)}}, {{ .Config.HelpInput }} for more help{{end}}]{{color "reset"}} | 	{{- "  "}}{{- color "cyan"}}[Use arrows to move, space to select, <right> to all, <left> to none, type to filter{{- if and .Help (not .ShowHelp)}}, {{ .Config.HelpInput }} for more help{{end}}]{{color "reset"}} | ||||||
|   {{- "\n"}} |   {{- "\n"}} | ||||||
|   {{- range $ix, $option := .PageEntries}} |   {{- range $ix, $option := .PageEntries}} | ||||||
|     {{- if eq $ix $.SelectedIndex }}{{color $.Config.Icons.SelectFocus.Format }}{{ $.Config.Icons.SelectFocus.Text }}{{color "reset"}}{{else}} {{end}} |     {{- template "option" $.IterateOption $ix $option}} | ||||||
|     {{- if index $.Checked $option.Index }}{{color $.Config.Icons.MarkedOption.Format }} {{ $.Config.Icons.MarkedOption.Text }} {{else}}{{color $.Config.Icons.UnmarkedOption.Format }} {{ $.Config.Icons.UnmarkedOption.Text }} {{end}} |  | ||||||
|     {{- color "reset"}} |  | ||||||
|     {{- " "}}{{$option.Value}}{{"\n"}} |  | ||||||
|   {{- end}} |   {{- end}} | ||||||
| {{- end}}` | {{- end}}` | ||||||
|  |  | ||||||
| @@ -159,18 +174,17 @@ func (m *MultiSelect) OnChange(key rune, config *PromptConfig) { | |||||||
| 	// and we have modified the filter then we should move the page back! | 	// and we have modified the filter then we should move the page back! | ||||||
| 	opts, idx := paginate(pageSize, options, m.selectedIndex) | 	opts, idx := paginate(pageSize, options, m.selectedIndex) | ||||||
|  |  | ||||||
| 	// render the options | 	tmplData := MultiSelectTemplateData{ | ||||||
| 	m.Render( |  | ||||||
| 		MultiSelectQuestionTemplate, |  | ||||||
| 		MultiSelectTemplateData{ |  | ||||||
| 		MultiSelect:   *m, | 		MultiSelect:   *m, | ||||||
| 		SelectedIndex: idx, | 		SelectedIndex: idx, | ||||||
| 		Checked:       m.checked, | 		Checked:       m.checked, | ||||||
| 		ShowHelp:      m.showingHelp, | 		ShowHelp:      m.showingHelp, | ||||||
| 		PageEntries:   opts, | 		PageEntries:   opts, | ||||||
| 		Config:        config, | 		Config:        config, | ||||||
| 		}, | 	} | ||||||
| 	) |  | ||||||
|  | 	// render the options | ||||||
|  | 	m.RenderWithCursorOffset(MultiSelectQuestionTemplate, tmplData, opts, idx) | ||||||
| } | } | ||||||
|  |  | ||||||
| func (m *MultiSelect) filterOptions(config *PromptConfig) []core.OptionAnswer { | func (m *MultiSelect) filterOptions(config *PromptConfig) []core.OptionAnswer { | ||||||
| @@ -250,20 +264,21 @@ func (m *MultiSelect) Prompt(config *PromptConfig) (interface{}, error) { | |||||||
| 	opts, idx := paginate(pageSize, core.OptionAnswerList(m.Options), m.selectedIndex) | 	opts, idx := paginate(pageSize, core.OptionAnswerList(m.Options), m.selectedIndex) | ||||||
|  |  | ||||||
| 	cursor := m.NewCursor() | 	cursor := m.NewCursor() | ||||||
|  | 	cursor.Save()          // for proper cursor placement during selection | ||||||
| 	cursor.Hide()          // hide the cursor | 	cursor.Hide()          // hide the cursor | ||||||
| 	defer cursor.Show()    // show the cursor when we're done | 	defer cursor.Show()    // show the cursor when we're done | ||||||
|  | 	defer cursor.Restore() // clear any accessibility offsetting on exit | ||||||
|  |  | ||||||
| 	// ask the question | 	tmplData := MultiSelectTemplateData{ | ||||||
| 	err := m.Render( |  | ||||||
| 		MultiSelectQuestionTemplate, |  | ||||||
| 		MultiSelectTemplateData{ |  | ||||||
| 		MultiSelect:   *m, | 		MultiSelect:   *m, | ||||||
| 		SelectedIndex: idx, | 		SelectedIndex: idx, | ||||||
| 		Checked:       m.checked, | 		Checked:       m.checked, | ||||||
| 		PageEntries:   opts, | 		PageEntries:   opts, | ||||||
| 		Config:        config, | 		Config:        config, | ||||||
| 		}, | 	} | ||||||
| 	) |  | ||||||
|  | 	// ask the question | ||||||
|  | 	err := m.RenderWithCursorOffset(MultiSelectQuestionTemplate, tmplData, opts, idx) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return "", err | 		return "", err | ||||||
| 	} | 	} | ||||||
|   | |||||||
							
								
								
									
										38
									
								
								vendor/github.com/AlecAivazis/survey/v2/renderer.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										38
									
								
								vendor/github.com/AlecAivazis/survey/v2/renderer.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -7,7 +7,7 @@ import ( | |||||||
|  |  | ||||||
| 	"github.com/AlecAivazis/survey/v2/core" | 	"github.com/AlecAivazis/survey/v2/core" | ||||||
| 	"github.com/AlecAivazis/survey/v2/terminal" | 	"github.com/AlecAivazis/survey/v2/terminal" | ||||||
| 	goterm "golang.org/x/crypto/ssh/terminal" | 	"golang.org/x/term" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type Renderer struct { | type Renderer struct { | ||||||
| @@ -69,6 +69,14 @@ func (r *Renderer) Error(config *PromptConfig, invalid error) error { | |||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func (r *Renderer) OffsetCursor(offset int) { | ||||||
|  | 	cursor := r.NewCursor() | ||||||
|  | 	for offset > 0 { | ||||||
|  | 		cursor.PreviousLine(1) | ||||||
|  | 		offset-- | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
| func (r *Renderer) Render(tmpl string, data interface{}) error { | func (r *Renderer) Render(tmpl string, data interface{}) error { | ||||||
| 	// cleanup the currently rendered text | 	// cleanup the currently rendered text | ||||||
| 	lineCount := r.countLines(r.renderedText) | 	lineCount := r.countLines(r.renderedText) | ||||||
| @@ -91,6 +99,21 @@ func (r *Renderer) Render(tmpl string, data interface{}) error { | |||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func (r *Renderer) RenderWithCursorOffset(tmpl string, data IterableOpts, opts []core.OptionAnswer, idx int) error { | ||||||
|  | 	cursor := r.NewCursor() | ||||||
|  | 	cursor.Restore() // clear any accessibility offsetting | ||||||
|  |  | ||||||
|  | 	if err := r.Render(tmpl, data); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	cursor.Save() | ||||||
|  |  | ||||||
|  | 	offset := computeCursorOffset(MultiSelectQuestionTemplate, data, opts, idx, r.termWidthSafe()) | ||||||
|  | 	r.OffsetCursor(offset) | ||||||
|  |  | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
| // appendRenderedError appends text to the renderer's error buffer | // appendRenderedError appends text to the renderer's error buffer | ||||||
| // which is used to track what has been printed. It is not exported | // which is used to track what has been printed. It is not exported | ||||||
| // as errors should only be displayed via Error(config, error). | // as errors should only be displayed via Error(config, error). | ||||||
| @@ -119,19 +142,24 @@ func (r *Renderer) resetPrompt(lines int) { | |||||||
|  |  | ||||||
| func (r *Renderer) termWidth() (int, error) { | func (r *Renderer) termWidth() (int, error) { | ||||||
| 	fd := int(r.stdio.Out.Fd()) | 	fd := int(r.stdio.Out.Fd()) | ||||||
| 	termWidth, _, err := goterm.GetSize(fd) | 	termWidth, _, err := term.GetSize(fd) | ||||||
| 	return termWidth, err | 	return termWidth, err | ||||||
| } | } | ||||||
|  |  | ||||||
| // countLines will return the count of `\n` with the addition of any | func (r *Renderer) termWidthSafe() int { | ||||||
| // lines that have wrapped due to narrow terminal width |  | ||||||
| func (r *Renderer) countLines(buf bytes.Buffer) int { |  | ||||||
| 	w, err := r.termWidth() | 	w, err := r.termWidth() | ||||||
| 	if err != nil || w == 0 { | 	if err != nil || w == 0 { | ||||||
| 		// if we got an error due to terminal.GetSize not being supported | 		// if we got an error due to terminal.GetSize not being supported | ||||||
| 		// on current platform then just assume a very wide terminal | 		// on current platform then just assume a very wide terminal | ||||||
| 		w = 10000 | 		w = 10000 | ||||||
| 	} | 	} | ||||||
|  | 	return w | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // countLines will return the count of `\n` with the addition of any | ||||||
|  | // lines that have wrapped due to narrow terminal width | ||||||
|  | func (r *Renderer) countLines(buf bytes.Buffer) int { | ||||||
|  | 	w := r.termWidthSafe() | ||||||
|  |  | ||||||
| 	bufBytes := buf.Bytes() | 	bufBytes := buf.Bytes() | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										60
									
								
								vendor/github.com/AlecAivazis/survey/v2/select.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										60
									
								
								vendor/github.com/AlecAivazis/survey/v2/select.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -43,9 +43,26 @@ type SelectTemplateData struct { | |||||||
| 	ShowAnswer    bool | 	ShowAnswer    bool | ||||||
| 	ShowHelp      bool | 	ShowHelp      bool | ||||||
| 	Config        *PromptConfig | 	Config        *PromptConfig | ||||||
|  |  | ||||||
|  | 	// These fields are used when rendering an individual option | ||||||
|  | 	CurrentOpt   core.OptionAnswer | ||||||
|  | 	CurrentIndex int | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // IterateOption sets CurrentOpt and CurrentIndex appropriately so a select option can be rendered individually | ||||||
|  | func (s SelectTemplateData) IterateOption(ix int, opt core.OptionAnswer) interface{} { | ||||||
|  | 	copy := s | ||||||
|  | 	copy.CurrentIndex = ix | ||||||
|  | 	copy.CurrentOpt = opt | ||||||
|  | 	return copy | ||||||
| } | } | ||||||
|  |  | ||||||
| var SelectQuestionTemplate = ` | var SelectQuestionTemplate = ` | ||||||
|  | {{- define "option"}} | ||||||
|  |     {{- if eq .SelectedIndex .CurrentIndex }}{{color .Config.Icons.SelectFocus.Format }}{{ .Config.Icons.SelectFocus.Text }} {{else}}{{color "default"}}  {{end}} | ||||||
|  |     {{- .CurrentOpt.Value}} | ||||||
|  |     {{- color "reset"}} | ||||||
|  | {{end}} | ||||||
| {{- if .ShowHelp }}{{- color .Config.Icons.Help.Format }}{{ .Config.Icons.Help.Text }} {{ .Help }}{{color "reset"}}{{"\n"}}{{end}} | {{- if .ShowHelp }}{{- color .Config.Icons.Help.Format }}{{ .Config.Icons.Help.Text }} {{ .Help }}{{color "reset"}}{{"\n"}}{{end}} | ||||||
| {{- color .Config.Icons.Question.Format }}{{ .Config.Icons.Question.Text }} {{color "reset"}} | {{- color .Config.Icons.Question.Format }}{{ .Config.Icons.Question.Text }} {{color "reset"}} | ||||||
| {{- color "default+hb"}}{{ .Message }}{{ .FilterMessage }}{{color "reset"}} | {{- color "default+hb"}}{{ .Message }}{{ .FilterMessage }}{{color "reset"}} | ||||||
| @@ -53,10 +70,8 @@ var SelectQuestionTemplate = ` | |||||||
| {{- else}} | {{- else}} | ||||||
|   {{- "  "}}{{- color "cyan"}}[Use arrows to move, type to filter{{- if and .Help (not .ShowHelp)}}, {{ .Config.HelpInput }} for more help{{end}}]{{color "reset"}} |   {{- "  "}}{{- color "cyan"}}[Use arrows to move, type to filter{{- if and .Help (not .ShowHelp)}}, {{ .Config.HelpInput }} for more help{{end}}]{{color "reset"}} | ||||||
|   {{- "\n"}} |   {{- "\n"}} | ||||||
|   {{- range $ix, $choice := .PageEntries}} |   {{- range $ix, $option := .PageEntries}} | ||||||
|     {{- if eq $ix $.SelectedIndex }}{{color $.Config.Icons.SelectFocus.Format }}{{ $.Config.Icons.SelectFocus.Text }} {{else}}{{color "default"}}  {{end}} |     {{- template "option" $.IterateOption $ix $option}} | ||||||
|     {{- $choice.Value}} |  | ||||||
|     {{- color "reset"}}{{"\n"}} |  | ||||||
|   {{- end}} |   {{- end}} | ||||||
| {{- end}}` | {{- end}}` | ||||||
|  |  | ||||||
| @@ -152,17 +167,16 @@ func (s *Select) OnChange(key rune, config *PromptConfig) bool { | |||||||
| 	// and we have modified the filter then we should move the page back! | 	// and we have modified the filter then we should move the page back! | ||||||
| 	opts, idx := paginate(pageSize, options, s.selectedIndex) | 	opts, idx := paginate(pageSize, options, s.selectedIndex) | ||||||
|  |  | ||||||
| 	// render the options | 	tmplData := SelectTemplateData{ | ||||||
| 	s.Render( |  | ||||||
| 		SelectQuestionTemplate, |  | ||||||
| 		SelectTemplateData{ |  | ||||||
| 		Select:        *s, | 		Select:        *s, | ||||||
| 		SelectedIndex: idx, | 		SelectedIndex: idx, | ||||||
| 		ShowHelp:      s.showingHelp, | 		ShowHelp:      s.showingHelp, | ||||||
| 		PageEntries:   opts, | 		PageEntries:   opts, | ||||||
| 		Config:        config, | 		Config:        config, | ||||||
| 		}, | 	} | ||||||
| 	) |  | ||||||
|  | 	// render the options | ||||||
|  | 	s.RenderWithCursorOffset(SelectQuestionTemplate, tmplData, opts, idx) | ||||||
|  |  | ||||||
| 	// keep prompting | 	// keep prompting | ||||||
| 	return false | 	return false | ||||||
| @@ -234,16 +248,22 @@ func (s *Select) Prompt(config *PromptConfig) (interface{}, error) { | |||||||
| 	// figure out the options and index to render | 	// figure out the options and index to render | ||||||
| 	opts, idx := paginate(pageSize, core.OptionAnswerList(s.Options), sel) | 	opts, idx := paginate(pageSize, core.OptionAnswerList(s.Options), sel) | ||||||
|  |  | ||||||
| 	// ask the question | 	cursor := s.NewCursor() | ||||||
| 	err := s.Render( | 	cursor.Save()          // for proper cursor placement during selection | ||||||
| 		SelectQuestionTemplate, | 	cursor.Hide()          // hide the cursor | ||||||
| 		SelectTemplateData{ | 	defer cursor.Show()    // show the cursor when we're done | ||||||
|  | 	defer cursor.Restore() // clear any accessibility offsetting on exit | ||||||
|  |  | ||||||
|  | 	tmplData := SelectTemplateData{ | ||||||
| 		Select:        *s, | 		Select:        *s, | ||||||
| 			PageEntries:   opts, |  | ||||||
| 		SelectedIndex: idx, | 		SelectedIndex: idx, | ||||||
|  | 		ShowHelp:      s.showingHelp, | ||||||
|  | 		PageEntries:   opts, | ||||||
| 		Config:        config, | 		Config:        config, | ||||||
| 		}, | 	} | ||||||
| 	) |  | ||||||
|  | 	// ask the question | ||||||
|  | 	err := s.RenderWithCursorOffset(SelectQuestionTemplate, tmplData, opts, idx) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return "", err | 		return "", err | ||||||
| 	} | 	} | ||||||
| @@ -255,10 +275,6 @@ func (s *Select) Prompt(config *PromptConfig) (interface{}, error) { | |||||||
| 	rr.SetTermMode() | 	rr.SetTermMode() | ||||||
| 	defer rr.RestoreTermMode() | 	defer rr.RestoreTermMode() | ||||||
|  |  | ||||||
| 	cursor := s.NewCursor() |  | ||||||
| 	cursor.Hide()       // hide the cursor |  | ||||||
| 	defer cursor.Show() // show the cursor when we're done |  | ||||||
|  |  | ||||||
| 	// start waiting for input | 	// start waiting for input | ||||||
| 	for { | 	for { | ||||||
| 		r, _, err := rr.ReadRune() | 		r, _, err := rr.ReadRune() | ||||||
| @@ -317,6 +333,8 @@ func (s *Select) Prompt(config *PromptConfig) (interface{}, error) { | |||||||
| } | } | ||||||
|  |  | ||||||
| func (s *Select) Cleanup(config *PromptConfig, val interface{}) error { | func (s *Select) Cleanup(config *PromptConfig, val interface{}) error { | ||||||
|  | 	cursor := s.NewCursor() | ||||||
|  | 	cursor.Restore() | ||||||
| 	return s.Render( | 	return s.Render( | ||||||
| 		SelectQuestionTemplate, | 		SelectQuestionTemplate, | ||||||
| 		SelectTemplateData{ | 		SelectTemplateData{ | ||||||
|   | |||||||
							
								
								
									
										54
									
								
								vendor/github.com/AlecAivazis/survey/v2/survey.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										54
									
								
								vendor/github.com/AlecAivazis/survey/v2/survey.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,10 +1,12 @@ | |||||||
| package survey | package survey | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
|  | 	"bytes" | ||||||
| 	"errors" | 	"errors" | ||||||
| 	"io" | 	"io" | ||||||
| 	"os" | 	"os" | ||||||
| 	"strings" | 	"strings" | ||||||
|  | 	"unicode/utf8" | ||||||
|  |  | ||||||
| 	"github.com/AlecAivazis/survey/v2/core" | 	"github.com/AlecAivazis/survey/v2/core" | ||||||
| 	"github.com/AlecAivazis/survey/v2/terminal" | 	"github.com/AlecAivazis/survey/v2/terminal" | ||||||
| @@ -55,6 +57,7 @@ func defaultAskOptions() *AskOptions { | |||||||
| 				return strings.Contains(strings.ToLower(value), filter) | 				return strings.Contains(strings.ToLower(value), filter) | ||||||
| 			}, | 			}, | ||||||
| 			KeepFilter: false, | 			KeepFilter: false, | ||||||
|  | 			ShowCursor: false, | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| @@ -114,6 +117,7 @@ type PromptConfig struct { | |||||||
| 	SuggestInput string | 	SuggestInput string | ||||||
| 	Filter       func(filter string, option string, index int) bool | 	Filter       func(filter string, option string, index int) bool | ||||||
| 	KeepFilter   bool | 	KeepFilter   bool | ||||||
|  | 	ShowCursor   bool | ||||||
| } | } | ||||||
|  |  | ||||||
| // Prompt is the primary interface for the objects that can take user input | // Prompt is the primary interface for the objects that can take user input | ||||||
| @@ -219,6 +223,17 @@ func WithIcons(setIcons func(*IconSet)) AskOpt { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // WithShowCursor sets the show cursor behavior when prompting the user | ||||||
|  | func WithShowCursor(ShowCursor bool) AskOpt { | ||||||
|  | 	return func(options *AskOptions) error { | ||||||
|  | 		// set the page size | ||||||
|  | 		options.PromptConfig.ShowCursor = ShowCursor | ||||||
|  |  | ||||||
|  | 		// nothing went wrong | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
| /* | /* | ||||||
| AskOne performs the prompt for a single prompt and asks for validation if required. | AskOne performs the prompt for a single prompt and asks for validation if required. | ||||||
| Response types should be something that can be casted from the response type designated | Response types should be something that can be casted from the response type designated | ||||||
| @@ -398,3 +413,42 @@ func paginate(pageSize int, choices []core.OptionAnswer, sel int) ([]core.Option | |||||||
| 	// return the subset we care about and the index | 	// return the subset we care about and the index | ||||||
| 	return choices[start:end], cursor | 	return choices[start:end], cursor | ||||||
| } | } | ||||||
|  |  | ||||||
|  | type IterableOpts interface { | ||||||
|  | 	IterateOption(int, core.OptionAnswer) interface{} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func computeCursorOffset(tmpl string, data IterableOpts, opts []core.OptionAnswer, idx, tWidth int) int { | ||||||
|  | 	tmpls, err := core.GetTemplatePair(tmpl) | ||||||
|  |  | ||||||
|  | 	if err != nil { | ||||||
|  | 		return 0 | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	t := tmpls[0] | ||||||
|  |  | ||||||
|  | 	renderOpt := func(ix int, opt core.OptionAnswer) string { | ||||||
|  | 		buf := bytes.NewBufferString("") | ||||||
|  | 		t.ExecuteTemplate(buf, "option", data.IterateOption(ix, opt)) | ||||||
|  | 		return buf.String() | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	offset := len(opts) - idx | ||||||
|  |  | ||||||
|  | 	for i, o := range opts { | ||||||
|  | 		if i < idx { | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		renderedOpt := renderOpt(i, o) | ||||||
|  | 		valWidth := utf8.RuneCount([]byte(renderedOpt)) | ||||||
|  | 		if valWidth > tWidth { | ||||||
|  | 			splitCount := valWidth / tWidth | ||||||
|  | 			if valWidth%tWidth == 0 { | ||||||
|  | 				splitCount -= 1 | ||||||
|  | 			} | ||||||
|  | 			offset += splitCount | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return offset | ||||||
|  | } | ||||||
|   | |||||||
							
								
								
									
										10
									
								
								vendor/github.com/AlecAivazis/survey/v2/terminal/cursor.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								vendor/github.com/AlecAivazis/survey/v2/terminal/cursor.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -43,11 +43,13 @@ func (c *Cursor) Back(n int) { | |||||||
| // NextLine moves cursor to beginning of the line n lines down. | // NextLine moves cursor to beginning of the line n lines down. | ||||||
| func (c *Cursor) NextLine(n int) { | func (c *Cursor) NextLine(n int) { | ||||||
| 	c.Down(1) | 	c.Down(1) | ||||||
|  | 	c.HorizontalAbsolute(0) | ||||||
| } | } | ||||||
|  |  | ||||||
| // PreviousLine moves cursor to beginning of the line n lines up. | // PreviousLine moves cursor to beginning of the line n lines up. | ||||||
| func (c *Cursor) PreviousLine(n int) { | func (c *Cursor) PreviousLine(n int) { | ||||||
| 	c.Up(1) | 	c.Up(1) | ||||||
|  | 	c.HorizontalAbsolute(0) | ||||||
| } | } | ||||||
|  |  | ||||||
| // HorizontalAbsolute moves cursor horizontally to x. | // HorizontalAbsolute moves cursor horizontally to x. | ||||||
| @@ -167,8 +169,11 @@ func (c *Cursor) Size(buf *bytes.Buffer) (*Coord, error) { | |||||||
|  |  | ||||||
| 	// hide the cursor (so it doesn't blink when getting the size of the terminal) | 	// hide the cursor (so it doesn't blink when getting the size of the terminal) | ||||||
| 	c.Hide() | 	c.Hide() | ||||||
|  | 	defer c.Show() | ||||||
|  |  | ||||||
| 	// save the current location of the cursor | 	// save the current location of the cursor | ||||||
| 	c.Save() | 	c.Save() | ||||||
|  | 	defer c.Restore() | ||||||
|  |  | ||||||
| 	// move the cursor to the very bottom of the terminal | 	// move the cursor to the very bottom of the terminal | ||||||
| 	c.Move(999, 999) | 	c.Move(999, 999) | ||||||
| @@ -179,11 +184,6 @@ func (c *Cursor) Size(buf *bytes.Buffer) (*Coord, error) { | |||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// move back where we began |  | ||||||
| 	c.Restore() |  | ||||||
|  |  | ||||||
| 	// show the cursor |  | ||||||
| 	c.Show() |  | ||||||
| 	// since the bottom was calculated in the lower right corner, it | 	// since the bottom was calculated in the lower right corner, it | ||||||
| 	// is the dimensions we are looking for | 	// is the dimensions we are looking for | ||||||
| 	return bottom, nil | 	return bottom, nil | ||||||
|   | |||||||
							
								
								
									
										71
									
								
								vendor/github.com/AlecAivazis/survey/v2/terminal/runereader.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										71
									
								
								vendor/github.com/AlecAivazis/survey/v2/terminal/runereader.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -31,7 +31,13 @@ func (rr *RuneReader) printChar(char rune, mask rune) { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func (rr *RuneReader) ReadLine(mask rune) ([]rune, error) { | type OnRuneFn func(rune, []rune) ([]rune, bool, error) | ||||||
|  |  | ||||||
|  | func (rr *RuneReader) ReadLine(mask rune, onRunes ...OnRuneFn) ([]rune, error) { | ||||||
|  | 	return rr.ReadLineWithDefault(mask, []rune{}, onRunes...) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (rr *RuneReader) ReadLineWithDefault(mask rune, d []rune, onRunes ...OnRuneFn) ([]rune, error) { | ||||||
| 	line := []rune{} | 	line := []rune{} | ||||||
| 	// we only care about horizontal displacements from the origin so start counting at 0 | 	// we only care about horizontal displacements from the origin so start counting at 0 | ||||||
| 	index := 0 | 	index := 0 | ||||||
| @@ -41,19 +47,56 @@ func (rr *RuneReader) ReadLine(mask rune) ([]rune, error) { | |||||||
| 		Out: rr.stdio.Out, | 		Out: rr.stdio.Out, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	onRune := func(r rune, line []rune) ([]rune, bool, error) { | ||||||
|  | 		return line, false, nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// if the user pressed a key the caller was interested in capturing | ||||||
|  | 	if len(onRunes) > 0 { | ||||||
|  | 		onRune = onRunes[0] | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	// we get the terminal width and height (if resized after this point the property might become invalid) | 	// we get the terminal width and height (if resized after this point the property might become invalid) | ||||||
| 	terminalSize, _ := cursor.Size(rr.Buffer()) | 	terminalSize, _ := cursor.Size(rr.Buffer()) | ||||||
| 	// we set the current location of the cursor once | 	// we set the current location of the cursor once | ||||||
| 	cursorCurrent, _ := cursor.Location(rr.Buffer()) | 	cursorCurrent, _ := cursor.Location(rr.Buffer()) | ||||||
|  |  | ||||||
|  | 	increment := func() { | ||||||
|  | 		if cursorCurrent.CursorIsAtLineEnd(terminalSize) { | ||||||
|  | 			cursorCurrent.X = COORDINATE_SYSTEM_BEGIN | ||||||
|  | 			cursorCurrent.Y++ | ||||||
|  | 		} else { | ||||||
|  | 			cursorCurrent.X++ | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	decrement := func() { | ||||||
|  | 		if cursorCurrent.CursorIsAtLineBegin() { | ||||||
|  | 			cursorCurrent.X = terminalSize.X | ||||||
|  | 			cursorCurrent.Y-- | ||||||
|  | 		} else { | ||||||
|  | 			cursorCurrent.X-- | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if len(d) > 0 { | ||||||
|  | 		index = len(d) | ||||||
|  | 		fmt.Fprint(rr.stdio.Out, string(d)) | ||||||
|  | 		line = d | ||||||
|  | 		for range d { | ||||||
|  | 			increment() | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	for { | 	for { | ||||||
| 		// wait for some input | 		// wait for some input | ||||||
| 		r, _, err := rr.ReadRune() | 		r, _, err := rr.ReadRune() | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return line, err | 			return line, err | ||||||
| 		} | 		} | ||||||
| 		// increment cursor location |  | ||||||
| 		cursorCurrent.X++ | 		if l, stop, err := onRune(r, line); stop || err != nil { | ||||||
|  | 			return l, err | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		// if the user pressed enter or some other newline/termination like ctrl+d | 		// if the user pressed enter or some other newline/termination like ctrl+d | ||||||
| 		if r == '\r' || r == '\n' || r == KeyEndTransmission { | 		if r == '\r' || r == '\n' || r == KeyEndTransmission { | ||||||
| @@ -63,13 +106,10 @@ func (rr *RuneReader) ReadLine(mask rune) ([]rune, error) { | |||||||
| 					EraseLine(rr.stdio.Out, ERASE_LINE_END) | 					EraseLine(rr.stdio.Out, ERASE_LINE_END) | ||||||
| 					cursor.PreviousLine(1) | 					cursor.PreviousLine(1) | ||||||
| 					cursor.Forward(int(terminalSize.X)) | 					cursor.Forward(int(terminalSize.X)) | ||||||
| 					cursorCurrent.X = terminalSize.X |  | ||||||
| 					cursorCurrent.Y-- |  | ||||||
|  |  | ||||||
| 				} else { | 				} else { | ||||||
| 					cursor.Back(1) | 					cursor.Back(1) | ||||||
| 					cursorCurrent.X-- |  | ||||||
| 				} | 				} | ||||||
|  | 				decrement() | ||||||
| 				index-- | 				index-- | ||||||
| 			} | 			} | ||||||
| 			// move the cursor the a new line | 			// move the cursor the a new line | ||||||
| @@ -148,6 +188,7 @@ func (rr *RuneReader) ReadLine(mask rune) ([]rune, error) { | |||||||
|  |  | ||||||
| 				// decrement the index | 				// decrement the index | ||||||
| 				index-- | 				index-- | ||||||
|  | 				decrement() | ||||||
| 			} else { | 			} else { | ||||||
| 				// otherwise the user pressed backspace while at the beginning of the line | 				// otherwise the user pressed backspace while at the beginning of the line | ||||||
| 				soundBell(rr.stdio.Out) | 				soundBell(rr.stdio.Out) | ||||||
| @@ -170,6 +211,7 @@ func (rr *RuneReader) ReadLine(mask rune) ([]rune, error) { | |||||||
| 				} | 				} | ||||||
| 				//decrement the index | 				//decrement the index | ||||||
| 				index-- | 				index-- | ||||||
|  | 				decrement() | ||||||
|  |  | ||||||
| 			} else { | 			} else { | ||||||
| 				// otherwise we are at the beginning of where we started reading lines | 				// otherwise we are at the beginning of where we started reading lines | ||||||
| @@ -192,6 +234,7 @@ func (rr *RuneReader) ReadLine(mask rune) ([]rune, error) { | |||||||
| 					cursor.Forward(runeWidth(line[index])) | 					cursor.Forward(runeWidth(line[index])) | ||||||
| 				} | 				} | ||||||
| 				index++ | 				index++ | ||||||
|  | 				increment() | ||||||
|  |  | ||||||
| 			} else { | 			} else { | ||||||
| 				// otherwise we are at the end of the word and can't go past | 				// otherwise we are at the end of the word and can't go past | ||||||
| @@ -208,12 +251,11 @@ func (rr *RuneReader) ReadLine(mask rune) ([]rune, error) { | |||||||
| 				if cursorCurrent.CursorIsAtLineBegin() { | 				if cursorCurrent.CursorIsAtLineBegin() { | ||||||
| 					cursor.PreviousLine(1) | 					cursor.PreviousLine(1) | ||||||
| 					cursor.Forward(int(terminalSize.X)) | 					cursor.Forward(int(terminalSize.X)) | ||||||
| 					cursorCurrent.X = terminalSize.X |  | ||||||
| 					cursorCurrent.Y-- | 					cursorCurrent.Y-- | ||||||
|  | 					cursorCurrent.X = terminalSize.X | ||||||
| 				} else { | 				} else { | ||||||
| 					cursor.Back(runeWidth(line[index-1])) | 					cursor.Back(runeWidth(line[index-1])) | ||||||
| 					cursorCurrent.X-- | 					cursorCurrent.X -= Short(runeWidth(line[index-1])) | ||||||
| 				} | 				} | ||||||
| 				index-- | 				index-- | ||||||
| 			} | 			} | ||||||
| @@ -223,12 +265,11 @@ func (rr *RuneReader) ReadLine(mask rune) ([]rune, error) { | |||||||
| 			for index != len(line) { | 			for index != len(line) { | ||||||
| 				if cursorCurrent.CursorIsAtLineEnd(terminalSize) { | 				if cursorCurrent.CursorIsAtLineEnd(terminalSize) { | ||||||
| 					cursor.NextLine(1) | 					cursor.NextLine(1) | ||||||
| 					cursorCurrent.X = COORDINATE_SYSTEM_BEGIN |  | ||||||
| 					cursorCurrent.Y++ | 					cursorCurrent.Y++ | ||||||
|  | 					cursorCurrent.X = COORDINATE_SYSTEM_BEGIN | ||||||
| 				} else { | 				} else { | ||||||
| 					cursor.Forward(runeWidth(line[index])) | 					cursor.Forward(runeWidth(line[index])) | ||||||
| 					cursorCurrent.X++ | 					cursorCurrent.X += Short(runeWidth(line[index])) | ||||||
| 				} | 				} | ||||||
| 				index++ | 				index++ | ||||||
| 			} | 			} | ||||||
| @@ -277,6 +318,7 @@ func (rr *RuneReader) ReadLine(mask rune) ([]rune, error) { | |||||||
| 			line = append(line, r) | 			line = append(line, r) | ||||||
| 			// save the location of the cursor | 			// save the location of the cursor | ||||||
| 			index++ | 			index++ | ||||||
|  | 			increment() | ||||||
| 			// print out the character | 			// print out the character | ||||||
| 			rr.printChar(r, mask) | 			rr.printChar(r, mask) | ||||||
| 		} else { | 		} else { | ||||||
| @@ -293,7 +335,7 @@ func (rr *RuneReader) ReadLine(mask rune) ([]rune, error) { | |||||||
| 				EraseLine(rr.stdio.Out, ERASE_LINE_END) | 				EraseLine(rr.stdio.Out, ERASE_LINE_END) | ||||||
| 				// print out the character | 				// print out the character | ||||||
| 				rr.printChar(char, mask) | 				rr.printChar(char, mask) | ||||||
| 				cursorCurrent.X++ | 				increment() | ||||||
| 			} | 			} | ||||||
| 			// if we are at the last line, we want to visually insert a new line and append to it. | 			// if we are at the last line, we want to visually insert a new line and append to it. | ||||||
| 			if cursorCurrent.CursorIsAtLineEnd(terminalSize) && cursorCurrent.Y == terminalSize.Y { | 			if cursorCurrent.CursorIsAtLineEnd(terminalSize) && cursorCurrent.Y == terminalSize.Y { | ||||||
| @@ -316,6 +358,7 @@ func (rr *RuneReader) ReadLine(mask rune) ([]rune, error) { | |||||||
| 			} | 			} | ||||||
| 			// increment the index | 			// increment the index | ||||||
| 			index++ | 			index++ | ||||||
|  | 			increment() | ||||||
|  |  | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|   | |||||||
							
								
								
									
										40
									
								
								vendor/github.com/AlecAivazis/survey/v2/validate.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										40
									
								
								vendor/github.com/AlecAivazis/survey/v2/validate.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -4,6 +4,8 @@ import ( | |||||||
| 	"errors" | 	"errors" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"reflect" | 	"reflect" | ||||||
|  |  | ||||||
|  | 	"github.com/AlecAivazis/survey/v2/core" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // Required does not allow an empty value | // Required does not allow an empty value | ||||||
| @@ -58,6 +60,44 @@ func MinLength(length int) Validator { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // MaxItems requires that the list is no longer than the specified value | ||||||
|  | func MaxItems(numberItems int) Validator { | ||||||
|  | 	// return a validator that checks the length of the list | ||||||
|  | 	return func(val interface{}) error { | ||||||
|  | 		if list, ok := val.([]core.OptionAnswer); ok { | ||||||
|  | 			// if the list is longer than the given value | ||||||
|  | 			if len(list) > numberItems { | ||||||
|  | 				// yell loudly | ||||||
|  | 				return fmt.Errorf("value is too long. Max items is %v", numberItems) | ||||||
|  | 			} | ||||||
|  | 		} else { | ||||||
|  | 			// otherwise we cannot convert the value into a list of answer and cannot enforce length | ||||||
|  | 			return fmt.Errorf("cannot impose the length on something other than a list of answers") | ||||||
|  | 		} | ||||||
|  | 		// the input is fine | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // MinItems requires that the list is longer or equal in length to the specified value | ||||||
|  | func MinItems(numberItems int) Validator { | ||||||
|  | 	// return a validator that checks the length of the list | ||||||
|  | 	return func(val interface{}) error { | ||||||
|  | 		if list, ok := val.([]core.OptionAnswer); ok { | ||||||
|  | 			// if the list is shorter than the given value | ||||||
|  | 			if len(list) < numberItems { | ||||||
|  | 				// yell loudly | ||||||
|  | 				return fmt.Errorf("value is too long. Min items is %v", numberItems) | ||||||
|  | 			} | ||||||
|  | 		} else { | ||||||
|  | 			// otherwise we cannot convert the value into a list of answer and cannot enforce length | ||||||
|  | 			return fmt.Errorf("cannot impose the length on something other than a list of answers") | ||||||
|  | 		} | ||||||
|  | 		// the input is fine | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
| // ComposeValidators is a variadic function used to create one validator from many. | // ComposeValidators is a variadic function used to create one validator from many. | ||||||
| func ComposeValidators(validators ...Validator) Validator { | func ComposeValidators(validators ...Validator) Validator { | ||||||
| 	// return a validator that calls each one sequentially | 	// return a validator that calls each one sequentially | ||||||
|   | |||||||
							
								
								
									
										1
									
								
								vendor/github.com/Microsoft/go-winio/CODEOWNERS
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								vendor/github.com/Microsoft/go-winio/CODEOWNERS
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  |   * @microsoft/containerplat | ||||||
							
								
								
									
										2
									
								
								vendor/github.com/Microsoft/go-winio/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/Microsoft/go-winio/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -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 | 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 | Go. Currently, this is focused on accessing named pipes and other file handles, and | ||||||
|   | |||||||
							
								
								
									
										36
									
								
								vendor/github.com/Microsoft/go-winio/fileinfo.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										36
									
								
								vendor/github.com/Microsoft/go-winio/fileinfo.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -5,21 +5,14 @@ package winio | |||||||
| import ( | import ( | ||||||
| 	"os" | 	"os" | ||||||
| 	"runtime" | 	"runtime" | ||||||
| 	"syscall" |  | ||||||
| 	"unsafe" | 	"unsafe" | ||||||
| ) |  | ||||||
|  |  | ||||||
| //sys getFileInformationByHandleEx(h syscall.Handle, class uint32, buffer *byte, size uint32) (err error) = GetFileInformationByHandleEx | 	"golang.org/x/sys/windows" | ||||||
| //sys setFileInformationByHandle(h syscall.Handle, class uint32, buffer *byte, size uint32) (err error) = SetFileInformationByHandle |  | ||||||
|  |  | ||||||
| const ( |  | ||||||
| 	fileBasicInfo = 0 |  | ||||||
| 	fileIDInfo    = 0x12 |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // FileBasicInfo contains file access time and file attributes information. | // FileBasicInfo contains file access time and file attributes information. | ||||||
| type FileBasicInfo struct { | type FileBasicInfo struct { | ||||||
| 	CreationTime, LastAccessTime, LastWriteTime, ChangeTime syscall.Filetime | 	CreationTime, LastAccessTime, LastWriteTime, ChangeTime windows.Filetime | ||||||
| 	FileAttributes                                          uint32 | 	FileAttributes                                          uint32 | ||||||
| 	pad                                                     uint32 // padding | 	pad                                                     uint32 // padding | ||||||
| } | } | ||||||
| @@ -27,7 +20,7 @@ type FileBasicInfo struct { | |||||||
| // GetFileBasicInfo retrieves times and attributes for a file. | // GetFileBasicInfo retrieves times and attributes for a file. | ||||||
| func GetFileBasicInfo(f *os.File) (*FileBasicInfo, error) { | func GetFileBasicInfo(f *os.File) (*FileBasicInfo, error) { | ||||||
| 	bi := &FileBasicInfo{} | 	bi := &FileBasicInfo{} | ||||||
| 	if err := getFileInformationByHandleEx(syscall.Handle(f.Fd()), fileBasicInfo, (*byte)(unsafe.Pointer(bi)), uint32(unsafe.Sizeof(*bi))); err != nil { | 	if err := windows.GetFileInformationByHandleEx(windows.Handle(f.Fd()), windows.FileBasicInfo, (*byte)(unsafe.Pointer(bi)), uint32(unsafe.Sizeof(*bi))); err != nil { | ||||||
| 		return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err} | 		return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err} | ||||||
| 	} | 	} | ||||||
| 	runtime.KeepAlive(f) | 	runtime.KeepAlive(f) | ||||||
| @@ -36,13 +29,32 @@ func GetFileBasicInfo(f *os.File) (*FileBasicInfo, error) { | |||||||
|  |  | ||||||
| // SetFileBasicInfo sets times and attributes for a file. | // SetFileBasicInfo sets times and attributes for a file. | ||||||
| func SetFileBasicInfo(f *os.File, bi *FileBasicInfo) error { | func SetFileBasicInfo(f *os.File, bi *FileBasicInfo) error { | ||||||
| 	if err := setFileInformationByHandle(syscall.Handle(f.Fd()), fileBasicInfo, (*byte)(unsafe.Pointer(bi)), uint32(unsafe.Sizeof(*bi))); err != nil { | 	if err := windows.SetFileInformationByHandle(windows.Handle(f.Fd()), windows.FileBasicInfo, (*byte)(unsafe.Pointer(bi)), uint32(unsafe.Sizeof(*bi))); err != nil { | ||||||
| 		return &os.PathError{Op: "SetFileInformationByHandle", Path: f.Name(), Err: err} | 		return &os.PathError{Op: "SetFileInformationByHandle", Path: f.Name(), Err: err} | ||||||
| 	} | 	} | ||||||
| 	runtime.KeepAlive(f) | 	runtime.KeepAlive(f) | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // FileStandardInfo contains extended information for the file. | ||||||
|  | // FILE_STANDARD_INFO in WinBase.h | ||||||
|  | // https://docs.microsoft.com/en-us/windows/win32/api/winbase/ns-winbase-file_standard_info | ||||||
|  | type FileStandardInfo struct { | ||||||
|  | 	AllocationSize, EndOfFile int64 | ||||||
|  | 	NumberOfLinks             uint32 | ||||||
|  | 	DeletePending, Directory  bool | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // GetFileStandardInfo retrieves ended information for the file. | ||||||
|  | func GetFileStandardInfo(f *os.File) (*FileStandardInfo, error) { | ||||||
|  | 	si := &FileStandardInfo{} | ||||||
|  | 	if err := windows.GetFileInformationByHandleEx(windows.Handle(f.Fd()), windows.FileStandardInfo, (*byte)(unsafe.Pointer(si)), uint32(unsafe.Sizeof(*si))); err != nil { | ||||||
|  | 		return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err} | ||||||
|  | 	} | ||||||
|  | 	runtime.KeepAlive(f) | ||||||
|  | 	return si, nil | ||||||
|  | } | ||||||
|  |  | ||||||
| // FileIDInfo contains the volume serial number and file ID for a file. This pair should be | // FileIDInfo contains the volume serial number and file ID for a file. This pair should be | ||||||
| // unique on a system. | // unique on a system. | ||||||
| type FileIDInfo struct { | type FileIDInfo struct { | ||||||
| @@ -53,7 +65,7 @@ type FileIDInfo struct { | |||||||
| // GetFileID retrieves the unique (volume, file ID) pair for a file. | // GetFileID retrieves the unique (volume, file ID) pair for a file. | ||||||
| func GetFileID(f *os.File) (*FileIDInfo, error) { | func GetFileID(f *os.File) (*FileIDInfo, error) { | ||||||
| 	fileID := &FileIDInfo{} | 	fileID := &FileIDInfo{} | ||||||
| 	if err := getFileInformationByHandleEx(syscall.Handle(f.Fd()), fileIDInfo, (*byte)(unsafe.Pointer(fileID)), uint32(unsafe.Sizeof(*fileID))); err != nil { | 	if err := windows.GetFileInformationByHandleEx(windows.Handle(f.Fd()), windows.FileIdInfo, (*byte)(unsafe.Pointer(fileID)), uint32(unsafe.Sizeof(*fileID))); err != nil { | ||||||
| 		return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err} | 		return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err} | ||||||
| 	} | 	} | ||||||
| 	runtime.KeepAlive(f) | 	runtime.KeepAlive(f) | ||||||
|   | |||||||
							
								
								
									
										4
									
								
								vendor/github.com/Microsoft/go-winio/go.mod
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/Microsoft/go-winio/go.mod
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -4,6 +4,6 @@ go 1.12 | |||||||
|  |  | ||||||
| require ( | require ( | ||||||
| 	github.com/pkg/errors v0.9.1 | 	github.com/pkg/errors v0.9.1 | ||||||
| 	github.com/sirupsen/logrus v1.4.1 | 	github.com/sirupsen/logrus v1.7.0 | ||||||
| 	golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3 | 	golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c | ||||||
| ) | ) | ||||||
|   | |||||||
							
								
								
									
										14
									
								
								vendor/github.com/Microsoft/go-winio/go.sum
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								vendor/github.com/Microsoft/go-winio/go.sum
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,16 +1,14 @@ | |||||||
| github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | 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/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||||||
| github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= |  | ||||||
| github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= |  | ||||||
| github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= | ||||||
| github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= | ||||||
| github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||||||
| github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||||||
| github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k= | github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= | ||||||
| github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= | github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= | ||||||
| github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= |  | ||||||
| github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= | github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= | ||||||
| github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= | ||||||
| golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4= | ||||||
| golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3 h1:7TYNF4UdlohbFwpNH04CoPMp1cHUZgO1Ebq5r2hIjfo= | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||||
| golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk= | ||||||
|  | golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								vendor/github.com/Microsoft/go-winio/hvsock.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/Microsoft/go-winio/hvsock.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,3 +1,5 @@ | |||||||
|  | // +build windows | ||||||
|  |  | ||||||
| package winio | package winio | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								vendor/github.com/Microsoft/go-winio/pkg/guid/guid.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/Microsoft/go-winio/pkg/guid/guid.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,3 +1,5 @@ | |||||||
|  | // +build windows | ||||||
|  |  | ||||||
| // Package guid provides a GUID type. The backing structure for a GUID is | // Package guid provides a GUID type. The backing structure for a GUID is | ||||||
| // identical to that used by the golang.org/x/sys/windows GUID type. | // identical to that used by the golang.org/x/sys/windows GUID type. | ||||||
| // There are two main binary encodings used for a GUID, the big-endian encoding, | // There are two main binary encodings used for a GUID, the big-endian encoding, | ||||||
|   | |||||||
							
								
								
									
										1
									
								
								vendor/github.com/Microsoft/go-winio/privilege.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								vendor/github.com/Microsoft/go-winio/privilege.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -30,6 +30,7 @@ const ( | |||||||
|  |  | ||||||
| 	SeBackupPrivilege   = "SeBackupPrivilege" | 	SeBackupPrivilege   = "SeBackupPrivilege" | ||||||
| 	SeRestorePrivilege  = "SeRestorePrivilege" | 	SeRestorePrivilege  = "SeRestorePrivilege" | ||||||
|  | 	SeSecurityPrivilege = "SeSecurityPrivilege" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| const ( | const ( | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								vendor/github.com/Microsoft/go-winio/syscall.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/Microsoft/go-winio/syscall.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,3 +1,3 @@ | |||||||
| package winio | package winio | ||||||
|  |  | ||||||
| //go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go file.go pipe.go sd.go fileinfo.go privilege.go backup.go hvsock.go | //go:generate go run golang.org/x/sys/windows/mkwinsyscall -output zsyscall_windows.go file.go pipe.go sd.go fileinfo.go privilege.go backup.go hvsock.go | ||||||
|   | |||||||
							
								
								
									
										595
									
								
								vendor/github.com/Microsoft/go-winio/zsyscall_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										595
									
								
								vendor/github.com/Microsoft/go-winio/zsyscall_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -19,6 +19,7 @@ const ( | |||||||
|  |  | ||||||
| var ( | var ( | ||||||
| 	errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING) | 	errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING) | ||||||
|  | 	errERROR_EINVAL     error = syscall.EINVAL | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // errnoErr returns common boxed Errno values, to prevent | // errnoErr returns common boxed Errno values, to prevent | ||||||
| @@ -26,7 +27,7 @@ var ( | |||||||
| func errnoErr(e syscall.Errno) error { | func errnoErr(e syscall.Errno) error { | ||||||
| 	switch e { | 	switch e { | ||||||
| 	case 0: | 	case 0: | ||||||
| 		return nil | 		return errERROR_EINVAL | ||||||
| 	case errnoERROR_IO_PENDING: | 	case errnoERROR_IO_PENDING: | ||||||
| 		return errERROR_IO_PENDING | 		return errERROR_IO_PENDING | ||||||
| 	} | 	} | ||||||
| @@ -37,243 +38,62 @@ func errnoErr(e syscall.Errno) error { | |||||||
| } | } | ||||||
|  |  | ||||||
| var ( | var ( | ||||||
| 	modkernel32 = windows.NewLazySystemDLL("kernel32.dll") |  | ||||||
| 	modws2_32   = windows.NewLazySystemDLL("ws2_32.dll") |  | ||||||
| 	modntdll    = windows.NewLazySystemDLL("ntdll.dll") |  | ||||||
| 	modadvapi32 = windows.NewLazySystemDLL("advapi32.dll") | 	modadvapi32 = windows.NewLazySystemDLL("advapi32.dll") | ||||||
|  | 	modkernel32 = windows.NewLazySystemDLL("kernel32.dll") | ||||||
|  | 	modntdll    = windows.NewLazySystemDLL("ntdll.dll") | ||||||
|  | 	modws2_32   = windows.NewLazySystemDLL("ws2_32.dll") | ||||||
|  |  | ||||||
| 	procCancelIoEx                                           = modkernel32.NewProc("CancelIoEx") | 	procAdjustTokenPrivileges                                = modadvapi32.NewProc("AdjustTokenPrivileges") | ||||||
| 	procCreateIoCompletionPort                               = modkernel32.NewProc("CreateIoCompletionPort") | 	procConvertSecurityDescriptorToStringSecurityDescriptorW = modadvapi32.NewProc("ConvertSecurityDescriptorToStringSecurityDescriptorW") | ||||||
| 	procGetQueuedCompletionStatus                            = modkernel32.NewProc("GetQueuedCompletionStatus") |  | ||||||
| 	procSetFileCompletionNotificationModes                   = modkernel32.NewProc("SetFileCompletionNotificationModes") |  | ||||||
| 	procWSAGetOverlappedResult                               = modws2_32.NewProc("WSAGetOverlappedResult") |  | ||||||
| 	procConnectNamedPipe                                     = modkernel32.NewProc("ConnectNamedPipe") |  | ||||||
| 	procCreateNamedPipeW                                     = modkernel32.NewProc("CreateNamedPipeW") |  | ||||||
| 	procCreateFileW                                          = modkernel32.NewProc("CreateFileW") |  | ||||||
| 	procGetNamedPipeInfo                                     = modkernel32.NewProc("GetNamedPipeInfo") |  | ||||||
| 	procGetNamedPipeHandleStateW                             = modkernel32.NewProc("GetNamedPipeHandleStateW") |  | ||||||
| 	procLocalAlloc                                           = modkernel32.NewProc("LocalAlloc") |  | ||||||
| 	procNtCreateNamedPipeFile                                = modntdll.NewProc("NtCreateNamedPipeFile") |  | ||||||
| 	procRtlNtStatusToDosErrorNoTeb                           = modntdll.NewProc("RtlNtStatusToDosErrorNoTeb") |  | ||||||
| 	procRtlDosPathNameToNtPathName_U                         = modntdll.NewProc("RtlDosPathNameToNtPathName_U") |  | ||||||
| 	procRtlDefaultNpAcl                                      = modntdll.NewProc("RtlDefaultNpAcl") |  | ||||||
| 	procLookupAccountNameW                                   = modadvapi32.NewProc("LookupAccountNameW") |  | ||||||
| 	procConvertSidToStringSidW                               = modadvapi32.NewProc("ConvertSidToStringSidW") | 	procConvertSidToStringSidW                               = modadvapi32.NewProc("ConvertSidToStringSidW") | ||||||
| 	procConvertStringSecurityDescriptorToSecurityDescriptorW = modadvapi32.NewProc("ConvertStringSecurityDescriptorToSecurityDescriptorW") | 	procConvertStringSecurityDescriptorToSecurityDescriptorW = modadvapi32.NewProc("ConvertStringSecurityDescriptorToSecurityDescriptorW") | ||||||
| 	procConvertSecurityDescriptorToStringSecurityDescriptorW = modadvapi32.NewProc("ConvertSecurityDescriptorToStringSecurityDescriptorW") |  | ||||||
| 	procLocalFree                                            = modkernel32.NewProc("LocalFree") |  | ||||||
| 	procGetSecurityDescriptorLength                          = modadvapi32.NewProc("GetSecurityDescriptorLength") | 	procGetSecurityDescriptorLength                          = modadvapi32.NewProc("GetSecurityDescriptorLength") | ||||||
| 	procGetFileInformationByHandleEx                         = modkernel32.NewProc("GetFileInformationByHandleEx") |  | ||||||
| 	procSetFileInformationByHandle                           = modkernel32.NewProc("SetFileInformationByHandle") |  | ||||||
| 	procAdjustTokenPrivileges                                = modadvapi32.NewProc("AdjustTokenPrivileges") |  | ||||||
| 	procImpersonateSelf                                      = modadvapi32.NewProc("ImpersonateSelf") | 	procImpersonateSelf                                      = modadvapi32.NewProc("ImpersonateSelf") | ||||||
| 	procRevertToSelf                                         = modadvapi32.NewProc("RevertToSelf") | 	procLookupAccountNameW                                   = modadvapi32.NewProc("LookupAccountNameW") | ||||||
| 	procOpenThreadToken                                      = modadvapi32.NewProc("OpenThreadToken") |  | ||||||
| 	procGetCurrentThread                                     = modkernel32.NewProc("GetCurrentThread") |  | ||||||
| 	procLookupPrivilegeValueW                                = modadvapi32.NewProc("LookupPrivilegeValueW") |  | ||||||
| 	procLookupPrivilegeNameW                                 = modadvapi32.NewProc("LookupPrivilegeNameW") |  | ||||||
| 	procLookupPrivilegeDisplayNameW                          = modadvapi32.NewProc("LookupPrivilegeDisplayNameW") | 	procLookupPrivilegeDisplayNameW                          = modadvapi32.NewProc("LookupPrivilegeDisplayNameW") | ||||||
|  | 	procLookupPrivilegeNameW                                 = modadvapi32.NewProc("LookupPrivilegeNameW") | ||||||
|  | 	procLookupPrivilegeValueW                                = modadvapi32.NewProc("LookupPrivilegeValueW") | ||||||
|  | 	procOpenThreadToken                                      = modadvapi32.NewProc("OpenThreadToken") | ||||||
|  | 	procRevertToSelf                                         = modadvapi32.NewProc("RevertToSelf") | ||||||
| 	procBackupRead                                           = modkernel32.NewProc("BackupRead") | 	procBackupRead                                           = modkernel32.NewProc("BackupRead") | ||||||
| 	procBackupWrite                                          = modkernel32.NewProc("BackupWrite") | 	procBackupWrite                                          = modkernel32.NewProc("BackupWrite") | ||||||
|  | 	procCancelIoEx                                           = modkernel32.NewProc("CancelIoEx") | ||||||
|  | 	procConnectNamedPipe                                     = modkernel32.NewProc("ConnectNamedPipe") | ||||||
|  | 	procCreateFileW                                          = modkernel32.NewProc("CreateFileW") | ||||||
|  | 	procCreateIoCompletionPort                               = modkernel32.NewProc("CreateIoCompletionPort") | ||||||
|  | 	procCreateNamedPipeW                                     = modkernel32.NewProc("CreateNamedPipeW") | ||||||
|  | 	procGetCurrentThread                                     = modkernel32.NewProc("GetCurrentThread") | ||||||
|  | 	procGetNamedPipeHandleStateW                             = modkernel32.NewProc("GetNamedPipeHandleStateW") | ||||||
|  | 	procGetNamedPipeInfo                                     = modkernel32.NewProc("GetNamedPipeInfo") | ||||||
|  | 	procGetQueuedCompletionStatus                            = modkernel32.NewProc("GetQueuedCompletionStatus") | ||||||
|  | 	procLocalAlloc                                           = modkernel32.NewProc("LocalAlloc") | ||||||
|  | 	procLocalFree                                            = modkernel32.NewProc("LocalFree") | ||||||
|  | 	procSetFileCompletionNotificationModes                   = modkernel32.NewProc("SetFileCompletionNotificationModes") | ||||||
|  | 	procNtCreateNamedPipeFile                                = modntdll.NewProc("NtCreateNamedPipeFile") | ||||||
|  | 	procRtlDefaultNpAcl                                      = modntdll.NewProc("RtlDefaultNpAcl") | ||||||
|  | 	procRtlDosPathNameToNtPathName_U                         = modntdll.NewProc("RtlDosPathNameToNtPathName_U") | ||||||
|  | 	procRtlNtStatusToDosErrorNoTeb                           = modntdll.NewProc("RtlNtStatusToDosErrorNoTeb") | ||||||
|  | 	procWSAGetOverlappedResult                               = modws2_32.NewProc("WSAGetOverlappedResult") | ||||||
| 	procbind                                                 = modws2_32.NewProc("bind") | 	procbind                                                 = modws2_32.NewProc("bind") | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func cancelIoEx(file syscall.Handle, o *syscall.Overlapped) (err error) { | func adjustTokenPrivileges(token windows.Token, releaseAll bool, input *byte, outputSize uint32, output *byte, requiredSize *uint32) (success bool, err error) { | ||||||
| 	r1, _, e1 := syscall.Syscall(procCancelIoEx.Addr(), 2, uintptr(file), uintptr(unsafe.Pointer(o)), 0) |  | ||||||
| 	if r1 == 0 { |  | ||||||
| 		if e1 != 0 { |  | ||||||
| 			err = errnoErr(e1) |  | ||||||
| 		} else { |  | ||||||
| 			err = syscall.EINVAL |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func createIoCompletionPort(file syscall.Handle, port syscall.Handle, key uintptr, threadCount uint32) (newport syscall.Handle, err error) { |  | ||||||
| 	r0, _, e1 := syscall.Syscall6(procCreateIoCompletionPort.Addr(), 4, uintptr(file), uintptr(port), uintptr(key), uintptr(threadCount), 0, 0) |  | ||||||
| 	newport = syscall.Handle(r0) |  | ||||||
| 	if newport == 0 { |  | ||||||
| 		if e1 != 0 { |  | ||||||
| 			err = errnoErr(e1) |  | ||||||
| 		} else { |  | ||||||
| 			err = syscall.EINVAL |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func getQueuedCompletionStatus(port syscall.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) { |  | ||||||
| 	r1, _, e1 := syscall.Syscall6(procGetQueuedCompletionStatus.Addr(), 5, uintptr(port), uintptr(unsafe.Pointer(bytes)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(o)), uintptr(timeout), 0) |  | ||||||
| 	if r1 == 0 { |  | ||||||
| 		if e1 != 0 { |  | ||||||
| 			err = errnoErr(e1) |  | ||||||
| 		} else { |  | ||||||
| 			err = syscall.EINVAL |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func setFileCompletionNotificationModes(h syscall.Handle, flags uint8) (err error) { |  | ||||||
| 	r1, _, e1 := syscall.Syscall(procSetFileCompletionNotificationModes.Addr(), 2, uintptr(h), uintptr(flags), 0) |  | ||||||
| 	if r1 == 0 { |  | ||||||
| 		if e1 != 0 { |  | ||||||
| 			err = errnoErr(e1) |  | ||||||
| 		} else { |  | ||||||
| 			err = syscall.EINVAL |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func wsaGetOverlappedResult(h syscall.Handle, o *syscall.Overlapped, bytes *uint32, wait bool, flags *uint32) (err error) { |  | ||||||
| 	var _p0 uint32 | 	var _p0 uint32 | ||||||
| 	if wait { | 	if releaseAll { | ||||||
| 		_p0 = 1 | 		_p0 = 1 | ||||||
| 	} else { |  | ||||||
| 		_p0 = 0 |  | ||||||
| 	} | 	} | ||||||
| 	r1, _, e1 := syscall.Syscall6(procWSAGetOverlappedResult.Addr(), 5, uintptr(h), uintptr(unsafe.Pointer(o)), uintptr(unsafe.Pointer(bytes)), uintptr(_p0), uintptr(unsafe.Pointer(flags)), 0) | 	r0, _, e1 := syscall.Syscall6(procAdjustTokenPrivileges.Addr(), 6, uintptr(token), uintptr(_p0), uintptr(unsafe.Pointer(input)), uintptr(outputSize), uintptr(unsafe.Pointer(output)), uintptr(unsafe.Pointer(requiredSize))) | ||||||
|  | 	success = r0 != 0 | ||||||
|  | 	if true { | ||||||
|  | 		err = errnoErr(e1) | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func convertSecurityDescriptorToStringSecurityDescriptor(sd *byte, revision uint32, secInfo uint32, sddl **uint16, sddlSize *uint32) (err error) { | ||||||
|  | 	r1, _, e1 := syscall.Syscall6(procConvertSecurityDescriptorToStringSecurityDescriptorW.Addr(), 5, uintptr(unsafe.Pointer(sd)), uintptr(revision), uintptr(secInfo), uintptr(unsafe.Pointer(sddl)), uintptr(unsafe.Pointer(sddlSize)), 0) | ||||||
| 	if r1 == 0 { | 	if r1 == 0 { | ||||||
| 		if e1 != 0 { |  | ||||||
| 		err = errnoErr(e1) | 		err = errnoErr(e1) | ||||||
| 		} else { |  | ||||||
| 			err = syscall.EINVAL |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) { |  | ||||||
| 	r1, _, e1 := syscall.Syscall(procConnectNamedPipe.Addr(), 2, uintptr(pipe), uintptr(unsafe.Pointer(o)), 0) |  | ||||||
| 	if r1 == 0 { |  | ||||||
| 		if e1 != 0 { |  | ||||||
| 			err = errnoErr(e1) |  | ||||||
| 		} else { |  | ||||||
| 			err = syscall.EINVAL |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *syscall.SecurityAttributes) (handle syscall.Handle, err error) { |  | ||||||
| 	var _p0 *uint16 |  | ||||||
| 	_p0, err = syscall.UTF16PtrFromString(name) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	return _createNamedPipe(_p0, flags, pipeMode, maxInstances, outSize, inSize, defaultTimeout, sa) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func _createNamedPipe(name *uint16, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *syscall.SecurityAttributes) (handle syscall.Handle, err error) { |  | ||||||
| 	r0, _, e1 := syscall.Syscall9(procCreateNamedPipeW.Addr(), 8, uintptr(unsafe.Pointer(name)), uintptr(flags), uintptr(pipeMode), uintptr(maxInstances), uintptr(outSize), uintptr(inSize), uintptr(defaultTimeout), uintptr(unsafe.Pointer(sa)), 0) |  | ||||||
| 	handle = syscall.Handle(r0) |  | ||||||
| 	if handle == syscall.InvalidHandle { |  | ||||||
| 		if e1 != 0 { |  | ||||||
| 			err = errnoErr(e1) |  | ||||||
| 		} else { |  | ||||||
| 			err = syscall.EINVAL |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func createFile(name string, access uint32, mode uint32, sa *syscall.SecurityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) { |  | ||||||
| 	var _p0 *uint16 |  | ||||||
| 	_p0, err = syscall.UTF16PtrFromString(name) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	return _createFile(_p0, access, mode, sa, createmode, attrs, templatefile) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func _createFile(name *uint16, access uint32, mode uint32, sa *syscall.SecurityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) { |  | ||||||
| 	r0, _, e1 := syscall.Syscall9(procCreateFileW.Addr(), 7, uintptr(unsafe.Pointer(name)), uintptr(access), uintptr(mode), uintptr(unsafe.Pointer(sa)), uintptr(createmode), uintptr(attrs), uintptr(templatefile), 0, 0) |  | ||||||
| 	handle = syscall.Handle(r0) |  | ||||||
| 	if handle == syscall.InvalidHandle { |  | ||||||
| 		if e1 != 0 { |  | ||||||
| 			err = errnoErr(e1) |  | ||||||
| 		} else { |  | ||||||
| 			err = syscall.EINVAL |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func getNamedPipeInfo(pipe syscall.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) { |  | ||||||
| 	r1, _, e1 := syscall.Syscall6(procGetNamedPipeInfo.Addr(), 5, uintptr(pipe), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(outSize)), uintptr(unsafe.Pointer(inSize)), uintptr(unsafe.Pointer(maxInstances)), 0) |  | ||||||
| 	if r1 == 0 { |  | ||||||
| 		if e1 != 0 { |  | ||||||
| 			err = errnoErr(e1) |  | ||||||
| 		} else { |  | ||||||
| 			err = syscall.EINVAL |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func getNamedPipeHandleState(pipe syscall.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) { |  | ||||||
| 	r1, _, e1 := syscall.Syscall9(procGetNamedPipeHandleStateW.Addr(), 7, uintptr(pipe), uintptr(unsafe.Pointer(state)), uintptr(unsafe.Pointer(curInstances)), uintptr(unsafe.Pointer(maxCollectionCount)), uintptr(unsafe.Pointer(collectDataTimeout)), uintptr(unsafe.Pointer(userName)), uintptr(maxUserNameSize), 0, 0) |  | ||||||
| 	if r1 == 0 { |  | ||||||
| 		if e1 != 0 { |  | ||||||
| 			err = errnoErr(e1) |  | ||||||
| 		} else { |  | ||||||
| 			err = syscall.EINVAL |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func localAlloc(uFlags uint32, length uint32) (ptr uintptr) { |  | ||||||
| 	r0, _, _ := syscall.Syscall(procLocalAlloc.Addr(), 2, uintptr(uFlags), uintptr(length), 0) |  | ||||||
| 	ptr = uintptr(r0) |  | ||||||
| 	return |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func ntCreateNamedPipeFile(pipe *syscall.Handle, access uint32, oa *objectAttributes, iosb *ioStatusBlock, share uint32, disposition uint32, options uint32, typ uint32, readMode uint32, completionMode uint32, maxInstances uint32, inboundQuota uint32, outputQuota uint32, timeout *int64) (status ntstatus) { |  | ||||||
| 	r0, _, _ := syscall.Syscall15(procNtCreateNamedPipeFile.Addr(), 14, uintptr(unsafe.Pointer(pipe)), uintptr(access), uintptr(unsafe.Pointer(oa)), uintptr(unsafe.Pointer(iosb)), uintptr(share), uintptr(disposition), uintptr(options), uintptr(typ), uintptr(readMode), uintptr(completionMode), uintptr(maxInstances), uintptr(inboundQuota), uintptr(outputQuota), uintptr(unsafe.Pointer(timeout)), 0) |  | ||||||
| 	status = ntstatus(r0) |  | ||||||
| 	return |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func rtlNtStatusToDosError(status ntstatus) (winerr error) { |  | ||||||
| 	r0, _, _ := syscall.Syscall(procRtlNtStatusToDosErrorNoTeb.Addr(), 1, uintptr(status), 0, 0) |  | ||||||
| 	if r0 != 0 { |  | ||||||
| 		winerr = syscall.Errno(r0) |  | ||||||
| 	} |  | ||||||
| 	return |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func rtlDosPathNameToNtPathName(name *uint16, ntName *unicodeString, filePart uintptr, reserved uintptr) (status ntstatus) { |  | ||||||
| 	r0, _, _ := syscall.Syscall6(procRtlDosPathNameToNtPathName_U.Addr(), 4, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(ntName)), uintptr(filePart), uintptr(reserved), 0, 0) |  | ||||||
| 	status = ntstatus(r0) |  | ||||||
| 	return |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func rtlDefaultNpAcl(dacl *uintptr) (status ntstatus) { |  | ||||||
| 	r0, _, _ := syscall.Syscall(procRtlDefaultNpAcl.Addr(), 1, uintptr(unsafe.Pointer(dacl)), 0, 0) |  | ||||||
| 	status = ntstatus(r0) |  | ||||||
| 	return |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func lookupAccountName(systemName *uint16, accountName string, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) { |  | ||||||
| 	var _p0 *uint16 |  | ||||||
| 	_p0, err = syscall.UTF16PtrFromString(accountName) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	return _lookupAccountName(systemName, _p0, sid, sidSize, refDomain, refDomainSize, sidNameUse) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func _lookupAccountName(systemName *uint16, accountName *uint16, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) { |  | ||||||
| 	r1, _, e1 := syscall.Syscall9(procLookupAccountNameW.Addr(), 7, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(accountName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(sidSize)), uintptr(unsafe.Pointer(refDomain)), uintptr(unsafe.Pointer(refDomainSize)), uintptr(unsafe.Pointer(sidNameUse)), 0, 0) |  | ||||||
| 	if r1 == 0 { |  | ||||||
| 		if e1 != 0 { |  | ||||||
| 			err = errnoErr(e1) |  | ||||||
| 		} else { |  | ||||||
| 			err = syscall.EINVAL |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
| 	return | 	return | ||||||
| } | } | ||||||
| @@ -281,11 +101,7 @@ func _lookupAccountName(systemName *uint16, accountName *uint16, sid *byte, sidS | |||||||
| func convertSidToStringSid(sid *byte, str **uint16) (err error) { | func convertSidToStringSid(sid *byte, str **uint16) (err error) { | ||||||
| 	r1, _, e1 := syscall.Syscall(procConvertSidToStringSidW.Addr(), 2, uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(str)), 0) | 	r1, _, e1 := syscall.Syscall(procConvertSidToStringSidW.Addr(), 2, uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(str)), 0) | ||||||
| 	if r1 == 0 { | 	if r1 == 0 { | ||||||
| 		if e1 != 0 { |  | ||||||
| 		err = errnoErr(e1) | 		err = errnoErr(e1) | ||||||
| 		} else { |  | ||||||
| 			err = syscall.EINVAL |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
| 	return | 	return | ||||||
| } | } | ||||||
| @@ -302,29 +118,8 @@ func convertStringSecurityDescriptorToSecurityDescriptor(str string, revision ui | |||||||
| func _convertStringSecurityDescriptorToSecurityDescriptor(str *uint16, revision uint32, sd *uintptr, size *uint32) (err error) { | func _convertStringSecurityDescriptorToSecurityDescriptor(str *uint16, revision uint32, sd *uintptr, size *uint32) (err error) { | ||||||
| 	r1, _, e1 := syscall.Syscall6(procConvertStringSecurityDescriptorToSecurityDescriptorW.Addr(), 4, uintptr(unsafe.Pointer(str)), uintptr(revision), uintptr(unsafe.Pointer(sd)), uintptr(unsafe.Pointer(size)), 0, 0) | 	r1, _, e1 := syscall.Syscall6(procConvertStringSecurityDescriptorToSecurityDescriptorW.Addr(), 4, uintptr(unsafe.Pointer(str)), uintptr(revision), uintptr(unsafe.Pointer(sd)), uintptr(unsafe.Pointer(size)), 0, 0) | ||||||
| 	if r1 == 0 { | 	if r1 == 0 { | ||||||
| 		if e1 != 0 { |  | ||||||
| 		err = errnoErr(e1) | 		err = errnoErr(e1) | ||||||
| 		} else { |  | ||||||
| 			err = syscall.EINVAL |  | ||||||
| 	} | 	} | ||||||
| 	} |  | ||||||
| 	return |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func convertSecurityDescriptorToStringSecurityDescriptor(sd *byte, revision uint32, secInfo uint32, sddl **uint16, sddlSize *uint32) (err error) { |  | ||||||
| 	r1, _, e1 := syscall.Syscall6(procConvertSecurityDescriptorToStringSecurityDescriptorW.Addr(), 5, uintptr(unsafe.Pointer(sd)), uintptr(revision), uintptr(secInfo), uintptr(unsafe.Pointer(sddl)), uintptr(unsafe.Pointer(sddlSize)), 0) |  | ||||||
| 	if r1 == 0 { |  | ||||||
| 		if e1 != 0 { |  | ||||||
| 			err = errnoErr(e1) |  | ||||||
| 		} else { |  | ||||||
| 			err = syscall.EINVAL |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func localFree(mem uintptr) { |  | ||||||
| 	syscall.Syscall(procLocalFree.Addr(), 1, uintptr(mem), 0, 0) |  | ||||||
| 	return | 	return | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -334,94 +129,62 @@ func getSecurityDescriptorLength(sd uintptr) (len uint32) { | |||||||
| 	return | 	return | ||||||
| } | } | ||||||
|  |  | ||||||
| func getFileInformationByHandleEx(h syscall.Handle, class uint32, buffer *byte, size uint32) (err error) { |  | ||||||
| 	r1, _, e1 := syscall.Syscall6(procGetFileInformationByHandleEx.Addr(), 4, uintptr(h), uintptr(class), uintptr(unsafe.Pointer(buffer)), uintptr(size), 0, 0) |  | ||||||
| 	if r1 == 0 { |  | ||||||
| 		if e1 != 0 { |  | ||||||
| 			err = errnoErr(e1) |  | ||||||
| 		} else { |  | ||||||
| 			err = syscall.EINVAL |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func setFileInformationByHandle(h syscall.Handle, class uint32, buffer *byte, size uint32) (err error) { |  | ||||||
| 	r1, _, e1 := syscall.Syscall6(procSetFileInformationByHandle.Addr(), 4, uintptr(h), uintptr(class), uintptr(unsafe.Pointer(buffer)), uintptr(size), 0, 0) |  | ||||||
| 	if r1 == 0 { |  | ||||||
| 		if e1 != 0 { |  | ||||||
| 			err = errnoErr(e1) |  | ||||||
| 		} else { |  | ||||||
| 			err = syscall.EINVAL |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func adjustTokenPrivileges(token windows.Token, releaseAll bool, input *byte, outputSize uint32, output *byte, requiredSize *uint32) (success bool, err error) { |  | ||||||
| 	var _p0 uint32 |  | ||||||
| 	if releaseAll { |  | ||||||
| 		_p0 = 1 |  | ||||||
| 	} else { |  | ||||||
| 		_p0 = 0 |  | ||||||
| 	} |  | ||||||
| 	r0, _, e1 := syscall.Syscall6(procAdjustTokenPrivileges.Addr(), 6, uintptr(token), uintptr(_p0), uintptr(unsafe.Pointer(input)), uintptr(outputSize), uintptr(unsafe.Pointer(output)), uintptr(unsafe.Pointer(requiredSize))) |  | ||||||
| 	success = r0 != 0 |  | ||||||
| 	if true { |  | ||||||
| 		if e1 != 0 { |  | ||||||
| 			err = errnoErr(e1) |  | ||||||
| 		} else { |  | ||||||
| 			err = syscall.EINVAL |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func impersonateSelf(level uint32) (err error) { | func impersonateSelf(level uint32) (err error) { | ||||||
| 	r1, _, e1 := syscall.Syscall(procImpersonateSelf.Addr(), 1, uintptr(level), 0, 0) | 	r1, _, e1 := syscall.Syscall(procImpersonateSelf.Addr(), 1, uintptr(level), 0, 0) | ||||||
| 	if r1 == 0 { | 	if r1 == 0 { | ||||||
| 		if e1 != 0 { |  | ||||||
| 		err = errnoErr(e1) | 		err = errnoErr(e1) | ||||||
| 		} else { |  | ||||||
| 			err = syscall.EINVAL |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
| 	return | 	return | ||||||
| } | } | ||||||
|  |  | ||||||
| func revertToSelf() (err error) { | func lookupAccountName(systemName *uint16, accountName string, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) { | ||||||
| 	r1, _, e1 := syscall.Syscall(procRevertToSelf.Addr(), 0, 0, 0, 0) | 	var _p0 *uint16 | ||||||
|  | 	_p0, err = syscall.UTF16PtrFromString(accountName) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	return _lookupAccountName(systemName, _p0, sid, sidSize, refDomain, refDomainSize, sidNameUse) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func _lookupAccountName(systemName *uint16, accountName *uint16, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) { | ||||||
|  | 	r1, _, e1 := syscall.Syscall9(procLookupAccountNameW.Addr(), 7, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(accountName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(sidSize)), uintptr(unsafe.Pointer(refDomain)), uintptr(unsafe.Pointer(refDomainSize)), uintptr(unsafe.Pointer(sidNameUse)), 0, 0) | ||||||
| 	if r1 == 0 { | 	if r1 == 0 { | ||||||
| 		if e1 != 0 { |  | ||||||
| 		err = errnoErr(e1) | 		err = errnoErr(e1) | ||||||
| 		} else { |  | ||||||
| 			err = syscall.EINVAL |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
| 	return | 	return | ||||||
| } | } | ||||||
|  |  | ||||||
| func openThreadToken(thread syscall.Handle, accessMask uint32, openAsSelf bool, token *windows.Token) (err error) { | func lookupPrivilegeDisplayName(systemName string, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) { | ||||||
| 	var _p0 uint32 | 	var _p0 *uint16 | ||||||
| 	if openAsSelf { | 	_p0, err = syscall.UTF16PtrFromString(systemName) | ||||||
| 		_p0 = 1 | 	if err != nil { | ||||||
| 	} else { | 		return | ||||||
| 		_p0 = 0 |  | ||||||
| 	} | 	} | ||||||
| 	r1, _, e1 := syscall.Syscall6(procOpenThreadToken.Addr(), 4, uintptr(thread), uintptr(accessMask), uintptr(_p0), uintptr(unsafe.Pointer(token)), 0, 0) | 	return _lookupPrivilegeDisplayName(_p0, name, buffer, size, languageId) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func _lookupPrivilegeDisplayName(systemName *uint16, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) { | ||||||
|  | 	r1, _, e1 := syscall.Syscall6(procLookupPrivilegeDisplayNameW.Addr(), 5, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(buffer)), uintptr(unsafe.Pointer(size)), uintptr(unsafe.Pointer(languageId)), 0) | ||||||
| 	if r1 == 0 { | 	if r1 == 0 { | ||||||
| 		if e1 != 0 { |  | ||||||
| 		err = errnoErr(e1) | 		err = errnoErr(e1) | ||||||
| 		} else { |  | ||||||
| 			err = syscall.EINVAL |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
| 	return | 	return | ||||||
| } | } | ||||||
|  |  | ||||||
| func getCurrentThread() (h syscall.Handle) { | func lookupPrivilegeName(systemName string, luid *uint64, buffer *uint16, size *uint32) (err error) { | ||||||
| 	r0, _, _ := syscall.Syscall(procGetCurrentThread.Addr(), 0, 0, 0, 0) | 	var _p0 *uint16 | ||||||
| 	h = syscall.Handle(r0) | 	_p0, err = syscall.UTF16PtrFromString(systemName) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	return _lookupPrivilegeName(_p0, luid, buffer, size) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func _lookupPrivilegeName(systemName *uint16, luid *uint64, buffer *uint16, size *uint32) (err error) { | ||||||
|  | 	r1, _, e1 := syscall.Syscall6(procLookupPrivilegeNameW.Addr(), 4, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(luid)), uintptr(unsafe.Pointer(buffer)), uintptr(unsafe.Pointer(size)), 0, 0) | ||||||
|  | 	if r1 == 0 { | ||||||
|  | 		err = errnoErr(e1) | ||||||
|  | 	} | ||||||
| 	return | 	return | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -442,53 +205,27 @@ func lookupPrivilegeValue(systemName string, name string, luid *uint64) (err err | |||||||
| func _lookupPrivilegeValue(systemName *uint16, name *uint16, luid *uint64) (err error) { | func _lookupPrivilegeValue(systemName *uint16, name *uint16, luid *uint64) (err error) { | ||||||
| 	r1, _, e1 := syscall.Syscall(procLookupPrivilegeValueW.Addr(), 3, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(luid))) | 	r1, _, e1 := syscall.Syscall(procLookupPrivilegeValueW.Addr(), 3, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(luid))) | ||||||
| 	if r1 == 0 { | 	if r1 == 0 { | ||||||
| 		if e1 != 0 { |  | ||||||
| 		err = errnoErr(e1) | 		err = errnoErr(e1) | ||||||
| 		} else { |  | ||||||
| 			err = syscall.EINVAL |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
| 	return | 	return | ||||||
| } | } | ||||||
|  |  | ||||||
| func lookupPrivilegeName(systemName string, luid *uint64, buffer *uint16, size *uint32) (err error) { | func openThreadToken(thread syscall.Handle, accessMask uint32, openAsSelf bool, token *windows.Token) (err error) { | ||||||
| 	var _p0 *uint16 | 	var _p0 uint32 | ||||||
| 	_p0, err = syscall.UTF16PtrFromString(systemName) | 	if openAsSelf { | ||||||
| 	if err != nil { | 		_p0 = 1 | ||||||
| 		return |  | ||||||
| 	} | 	} | ||||||
| 	return _lookupPrivilegeName(_p0, luid, buffer, size) | 	r1, _, e1 := syscall.Syscall6(procOpenThreadToken.Addr(), 4, uintptr(thread), uintptr(accessMask), uintptr(_p0), uintptr(unsafe.Pointer(token)), 0, 0) | ||||||
| } |  | ||||||
|  |  | ||||||
| func _lookupPrivilegeName(systemName *uint16, luid *uint64, buffer *uint16, size *uint32) (err error) { |  | ||||||
| 	r1, _, e1 := syscall.Syscall6(procLookupPrivilegeNameW.Addr(), 4, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(luid)), uintptr(unsafe.Pointer(buffer)), uintptr(unsafe.Pointer(size)), 0, 0) |  | ||||||
| 	if r1 == 0 { | 	if r1 == 0 { | ||||||
| 		if e1 != 0 { |  | ||||||
| 		err = errnoErr(e1) | 		err = errnoErr(e1) | ||||||
| 		} else { |  | ||||||
| 			err = syscall.EINVAL |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
| 	return | 	return | ||||||
| } | } | ||||||
|  |  | ||||||
| func lookupPrivilegeDisplayName(systemName string, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) { | func revertToSelf() (err error) { | ||||||
| 	var _p0 *uint16 | 	r1, _, e1 := syscall.Syscall(procRevertToSelf.Addr(), 0, 0, 0, 0) | ||||||
| 	_p0, err = syscall.UTF16PtrFromString(systemName) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	return _lookupPrivilegeDisplayName(_p0, name, buffer, size, languageId) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func _lookupPrivilegeDisplayName(systemName *uint16, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) { |  | ||||||
| 	r1, _, e1 := syscall.Syscall6(procLookupPrivilegeDisplayNameW.Addr(), 5, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(buffer)), uintptr(unsafe.Pointer(size)), uintptr(unsafe.Pointer(languageId)), 0) |  | ||||||
| 	if r1 == 0 { | 	if r1 == 0 { | ||||||
| 		if e1 != 0 { |  | ||||||
| 		err = errnoErr(e1) | 		err = errnoErr(e1) | ||||||
| 		} else { |  | ||||||
| 			err = syscall.EINVAL |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
| 	return | 	return | ||||||
| } | } | ||||||
| @@ -501,22 +238,14 @@ func backupRead(h syscall.Handle, b []byte, bytesRead *uint32, abort bool, proce | |||||||
| 	var _p1 uint32 | 	var _p1 uint32 | ||||||
| 	if abort { | 	if abort { | ||||||
| 		_p1 = 1 | 		_p1 = 1 | ||||||
| 	} else { |  | ||||||
| 		_p1 = 0 |  | ||||||
| 	} | 	} | ||||||
| 	var _p2 uint32 | 	var _p2 uint32 | ||||||
| 	if processSecurity { | 	if processSecurity { | ||||||
| 		_p2 = 1 | 		_p2 = 1 | ||||||
| 	} else { |  | ||||||
| 		_p2 = 0 |  | ||||||
| 	} | 	} | ||||||
| 	r1, _, e1 := syscall.Syscall9(procBackupRead.Addr(), 7, uintptr(h), uintptr(unsafe.Pointer(_p0)), uintptr(len(b)), uintptr(unsafe.Pointer(bytesRead)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(context)), 0, 0) | 	r1, _, e1 := syscall.Syscall9(procBackupRead.Addr(), 7, uintptr(h), uintptr(unsafe.Pointer(_p0)), uintptr(len(b)), uintptr(unsafe.Pointer(bytesRead)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(context)), 0, 0) | ||||||
| 	if r1 == 0 { | 	if r1 == 0 { | ||||||
| 		if e1 != 0 { |  | ||||||
| 		err = errnoErr(e1) | 		err = errnoErr(e1) | ||||||
| 		} else { |  | ||||||
| 			err = syscall.EINVAL |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
| 	return | 	return | ||||||
| } | } | ||||||
| @@ -529,22 +258,162 @@ func backupWrite(h syscall.Handle, b []byte, bytesWritten *uint32, abort bool, p | |||||||
| 	var _p1 uint32 | 	var _p1 uint32 | ||||||
| 	if abort { | 	if abort { | ||||||
| 		_p1 = 1 | 		_p1 = 1 | ||||||
| 	} else { |  | ||||||
| 		_p1 = 0 |  | ||||||
| 	} | 	} | ||||||
| 	var _p2 uint32 | 	var _p2 uint32 | ||||||
| 	if processSecurity { | 	if processSecurity { | ||||||
| 		_p2 = 1 | 		_p2 = 1 | ||||||
| 	} else { |  | ||||||
| 		_p2 = 0 |  | ||||||
| 	} | 	} | ||||||
| 	r1, _, e1 := syscall.Syscall9(procBackupWrite.Addr(), 7, uintptr(h), uintptr(unsafe.Pointer(_p0)), uintptr(len(b)), uintptr(unsafe.Pointer(bytesWritten)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(context)), 0, 0) | 	r1, _, e1 := syscall.Syscall9(procBackupWrite.Addr(), 7, uintptr(h), uintptr(unsafe.Pointer(_p0)), uintptr(len(b)), uintptr(unsafe.Pointer(bytesWritten)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(context)), 0, 0) | ||||||
| 	if r1 == 0 { | 	if r1 == 0 { | ||||||
| 		if e1 != 0 { |  | ||||||
| 		err = errnoErr(e1) | 		err = errnoErr(e1) | ||||||
| 		} else { |  | ||||||
| 			err = syscall.EINVAL |  | ||||||
| 	} | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func cancelIoEx(file syscall.Handle, o *syscall.Overlapped) (err error) { | ||||||
|  | 	r1, _, e1 := syscall.Syscall(procCancelIoEx.Addr(), 2, uintptr(file), uintptr(unsafe.Pointer(o)), 0) | ||||||
|  | 	if r1 == 0 { | ||||||
|  | 		err = errnoErr(e1) | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) { | ||||||
|  | 	r1, _, e1 := syscall.Syscall(procConnectNamedPipe.Addr(), 2, uintptr(pipe), uintptr(unsafe.Pointer(o)), 0) | ||||||
|  | 	if r1 == 0 { | ||||||
|  | 		err = errnoErr(e1) | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func createFile(name string, access uint32, mode uint32, sa *syscall.SecurityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) { | ||||||
|  | 	var _p0 *uint16 | ||||||
|  | 	_p0, err = syscall.UTF16PtrFromString(name) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	return _createFile(_p0, access, mode, sa, createmode, attrs, templatefile) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func _createFile(name *uint16, access uint32, mode uint32, sa *syscall.SecurityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) { | ||||||
|  | 	r0, _, e1 := syscall.Syscall9(procCreateFileW.Addr(), 7, uintptr(unsafe.Pointer(name)), uintptr(access), uintptr(mode), uintptr(unsafe.Pointer(sa)), uintptr(createmode), uintptr(attrs), uintptr(templatefile), 0, 0) | ||||||
|  | 	handle = syscall.Handle(r0) | ||||||
|  | 	if handle == syscall.InvalidHandle { | ||||||
|  | 		err = errnoErr(e1) | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func createIoCompletionPort(file syscall.Handle, port syscall.Handle, key uintptr, threadCount uint32) (newport syscall.Handle, err error) { | ||||||
|  | 	r0, _, e1 := syscall.Syscall6(procCreateIoCompletionPort.Addr(), 4, uintptr(file), uintptr(port), uintptr(key), uintptr(threadCount), 0, 0) | ||||||
|  | 	newport = syscall.Handle(r0) | ||||||
|  | 	if newport == 0 { | ||||||
|  | 		err = errnoErr(e1) | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *syscall.SecurityAttributes) (handle syscall.Handle, err error) { | ||||||
|  | 	var _p0 *uint16 | ||||||
|  | 	_p0, err = syscall.UTF16PtrFromString(name) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	return _createNamedPipe(_p0, flags, pipeMode, maxInstances, outSize, inSize, defaultTimeout, sa) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func _createNamedPipe(name *uint16, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *syscall.SecurityAttributes) (handle syscall.Handle, err error) { | ||||||
|  | 	r0, _, e1 := syscall.Syscall9(procCreateNamedPipeW.Addr(), 8, uintptr(unsafe.Pointer(name)), uintptr(flags), uintptr(pipeMode), uintptr(maxInstances), uintptr(outSize), uintptr(inSize), uintptr(defaultTimeout), uintptr(unsafe.Pointer(sa)), 0) | ||||||
|  | 	handle = syscall.Handle(r0) | ||||||
|  | 	if handle == syscall.InvalidHandle { | ||||||
|  | 		err = errnoErr(e1) | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func getCurrentThread() (h syscall.Handle) { | ||||||
|  | 	r0, _, _ := syscall.Syscall(procGetCurrentThread.Addr(), 0, 0, 0, 0) | ||||||
|  | 	h = syscall.Handle(r0) | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func getNamedPipeHandleState(pipe syscall.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) { | ||||||
|  | 	r1, _, e1 := syscall.Syscall9(procGetNamedPipeHandleStateW.Addr(), 7, uintptr(pipe), uintptr(unsafe.Pointer(state)), uintptr(unsafe.Pointer(curInstances)), uintptr(unsafe.Pointer(maxCollectionCount)), uintptr(unsafe.Pointer(collectDataTimeout)), uintptr(unsafe.Pointer(userName)), uintptr(maxUserNameSize), 0, 0) | ||||||
|  | 	if r1 == 0 { | ||||||
|  | 		err = errnoErr(e1) | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func getNamedPipeInfo(pipe syscall.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) { | ||||||
|  | 	r1, _, e1 := syscall.Syscall6(procGetNamedPipeInfo.Addr(), 5, uintptr(pipe), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(outSize)), uintptr(unsafe.Pointer(inSize)), uintptr(unsafe.Pointer(maxInstances)), 0) | ||||||
|  | 	if r1 == 0 { | ||||||
|  | 		err = errnoErr(e1) | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func getQueuedCompletionStatus(port syscall.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) { | ||||||
|  | 	r1, _, e1 := syscall.Syscall6(procGetQueuedCompletionStatus.Addr(), 5, uintptr(port), uintptr(unsafe.Pointer(bytes)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(o)), uintptr(timeout), 0) | ||||||
|  | 	if r1 == 0 { | ||||||
|  | 		err = errnoErr(e1) | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func localAlloc(uFlags uint32, length uint32) (ptr uintptr) { | ||||||
|  | 	r0, _, _ := syscall.Syscall(procLocalAlloc.Addr(), 2, uintptr(uFlags), uintptr(length), 0) | ||||||
|  | 	ptr = uintptr(r0) | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func localFree(mem uintptr) { | ||||||
|  | 	syscall.Syscall(procLocalFree.Addr(), 1, uintptr(mem), 0, 0) | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func setFileCompletionNotificationModes(h syscall.Handle, flags uint8) (err error) { | ||||||
|  | 	r1, _, e1 := syscall.Syscall(procSetFileCompletionNotificationModes.Addr(), 2, uintptr(h), uintptr(flags), 0) | ||||||
|  | 	if r1 == 0 { | ||||||
|  | 		err = errnoErr(e1) | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func ntCreateNamedPipeFile(pipe *syscall.Handle, access uint32, oa *objectAttributes, iosb *ioStatusBlock, share uint32, disposition uint32, options uint32, typ uint32, readMode uint32, completionMode uint32, maxInstances uint32, inboundQuota uint32, outputQuota uint32, timeout *int64) (status ntstatus) { | ||||||
|  | 	r0, _, _ := syscall.Syscall15(procNtCreateNamedPipeFile.Addr(), 14, uintptr(unsafe.Pointer(pipe)), uintptr(access), uintptr(unsafe.Pointer(oa)), uintptr(unsafe.Pointer(iosb)), uintptr(share), uintptr(disposition), uintptr(options), uintptr(typ), uintptr(readMode), uintptr(completionMode), uintptr(maxInstances), uintptr(inboundQuota), uintptr(outputQuota), uintptr(unsafe.Pointer(timeout)), 0) | ||||||
|  | 	status = ntstatus(r0) | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func rtlDefaultNpAcl(dacl *uintptr) (status ntstatus) { | ||||||
|  | 	r0, _, _ := syscall.Syscall(procRtlDefaultNpAcl.Addr(), 1, uintptr(unsafe.Pointer(dacl)), 0, 0) | ||||||
|  | 	status = ntstatus(r0) | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func rtlDosPathNameToNtPathName(name *uint16, ntName *unicodeString, filePart uintptr, reserved uintptr) (status ntstatus) { | ||||||
|  | 	r0, _, _ := syscall.Syscall6(procRtlDosPathNameToNtPathName_U.Addr(), 4, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(ntName)), uintptr(filePart), uintptr(reserved), 0, 0) | ||||||
|  | 	status = ntstatus(r0) | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func rtlNtStatusToDosError(status ntstatus) (winerr error) { | ||||||
|  | 	r0, _, _ := syscall.Syscall(procRtlNtStatusToDosErrorNoTeb.Addr(), 1, uintptr(status), 0, 0) | ||||||
|  | 	if r0 != 0 { | ||||||
|  | 		winerr = syscall.Errno(r0) | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func wsaGetOverlappedResult(h syscall.Handle, o *syscall.Overlapped, bytes *uint32, wait bool, flags *uint32) (err error) { | ||||||
|  | 	var _p0 uint32 | ||||||
|  | 	if wait { | ||||||
|  | 		_p0 = 1 | ||||||
|  | 	} | ||||||
|  | 	r1, _, e1 := syscall.Syscall6(procWSAGetOverlappedResult.Addr(), 5, uintptr(h), uintptr(unsafe.Pointer(o)), uintptr(unsafe.Pointer(bytes)), uintptr(_p0), uintptr(unsafe.Pointer(flags)), 0) | ||||||
|  | 	if r1 == 0 { | ||||||
|  | 		err = errnoErr(e1) | ||||||
| 	} | 	} | ||||||
| 	return | 	return | ||||||
| } | } | ||||||
| @@ -552,11 +421,7 @@ func backupWrite(h syscall.Handle, b []byte, bytesWritten *uint32, abort bool, p | |||||||
| func bind(s syscall.Handle, name unsafe.Pointer, namelen int32) (err error) { | func bind(s syscall.Handle, name unsafe.Pointer, namelen int32) (err error) { | ||||||
| 	r1, _, e1 := syscall.Syscall(procbind.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen)) | 	r1, _, e1 := syscall.Syscall(procbind.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen)) | ||||||
| 	if r1 == socketError { | 	if r1 == socketError { | ||||||
| 		if e1 != 0 { |  | ||||||
| 		err = errnoErr(e1) | 		err = errnoErr(e1) | ||||||
| 		} else { |  | ||||||
| 			err = syscall.EINVAL |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
| 	return | 	return | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										3
									
								
								vendor/github.com/ProtonMail/go-crypto/AUTHORS
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								vendor/github.com/ProtonMail/go-crypto/AUTHORS
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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. | ||||||
							
								
								
									
										3
									
								
								vendor/github.com/ProtonMail/go-crypto/CONTRIBUTORS
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								vendor/github.com/ProtonMail/go-crypto/CONTRIBUTORS
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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. | ||||||
							
								
								
									
										27
									
								
								vendor/github.com/ProtonMail/go-crypto/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								vendor/github.com/ProtonMail/go-crypto/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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. | ||||||
							
								
								
									
										22
									
								
								vendor/github.com/ProtonMail/go-crypto/PATENTS
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								vendor/github.com/ProtonMail/go-crypto/PATENTS
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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. | ||||||
							
								
								
									
										381
									
								
								vendor/github.com/ProtonMail/go-crypto/bitcurves/bitcurve.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										381
									
								
								vendor/github.com/ProtonMail/go-crypto/bitcurves/bitcurve.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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 | ||||||
|  | } | ||||||
							
								
								
									
										134
									
								
								vendor/github.com/ProtonMail/go-crypto/brainpool/brainpool.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								vendor/github.com/ProtonMail/go-crypto/brainpool/brainpool.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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 | ||||||
|  | } | ||||||
							
								
								
									
										83
									
								
								vendor/github.com/ProtonMail/go-crypto/brainpool/rcurve.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								vendor/github.com/ProtonMail/go-crypto/brainpool/rcurve.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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)) | ||||||
|  | } | ||||||
							
								
								
									
										162
									
								
								vendor/github.com/ProtonMail/go-crypto/eax/eax.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										162
									
								
								vendor/github.com/ProtonMail/go-crypto/eax/eax.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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) | ||||||
|  | } | ||||||
							
								
								
									
										58
									
								
								vendor/github.com/ProtonMail/go-crypto/eax/eax_test_vectors.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								vendor/github.com/ProtonMail/go-crypto/eax/eax_test_vectors.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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"}, | ||||||
|  | } | ||||||
							
								
								
									
										131
									
								
								vendor/github.com/ProtonMail/go-crypto/eax/random_vectors.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										131
									
								
								vendor/github.com/ProtonMail/go-crypto/eax/random_vectors.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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 | ||||||
|  | } | ||||||
|  |  | ||||||
							
								
								
									
										317
									
								
								vendor/github.com/ProtonMail/go-crypto/ocb/ocb.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										317
									
								
								vendor/github.com/ProtonMail/go-crypto/ocb/ocb.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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) | ||||||
|  | } | ||||||
							
								
								
									
										136
									
								
								vendor/github.com/ProtonMail/go-crypto/ocb/random_vectors.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										136
									
								
								vendor/github.com/ProtonMail/go-crypto/ocb/random_vectors.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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 | ||||||
|  | } | ||||||
| @@ -4,13 +4,13 @@ | |||||||
| 
 | 
 | ||||||
| // Package armor implements OpenPGP ASCII Armor, see RFC 4880. OpenPGP Armor is | // Package armor implements OpenPGP ASCII Armor, see RFC 4880. OpenPGP Armor is | ||||||
| // very similar to PEM except that it has an additional CRC checksum. | // very similar to PEM except that it has an additional CRC checksum. | ||||||
| package armor // import "golang.org/x/crypto/openpgp/armor" | package armor // import "github.com/ProtonMail/go-crypto/openpgp/armor" | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"bufio" | 	"bufio" | ||||||
| 	"bytes" | 	"bytes" | ||||||
| 	"encoding/base64" | 	"encoding/base64" | ||||||
| 	"golang.org/x/crypto/openpgp/errors" | 	"github.com/ProtonMail/go-crypto/openpgp/errors" | ||||||
| 	"io" | 	"io" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| @@ -4,7 +4,10 @@ | |||||||
| 
 | 
 | ||||||
| package openpgp | package openpgp | ||||||
| 
 | 
 | ||||||
| import "hash" | import ( | ||||||
|  | 	"hash" | ||||||
|  | 	"io" | ||||||
|  | ) | ||||||
| 
 | 
 | ||||||
| // NewCanonicalTextHash reformats text written to it into the canonical | // NewCanonicalTextHash reformats text written to it into the canonical | ||||||
| // form and then applies the hash h.  See RFC 4880, section 5.2.1. | // form and then applies the hash h.  See RFC 4880, section 5.2.1. | ||||||
| @@ -19,28 +22,31 @@ type canonicalTextHash struct { | |||||||
| 
 | 
 | ||||||
| var newline = []byte{'\r', '\n'} | var newline = []byte{'\r', '\n'} | ||||||
| 
 | 
 | ||||||
| func (cth *canonicalTextHash) Write(buf []byte) (int, error) { | func writeCanonical(cw io.Writer, buf []byte, s *int) (int, error) { | ||||||
| 	start := 0 | 	start := 0 | ||||||
| 
 |  | ||||||
| 	for i, c := range buf { | 	for i, c := range buf { | ||||||
| 		switch cth.s { | 		switch *s { | ||||||
| 		case 0: | 		case 0: | ||||||
| 			if c == '\r' { | 			if c == '\r' { | ||||||
| 				cth.s = 1 | 				*s = 1 | ||||||
| 			} else if c == '\n' { | 			} else if c == '\n' { | ||||||
| 				cth.h.Write(buf[start:i]) | 				cw.Write(buf[start:i]) | ||||||
| 				cth.h.Write(newline) | 				cw.Write(newline) | ||||||
| 				start = i + 1 | 				start = i + 1 | ||||||
| 			} | 			} | ||||||
| 		case 1: | 		case 1: | ||||||
| 			cth.s = 0 | 			*s = 0 | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	cth.h.Write(buf[start:]) | 	cw.Write(buf[start:]) | ||||||
| 	return len(buf), nil | 	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 { | func (cth *canonicalTextHash) Sum(in []byte) []byte { | ||||||
| 	return cth.h.Sum(in) | 	return cth.h.Sum(in) | ||||||
| } | } | ||||||
							
								
								
									
										165
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/ecdh/ecdh.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										165
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/ecdh/ecdh.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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. | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										157
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/ecdh/x25519.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										157
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/ecdh/x25519.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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] | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @@ -10,7 +10,7 @@ | |||||||
| // This form of ElGamal embeds PKCS#1 v1.5 padding, which may make it | // 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 | // unsuitable for other protocols. RSA should be used in preference in any | ||||||
| // case. | // case. | ||||||
| package elgamal // import "golang.org/x/crypto/openpgp/elgamal" | package elgamal // import "github.com/ProtonMail/go-crypto/openpgp/elgamal" | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"crypto/rand" | 	"crypto/rand" | ||||||
| @@ -3,7 +3,7 @@ | |||||||
| // license that can be found in the LICENSE file. | // license that can be found in the LICENSE file. | ||||||
| 
 | 
 | ||||||
| // Package errors contains common error types for the OpenPGP packages. | // Package errors contains common error types for the OpenPGP packages. | ||||||
| package errors // import "golang.org/x/crypto/openpgp/errors" | package errors // import "github.com/ProtonMail/go-crypto/openpgp/errors" | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"strconv" | 	"strconv" | ||||||
| @@ -41,6 +41,25 @@ func (b SignatureError) Error() string { | |||||||
| 	return "openpgp: invalid signature: " + string(b) | 	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 | type keyIncorrectError int | ||||||
| 
 | 
 | ||||||
| func (ki keyIncorrectError) Error() string { | func (ki keyIncorrectError) Error() string { | ||||||
| @@ -49,6 +68,14 @@ func (ki keyIncorrectError) Error() string { | |||||||
| 
 | 
 | ||||||
| var ErrKeyIncorrect error = keyIncorrectError(0) | 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 | type unknownIssuerError int | ||||||
| 
 | 
 | ||||||
| func (unknownIssuerError) Error() string { | func (unknownIssuerError) Error() string { | ||||||
| @@ -70,3 +97,20 @@ type UnknownPacketTypeError uint8 | |||||||
| func (upte UnknownPacketTypeError) Error() string { | func (upte UnknownPacketTypeError) Error() string { | ||||||
| 	return "openpgp: unknown packet type: " + strconv.Itoa(int(upte)) | 	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 | ||||||
|  | } | ||||||
							
								
								
									
										375
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/key_generation.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										375
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/key_generation.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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 | ||||||
|  | } | ||||||
| @@ -5,13 +5,13 @@ | |||||||
| package openpgp | package openpgp | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"crypto/rsa" | 	goerrors "errors" | ||||||
| 	"io" | 	"io" | ||||||
| 	"time" | 	"time" | ||||||
| 
 | 
 | ||||||
| 	"golang.org/x/crypto/openpgp/armor" | 	"github.com/ProtonMail/go-crypto/openpgp/armor" | ||||||
| 	"golang.org/x/crypto/openpgp/errors" | 	"github.com/ProtonMail/go-crypto/openpgp/errors" | ||||||
| 	"golang.org/x/crypto/openpgp/packet" | 	"github.com/ProtonMail/go-crypto/openpgp/packet" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // PublicKeyType is the armor type for a PGP public key. | // PublicKeyType is the armor type for a PGP public key. | ||||||
| @@ -71,9 +71,9 @@ type KeyRing interface { | |||||||
| 	DecryptionKeys() []Key | 	DecryptionKeys() []Key | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // primaryIdentity returns the Identity marked as primary or the first identity | // PrimaryIdentity returns the Identity marked as primary or the first identity | ||||||
| // if none are so marked. | // if none are so marked. | ||||||
| func (e *Entity) primaryIdentity() *Identity { | func (e *Entity) PrimaryIdentity() *Identity { | ||||||
| 	var firstIdentity *Identity | 	var firstIdentity *Identity | ||||||
| 	for _, ident := range e.Identities { | 	for _, ident := range e.Identities { | ||||||
| 		if firstIdentity == nil { | 		if firstIdentity == nil { | ||||||
| @@ -86,18 +86,24 @@ func (e *Entity) primaryIdentity() *Identity { | |||||||
| 	return firstIdentity | 	return firstIdentity | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // encryptionKey returns the best candidate Key for encrypting a message to the | // EncryptionKey returns the best candidate Key for encrypting a message to the | ||||||
| // given Entity. | // given Entity. | ||||||
| func (e *Entity) encryptionKey(now time.Time) (Key, bool) { | func (e *Entity) EncryptionKey(now time.Time) (Key, bool) { | ||||||
| 	candidateSubkey := -1 | 	// 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 key | 	// Iterate the keys to find the newest, unexpired one | ||||||
|  | 	candidateSubkey := -1 | ||||||
| 	var maxTime time.Time | 	var maxTime time.Time | ||||||
| 	for i, subkey := range e.Subkeys { | 	for i, subkey := range e.Subkeys { | ||||||
| 		if subkey.Sig.FlagsValid && | 		if subkey.Sig.FlagsValid && | ||||||
| 			subkey.Sig.FlagEncryptCommunications && | 			subkey.Sig.FlagEncryptCommunications && | ||||||
| 			subkey.PublicKey.PubKeyAlgo.CanEncrypt() && | 			subkey.PublicKey.PubKeyAlgo.CanEncrypt() && | ||||||
| 			!subkey.Sig.KeyExpired(now) && | 			!subkey.PublicKey.KeyExpired(subkey.Sig, now) && | ||||||
| 			(maxTime.IsZero() || subkey.Sig.CreationTime.After(maxTime)) { | 			(maxTime.IsZero() || subkey.Sig.CreationTime.After(maxTime)) { | ||||||
| 			candidateSubkey = i | 			candidateSubkey = i | ||||||
| 			maxTime = subkey.Sig.CreationTime | 			maxTime = subkey.Sig.CreationTime | ||||||
| @@ -112,30 +118,44 @@ func (e *Entity) encryptionKey(now time.Time) (Key, bool) { | |||||||
| 	// If we don't have any candidate subkeys for encryption and | 	// If we don't have any candidate subkeys for encryption and | ||||||
| 	// the primary key doesn't have any usage metadata then we | 	// the primary key doesn't have any usage metadata then we | ||||||
| 	// assume that the primary key is ok. Or, if the primary key is | 	// assume that the primary key is ok. Or, if the primary key is | ||||||
| 	// marked as ok to encrypt to, then we can obviously use it. | 	// marked as ok to encrypt with, then we can obviously use it. | ||||||
| 	i := e.primaryIdentity() | 	// Also, check expiry again just to be safe. | ||||||
| 	if !i.SelfSignature.FlagsValid || i.SelfSignature.FlagEncryptCommunications && | 	if !i.SelfSignature.FlagsValid || i.SelfSignature.FlagEncryptCommunications && | ||||||
| 		e.PrimaryKey.PubKeyAlgo.CanEncrypt() && | 		e.PrimaryKey.PubKeyAlgo.CanEncrypt() && !primaryKeyExpired { | ||||||
| 		!i.SelfSignature.KeyExpired(now) { |  | ||||||
| 		return Key{e, e.PrimaryKey, e.PrivateKey, i.SelfSignature}, true | 		return Key{e, e.PrimaryKey, e.PrivateKey, i.SelfSignature}, true | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// This Entity appears to be signing only. |  | ||||||
| 	return Key{}, false | 	return Key{}, false | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // signingKey return the best candidate Key for signing a message with this | // SigningKey return the best candidate Key for signing a message with this | ||||||
| // Entity. | // Entity. | ||||||
| func (e *Entity) signingKey(now time.Time) (Key, bool) { | func (e *Entity) SigningKey(now time.Time) (Key, bool) { | ||||||
| 	candidateSubkey := -1 | 	return e.SigningKeyById(now, 0) | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| 	for i, subkey := range e.Subkeys { | // 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 && | 		if subkey.Sig.FlagsValid && | ||||||
| 			subkey.Sig.FlagSign && | 			subkey.Sig.FlagSign && | ||||||
| 			subkey.PublicKey.PubKeyAlgo.CanSign() && | 			subkey.PublicKey.PubKeyAlgo.CanSign() && | ||||||
| 			!subkey.Sig.KeyExpired(now) { | 			!subkey.PublicKey.KeyExpired(subkey.Sig, now) && | ||||||
| 			candidateSubkey = i | 			(maxTime.IsZero() || subkey.Sig.CreationTime.After(maxTime)) && | ||||||
| 			break | 			(id == 0 || subkey.PrivateKey.KeyId == id) { | ||||||
|  | 			candidateSubkey = idx | ||||||
|  | 			maxTime = subkey.Sig.CreationTime | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @@ -145,13 +165,15 @@ func (e *Entity) signingKey(now time.Time) (Key, bool) { | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// If we have no candidate subkey then we assume that it's ok to sign | 	// If we have no candidate subkey then we assume that it's ok to sign | ||||||
| 	// with the primary key. | 	// with the primary key.  Or, if the primary key is marked as ok to | ||||||
| 	i := e.primaryIdentity() | 	// sign with, then we can use it. Also, check expiry again just to be safe. | ||||||
| 	if !i.SelfSignature.FlagsValid || i.SelfSignature.FlagSign && | 	if !i.SelfSignature.FlagsValid || i.SelfSignature.FlagSign && | ||||||
| 		!i.SelfSignature.KeyExpired(now) { | 		e.PrimaryKey.PubKeyAlgo.CanSign() && !primaryKeyExpired && | ||||||
|  | 		(id == 0 || e.PrivateKey.KeyId == id) { | ||||||
| 		return Key{e, e.PrimaryKey, e.PrivateKey, i.SelfSignature}, true | 		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 | 	return Key{}, false | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @@ -420,11 +442,14 @@ func addUserID(e *Entity, packets *packet.Reader, pkt *packet.UserId) error { | |||||||
| 			break | 			break | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (sig.SigType == packet.SigTypePositiveCert || sig.SigType == packet.SigTypeGenericCert) && sig.IssuerKeyId != nil && *sig.IssuerKeyId == e.PrimaryKey.KeyId { | 		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 { | 			if err = e.PrimaryKey.VerifyUserIdSignature(pkt.Id, e.PrimaryKey, sig); err != nil { | ||||||
| 				return errors.StructuralError("user ID self-signature invalid: " + err.Error()) | 				return errors.StructuralError("user ID self-signature invalid: " + err.Error()) | ||||||
| 			} | 			} | ||||||
|  | 			if identity.SelfSignature == nil || sig.CreationTime.After(identity.SelfSignature.CreationTime) { | ||||||
| 				identity.SelfSignature = sig | 				identity.SelfSignature = sig | ||||||
|  | 			} | ||||||
|  | 			identity.Signatures = append(identity.Signatures, sig) | ||||||
| 			e.Identities[pkt.Id] = identity | 			e.Identities[pkt.Id] = identity | ||||||
| 		} else { | 		} else { | ||||||
| 			identity.Signatures = append(identity.Signatures, sig) | 			identity.Signatures = append(identity.Signatures, sig) | ||||||
| @@ -465,7 +490,6 @@ func addSubkey(e *Entity, packets *packet.Reader, pub *packet.PublicKey, priv *p | |||||||
| 		case packet.SigTypeSubkeyRevocation: | 		case packet.SigTypeSubkeyRevocation: | ||||||
| 			subKey.Sig = sig | 			subKey.Sig = sig | ||||||
| 		case packet.SigTypeSubkeyBinding: | 		case packet.SigTypeSubkeyBinding: | ||||||
| 
 |  | ||||||
| 			if shouldReplaceSubkeySig(subKey.Sig, sig) { | 			if shouldReplaceSubkeySig(subKey.Sig, sig) { | ||||||
| 				subKey.Sig = sig | 				subKey.Sig = sig | ||||||
| 			} | 			} | ||||||
| @@ -497,99 +521,30 @@ func shouldReplaceSubkeySig(existingSig, potentialNewSig *packet.Signature) bool | |||||||
| 	return potentialNewSig.CreationTime.After(existingSig.CreationTime) | 	return potentialNewSig.CreationTime.After(existingSig.CreationTime) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const defaultRSAKeyBits = 2048 |  | ||||||
| 
 |  | ||||||
| // 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() |  | ||||||
| 
 |  | ||||||
| 	bits := defaultRSAKeyBits |  | ||||||
| 	if config != nil && config.RSABits != 0 { |  | ||||||
| 		bits = config.RSABits |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	uid := packet.NewUserId(name, comment, email) |  | ||||||
| 	if uid == nil { |  | ||||||
| 		return nil, errors.InvalidArgumentError("user id field contained invalid characters") |  | ||||||
| 	} |  | ||||||
| 	signingPriv, err := rsa.GenerateKey(config.Random(), bits) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	encryptingPriv, err := rsa.GenerateKey(config.Random(), bits) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	e := &Entity{ |  | ||||||
| 		PrimaryKey: packet.NewRSAPublicKey(creationTime, &signingPriv.PublicKey), |  | ||||||
| 		PrivateKey: packet.NewRSAPrivateKey(creationTime, signingPriv), |  | ||||||
| 		Identities: make(map[string]*Identity), |  | ||||||
| 	} |  | ||||||
| 	isPrimaryId := true |  | ||||||
| 	e.Identities[uid.Id] = &Identity{ |  | ||||||
| 		Name:   uid.Id, |  | ||||||
| 		UserId: uid, |  | ||||||
| 		SelfSignature: &packet.Signature{ |  | ||||||
| 			CreationTime: creationTime, |  | ||||||
| 			SigType:      packet.SigTypePositiveCert, |  | ||||||
| 			PubKeyAlgo:   packet.PubKeyAlgoRSA, |  | ||||||
| 			Hash:         config.Hash(), |  | ||||||
| 			IsPrimaryId:  &isPrimaryId, |  | ||||||
| 			FlagsValid:   true, |  | ||||||
| 			FlagSign:     true, |  | ||||||
| 			FlagCertify:  true, |  | ||||||
| 			IssuerKeyId:  &e.PrimaryKey.KeyId, |  | ||||||
| 		}, |  | ||||||
| 	} |  | ||||||
| 	err = e.Identities[uid.Id].SelfSignature.SignUserId(uid.Id, e.PrimaryKey, e.PrivateKey, config) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// If the user passes in a DefaultHash via packet.Config, |  | ||||||
| 	// set the PreferredHash for the SelfSignature. |  | ||||||
| 	if config != nil && config.DefaultHash != 0 { |  | ||||||
| 		e.Identities[uid.Id].SelfSignature.PreferredHash = []uint8{hashToHashId(config.DefaultHash)} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// Likewise for DefaultCipher. |  | ||||||
| 	if config != nil && config.DefaultCipher != 0 { |  | ||||||
| 		e.Identities[uid.Id].SelfSignature.PreferredSymmetric = []uint8{uint8(config.DefaultCipher)} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	e.Subkeys = make([]Subkey, 1) |  | ||||||
| 	e.Subkeys[0] = Subkey{ |  | ||||||
| 		PublicKey:  packet.NewRSAPublicKey(creationTime, &encryptingPriv.PublicKey), |  | ||||||
| 		PrivateKey: packet.NewRSAPrivateKey(creationTime, encryptingPriv), |  | ||||||
| 		Sig: &packet.Signature{ |  | ||||||
| 			CreationTime:              creationTime, |  | ||||||
| 			SigType:                   packet.SigTypeSubkeyBinding, |  | ||||||
| 			PubKeyAlgo:                packet.PubKeyAlgoRSA, |  | ||||||
| 			Hash:                      config.Hash(), |  | ||||||
| 			FlagsValid:                true, |  | ||||||
| 			FlagEncryptStorage:        true, |  | ||||||
| 			FlagEncryptCommunications: true, |  | ||||||
| 			IssuerKeyId:               &e.PrimaryKey.KeyId, |  | ||||||
| 		}, |  | ||||||
| 	} |  | ||||||
| 	e.Subkeys[0].PublicKey.IsSubkey = true |  | ||||||
| 	e.Subkeys[0].PrivateKey.IsSubkey = true |  | ||||||
| 	err = e.Subkeys[0].Sig.SignKey(e.Subkeys[0].PublicKey, e.PrivateKey, config) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	return e, nil |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // SerializePrivate serializes an Entity, including private key material, but | // SerializePrivate serializes an Entity, including private key material, but | ||||||
| // excluding signatures from other entities, to the given Writer. | // excluding signatures from other entities, to the given Writer. | ||||||
| // Identities and subkeys are re-signed in case they changed since NewEntry. | // Identities and subkeys are re-signed in case they changed since NewEntry. | ||||||
| // If config is nil, sensible defaults will be used. | // If config is nil, sensible defaults will be used. | ||||||
| func (e *Entity) SerializePrivate(w io.Writer, config *packet.Config) (err error) { | 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) | 	err = e.PrivateKey.Serialize(w) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return | 		return | ||||||
| @@ -599,10 +554,12 @@ func (e *Entity) SerializePrivate(w io.Writer, config *packet.Config) (err error | |||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
|  | 		if reSign { | ||||||
| 			err = ident.SelfSignature.SignUserId(ident.UserId.Id, e.PrimaryKey, e.PrivateKey, config) | 			err = ident.SelfSignature.SignUserId(ident.UserId.Id, e.PrimaryKey, e.PrivateKey, config) | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				return | 				return | ||||||
| 			} | 			} | ||||||
|  | 		} | ||||||
| 		err = ident.SelfSignature.Serialize(w) | 		err = ident.SelfSignature.Serialize(w) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return | 			return | ||||||
| @@ -613,10 +570,19 @@ func (e *Entity) SerializePrivate(w io.Writer, config *packet.Config) (err error | |||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
|  | 		if reSign { | ||||||
| 			err = subkey.Sig.SignKey(subkey.PublicKey, e.PrivateKey, config) | 			err = subkey.Sig.SignKey(subkey.PublicKey, e.PrivateKey, config) | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				return | 				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) | 		err = subkey.Sig.Serialize(w) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return | 			return | ||||||
| @@ -637,10 +603,6 @@ func (e *Entity) Serialize(w io.Writer) error { | |||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return err | 			return err | ||||||
| 		} | 		} | ||||||
| 		err = ident.SelfSignature.Serialize(w) |  | ||||||
| 		if err != nil { |  | ||||||
| 			return err |  | ||||||
| 		} |  | ||||||
| 		for _, sig := range ident.Signatures { | 		for _, sig := range ident.Signatures { | ||||||
| 			err = sig.Serialize(w) | 			err = sig.Serialize(w) | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| @@ -679,6 +641,7 @@ func (e *Entity) SignIdentity(identity string, signer *Entity, config *packet.Co | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	sig := &packet.Signature{ | 	sig := &packet.Signature{ | ||||||
|  | 		Version:      signer.PrivateKey.Version, | ||||||
| 		SigType:      packet.SigTypeGenericCert, | 		SigType:      packet.SigTypeGenericCert, | ||||||
| 		PubKeyAlgo:   signer.PrivateKey.PubKeyAlgo, | 		PubKeyAlgo:   signer.PrivateKey.PubKeyAlgo, | ||||||
| 		Hash:         config.Hash(), | 		Hash:         config.Hash(), | ||||||
| @@ -691,3 +654,54 @@ func (e *Entity) SignIdentity(identity string, signer *Entity, config *packet.Co | |||||||
| 	ident.Signatures = append(ident.Signatures, sig) | 	ident.Signatures = append(ident.Signatures, sig) | ||||||
| 	return nil | 	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 | ||||||
|  | } | ||||||
							
								
								
									
										336
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/keys_test_data.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										336
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/keys_test_data.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												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") | ||||||
|  | } | ||||||
| @@ -8,7 +8,7 @@ import ( | |||||||
| 	"compress/bzip2" | 	"compress/bzip2" | ||||||
| 	"compress/flate" | 	"compress/flate" | ||||||
| 	"compress/zlib" | 	"compress/zlib" | ||||||
| 	"golang.org/x/crypto/openpgp/errors" | 	"github.com/ProtonMail/go-crypto/openpgp/errors" | ||||||
| 	"io" | 	"io" | ||||||
| 	"strconv" | 	"strconv" | ||||||
| ) | ) | ||||||
| @@ -8,6 +8,7 @@ import ( | |||||||
| 	"crypto" | 	"crypto" | ||||||
| 	"crypto/rand" | 	"crypto/rand" | ||||||
| 	"io" | 	"io" | ||||||
|  | 	"math/big" | ||||||
| 	"time" | 	"time" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| @@ -46,6 +47,37 @@ type Config struct { | |||||||
| 	// RSABits is the number of bits in new RSA keys made with NewEntity. | 	// RSABits is the number of bits in new RSA keys made with NewEntity. | ||||||
| 	// If zero, then 2048 bit keys are created. | 	// If zero, then 2048 bit keys are created. | ||||||
| 	RSABits int | 	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 { | func (c *Config) Random() io.Reader { | ||||||
| @@ -76,6 +108,22 @@ func (c *Config) Now() time.Time { | |||||||
| 	return c.Time() | 	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 { | func (c *Config) Compression() CompressionAlgo { | ||||||
| 	if c == nil { | 	if c == nil { | ||||||
| 		return CompressionNone | 		return CompressionNone | ||||||
| @@ -89,3 +137,31 @@ func (c *Config) PasswordHashIterations() int { | |||||||
| 	} | 	} | ||||||
| 	return c.S2KCount | 	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 | ||||||
|  | } | ||||||
| @@ -12,8 +12,10 @@ import ( | |||||||
| 	"math/big" | 	"math/big" | ||||||
| 	"strconv" | 	"strconv" | ||||||
| 
 | 
 | ||||||
| 	"golang.org/x/crypto/openpgp/elgamal" | 	"github.com/ProtonMail/go-crypto/openpgp/ecdh" | ||||||
| 	"golang.org/x/crypto/openpgp/errors" | 	"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 | const encryptedKeyVersion = 3 | ||||||
| @@ -26,7 +28,7 @@ type EncryptedKey struct { | |||||||
| 	CipherFunc CipherFunction // only valid after a successful Decrypt | 	CipherFunc CipherFunction // only valid after a successful Decrypt | ||||||
| 	Key        []byte         // only valid after a successful Decrypt | 	Key        []byte         // only valid after a successful Decrypt | ||||||
| 
 | 
 | ||||||
| 	encryptedMPI1, encryptedMPI2 parsedMPI | 	encryptedMPI1, encryptedMPI2 encoding.Field | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (e *EncryptedKey) parse(r io.Reader) (err error) { | func (e *EncryptedKey) parse(r io.Reader) (err error) { | ||||||
| @@ -42,17 +44,28 @@ func (e *EncryptedKey) parse(r io.Reader) (err error) { | |||||||
| 	e.Algo = PublicKeyAlgorithm(buf[9]) | 	e.Algo = PublicKeyAlgorithm(buf[9]) | ||||||
| 	switch e.Algo { | 	switch e.Algo { | ||||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly: | 	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly: | ||||||
| 		e.encryptedMPI1.bytes, e.encryptedMPI1.bitLength, err = readMPI(r) | 		e.encryptedMPI1 = new(encoding.MPI) | ||||||
| 		if err != nil { | 		if _, err = e.encryptedMPI1.ReadFrom(r); err != nil { | ||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
| 	case PubKeyAlgoElGamal: | 	case PubKeyAlgoElGamal: | ||||||
| 		e.encryptedMPI1.bytes, e.encryptedMPI1.bitLength, err = readMPI(r) | 		e.encryptedMPI1 = new(encoding.MPI) | ||||||
| 		if err != nil { | 		if _, err = e.encryptedMPI1.ReadFrom(r); err != nil { | ||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
| 		e.encryptedMPI2.bytes, e.encryptedMPI2.bitLength, err = readMPI(r) | 
 | ||||||
| 		if err != nil { | 		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 | 			return | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @@ -72,6 +85,16 @@ func checksumKeyMaterial(key []byte) uint16 { | |||||||
| // private key must have been decrypted first. | // private key must have been decrypted first. | ||||||
| // If config is nil, sensible defaults will be used. | // If config is nil, sensible defaults will be used. | ||||||
| func (e *EncryptedKey) Decrypt(priv *PrivateKey, config *Config) error { | 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 err error | ||||||
| 	var b []byte | 	var b []byte | ||||||
| 
 | 
 | ||||||
| @@ -81,13 +104,18 @@ func (e *EncryptedKey) Decrypt(priv *PrivateKey, config *Config) error { | |||||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly: | 	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly: | ||||||
| 		// Supports both *rsa.PrivateKey and crypto.Decrypter | 		// Supports both *rsa.PrivateKey and crypto.Decrypter | ||||||
| 		k := priv.PrivateKey.(crypto.Decrypter) | 		k := priv.PrivateKey.(crypto.Decrypter) | ||||||
| 		b, err = k.Decrypt(config.Random(), padToKeySize(k.Public().(*rsa.PublicKey), e.encryptedMPI1.bytes), nil) | 		b, err = k.Decrypt(config.Random(), padToKeySize(k.Public().(*rsa.PublicKey), e.encryptedMPI1.Bytes()), nil) | ||||||
| 	case PubKeyAlgoElGamal: | 	case PubKeyAlgoElGamal: | ||||||
| 		c1 := new(big.Int).SetBytes(e.encryptedMPI1.bytes) | 		c1 := new(big.Int).SetBytes(e.encryptedMPI1.Bytes()) | ||||||
| 		c2 := new(big.Int).SetBytes(e.encryptedMPI2.bytes) | 		c2 := new(big.Int).SetBytes(e.encryptedMPI2.Bytes()) | ||||||
| 		b, err = elgamal.Decrypt(priv.PrivateKey.(*elgamal.PrivateKey), c1, c2) | 		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: | 	default: | ||||||
| 		err = errors.InvalidArgumentError("cannot decrypted encrypted session key with private key of type " + strconv.Itoa(int(priv.PubKeyAlgo))) | 		err = errors.InvalidArgumentError("cannot decrypt encrypted session key with private key of type " + strconv.Itoa(int(priv.PubKeyAlgo))) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| @@ -110,14 +138,19 @@ func (e *EncryptedKey) Serialize(w io.Writer) error { | |||||||
| 	var mpiLen int | 	var mpiLen int | ||||||
| 	switch e.Algo { | 	switch e.Algo { | ||||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly: | 	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly: | ||||||
| 		mpiLen = 2 + len(e.encryptedMPI1.bytes) | 		mpiLen = int(e.encryptedMPI1.EncodedLength()) | ||||||
| 	case PubKeyAlgoElGamal: | 	case PubKeyAlgoElGamal: | ||||||
| 		mpiLen = 2 + len(e.encryptedMPI1.bytes) + 2 + len(e.encryptedMPI2.bytes) | 		mpiLen = int(e.encryptedMPI1.EncodedLength()) + int(e.encryptedMPI2.EncodedLength()) | ||||||
|  | 	case PubKeyAlgoECDH: | ||||||
|  | 		mpiLen = int(e.encryptedMPI1.EncodedLength()) + int(e.encryptedMPI2.EncodedLength()) | ||||||
| 	default: | 	default: | ||||||
| 		return errors.InvalidArgumentError("don't know how to serialize encrypted key type " + strconv.Itoa(int(e.Algo))) | 		return errors.InvalidArgumentError("don't know how to serialize encrypted key type " + strconv.Itoa(int(e.Algo))) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	serializeHeader(w, packetTypeEncryptedKey, 1 /* version */ +8 /* key id */ +1 /* algo */ +mpiLen) | 	err := serializeHeader(w, packetTypeEncryptedKey, 1 /* version */ +8 /* key id */ +1 /* algo */ +mpiLen) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	w.Write([]byte{encryptedKeyVersion}) | 	w.Write([]byte{encryptedKeyVersion}) | ||||||
| 	binary.Write(w, binary.BigEndian, e.KeyId) | 	binary.Write(w, binary.BigEndian, e.KeyId) | ||||||
| @@ -125,14 +158,23 @@ func (e *EncryptedKey) Serialize(w io.Writer) error { | |||||||
| 
 | 
 | ||||||
| 	switch e.Algo { | 	switch e.Algo { | ||||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly: | 	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly: | ||||||
| 		writeMPIs(w, e.encryptedMPI1) | 		_, err := w.Write(e.encryptedMPI1.EncodedBytes()) | ||||||
|  | 		return err | ||||||
| 	case PubKeyAlgoElGamal: | 	case PubKeyAlgoElGamal: | ||||||
| 		writeMPIs(w, e.encryptedMPI1, e.encryptedMPI2) | 		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: | 	default: | ||||||
| 		panic("internal error") | 		panic("internal error") | ||||||
| 	} | 	} | ||||||
| 
 |  | ||||||
| 	return nil |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // SerializeEncryptedKey serializes an encrypted key packet to w that contains | // SerializeEncryptedKey serializes an encrypted key packet to w that contains | ||||||
| @@ -156,6 +198,8 @@ func SerializeEncryptedKey(w io.Writer, pub *PublicKey, cipherFunc CipherFunctio | |||||||
| 		return serializeEncryptedKeyRSA(w, config.Random(), buf, pub.PublicKey.(*rsa.PublicKey), keyBlock) | 		return serializeEncryptedKeyRSA(w, config.Random(), buf, pub.PublicKey.(*rsa.PublicKey), keyBlock) | ||||||
| 	case PubKeyAlgoElGamal: | 	case PubKeyAlgoElGamal: | ||||||
| 		return serializeEncryptedKeyElGamal(w, config.Random(), buf, pub.PublicKey.(*elgamal.PublicKey), keyBlock) | 		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: | 	case PubKeyAlgoDSA, PubKeyAlgoRSASignOnly: | ||||||
| 		return errors.InvalidArgumentError("cannot encrypt to public key of type " + strconv.Itoa(int(pub.PubKeyAlgo))) | 		return errors.InvalidArgumentError("cannot encrypt to public key of type " + strconv.Itoa(int(pub.PubKeyAlgo))) | ||||||
| 	} | 	} | ||||||
| @@ -169,7 +213,8 @@ func serializeEncryptedKeyRSA(w io.Writer, rand io.Reader, header [10]byte, pub | |||||||
| 		return errors.InvalidArgumentError("RSA encryption failed: " + err.Error()) | 		return errors.InvalidArgumentError("RSA encryption failed: " + err.Error()) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	packetLen := 10 /* header length */ + 2 /* mpi size */ + len(cipherText) | 	cipherMPI := encoding.NewMPI(cipherText) | ||||||
|  | 	packetLen := 10 /* header length */ + int(cipherMPI.EncodedLength()) | ||||||
| 
 | 
 | ||||||
| 	err = serializeHeader(w, packetTypeEncryptedKey, packetLen) | 	err = serializeHeader(w, packetTypeEncryptedKey, packetLen) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| @@ -179,7 +224,8 @@ func serializeEncryptedKeyRSA(w io.Writer, rand io.Reader, header [10]byte, pub | |||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 	return writeMPI(w, 8*uint16(len(cipherText)), cipherText) | 	_, err = w.Write(cipherMPI.EncodedBytes()) | ||||||
|  | 	return err | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func serializeEncryptedKeyElGamal(w io.Writer, rand io.Reader, header [10]byte, pub *elgamal.PublicKey, keyBlock []byte) error { | func serializeEncryptedKeyElGamal(w io.Writer, rand io.Reader, header [10]byte, pub *elgamal.PublicKey, keyBlock []byte) error { | ||||||
| @@ -200,9 +246,37 @@ func serializeEncryptedKeyElGamal(w io.Writer, rand io.Reader, header [10]byte, | |||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 	err = writeBig(w, c1) | 	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 { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 	return writeBig(w, c2) | 
 | ||||||
|  | 	_, 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 | ||||||
| } | } | ||||||
| @@ -11,6 +11,7 @@ import ( | |||||||
| 
 | 
 | ||||||
| // LiteralData represents an encrypted file. See RFC 4880, section 5.9. | // LiteralData represents an encrypted file. See RFC 4880, section 5.9. | ||||||
| type LiteralData struct { | type LiteralData struct { | ||||||
|  | 	Format   uint8 | ||||||
| 	IsBinary bool | 	IsBinary bool | ||||||
| 	FileName string | 	FileName string | ||||||
| 	Time     uint32 // Unix epoch time. Either creation time or modification time. 0 means undefined. | 	Time     uint32 // Unix epoch time. Either creation time or modification time. 0 means undefined. | ||||||
| @@ -31,7 +32,8 @@ func (l *LiteralData) parse(r io.Reader) (err error) { | |||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	l.IsBinary = buf[0] == 'b' | 	l.Format = buf[0] | ||||||
|  | 	l.IsBinary = l.Format == 'b' | ||||||
| 	fileNameLen := int(buf[1]) | 	fileNameLen := int(buf[1]) | ||||||
| 
 | 
 | ||||||
| 	_, err = readFull(r, buf[:fileNameLen]) | 	_, err = readFull(r, buf[:fileNameLen]) | ||||||
| @@ -85,8 +85,7 @@ type ocfbDecrypter struct { | |||||||
| // NewOCFBDecrypter returns a cipher.Stream which decrypts data with OpenPGP's | // NewOCFBDecrypter returns a cipher.Stream which decrypts data with OpenPGP's | ||||||
| // cipher feedback mode using the given cipher.Block. Prefix must be the first | // 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 | // blockSize + 2 bytes of the ciphertext, where blockSize is the cipher.Block's | ||||||
| // block size. If an incorrect key is detected then nil is returned. On | // block size. On successful exit, blockSize+2 bytes of decrypted data are written into | ||||||
| // successful exit, blockSize+2 bytes of decrypted data are written into |  | ||||||
| // prefix. Resync determines if the "resynchronization step" from RFC 4880, | // prefix. Resync determines if the "resynchronization step" from RFC 4880, | ||||||
| // 13.9 step 7 is performed. Different parts of OpenPGP vary on this point. | // 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 { | func NewOCFBDecrypter(block cipher.Block, prefix []byte, resync OCFBResyncOption) cipher.Stream { | ||||||
| @@ -112,11 +111,6 @@ func NewOCFBDecrypter(block cipher.Block, prefix []byte, resync OCFBResyncOption | |||||||
| 	prefixCopy[blockSize] ^= x.fre[0] | 	prefixCopy[blockSize] ^= x.fre[0] | ||||||
| 	prefixCopy[blockSize+1] ^= x.fre[1] | 	prefixCopy[blockSize+1] ^= x.fre[1] | ||||||
| 
 | 
 | ||||||
| 	if prefixCopy[blockSize-2] != prefixCopy[blockSize] || |  | ||||||
| 		prefixCopy[blockSize-1] != prefixCopy[blockSize+1] { |  | ||||||
| 		return nil |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if resync { | 	if resync { | ||||||
| 		block.Encrypt(x.fre, prefix[2:]) | 		block.Encrypt(x.fre, prefix[2:]) | ||||||
| 	} else { | 	} else { | ||||||
| @@ -7,8 +7,8 @@ package packet | |||||||
| import ( | import ( | ||||||
| 	"crypto" | 	"crypto" | ||||||
| 	"encoding/binary" | 	"encoding/binary" | ||||||
| 	"golang.org/x/crypto/openpgp/errors" | 	"github.com/ProtonMail/go-crypto/openpgp/errors" | ||||||
| 	"golang.org/x/crypto/openpgp/s2k" | 	"github.com/ProtonMail/go-crypto/openpgp/s2k" | ||||||
| 	"io" | 	"io" | ||||||
| 	"strconv" | 	"strconv" | ||||||
| ) | ) | ||||||
| @@ -9,7 +9,7 @@ import ( | |||||||
| 	"io" | 	"io" | ||||||
| 	"io/ioutil" | 	"io/ioutil" | ||||||
| 
 | 
 | ||||||
| 	"golang.org/x/crypto/openpgp/errors" | 	"github.com/ProtonMail/go-crypto/openpgp/errors" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // OpaquePacket represents an OpenPGP packet as raw, unparsed data. This is | // OpaquePacket represents an OpenPGP packet as raw, unparsed data. This is | ||||||
| @@ -4,20 +4,16 @@ | |||||||
| 
 | 
 | ||||||
| // Package packet implements parsing and serialization of OpenPGP packets, as | // Package packet implements parsing and serialization of OpenPGP packets, as | ||||||
| // specified in RFC 4880. | // specified in RFC 4880. | ||||||
| package packet // import "golang.org/x/crypto/openpgp/packet" | package packet // import "github.com/ProtonMail/go-crypto/openpgp/packet" | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"bufio" | 	"bytes" | ||||||
| 	"crypto/aes" |  | ||||||
| 	"crypto/cipher" | 	"crypto/cipher" | ||||||
| 	"crypto/des" |  | ||||||
| 	"crypto/rsa" | 	"crypto/rsa" | ||||||
| 	"io" | 	"io" | ||||||
| 	"math/big" |  | ||||||
| 	"math/bits" |  | ||||||
| 
 | 
 | ||||||
| 	"golang.org/x/crypto/cast5" | 	"github.com/ProtonMail/go-crypto/openpgp/errors" | ||||||
| 	"golang.org/x/crypto/openpgp/errors" | 	"github.com/ProtonMail/go-crypto/openpgp/internal/algorithm" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // readFull is the same as io.ReadFull except that reading zero bytes returns | // readFull is the same as io.ReadFull except that reading zero bytes returns | ||||||
| @@ -100,68 +96,43 @@ func (r *partialLengthReader) Read(p []byte) (n int, err error) { | |||||||
| // See RFC 4880, section 4.2.2.4. | // See RFC 4880, section 4.2.2.4. | ||||||
| type partialLengthWriter struct { | type partialLengthWriter struct { | ||||||
| 	w          io.WriteCloser | 	w          io.WriteCloser | ||||||
|  | 	buf        bytes.Buffer | ||||||
| 	lengthByte [1]byte | 	lengthByte [1]byte | ||||||
| 	sentFirst  bool |  | ||||||
| 	buf        []byte |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // RFC 4880 4.2.2.4: the first partial length MUST be at least 512 octets long. |  | ||||||
| const minFirstPartialWrite = 512 |  | ||||||
| 
 |  | ||||||
| func (w *partialLengthWriter) Write(p []byte) (n int, err error) { | func (w *partialLengthWriter) Write(p []byte) (n int, err error) { | ||||||
| 	off := 0 | 	bufLen := w.buf.Len() | ||||||
| 	if !w.sentFirst { | 	if bufLen > 512 { | ||||||
| 		if len(w.buf) > 0 || len(p) < minFirstPartialWrite { | 		for power := uint(30); ; power-- { | ||||||
| 			off = len(w.buf) |  | ||||||
| 			w.buf = append(w.buf, p...) |  | ||||||
| 			if len(w.buf) < minFirstPartialWrite { |  | ||||||
| 				return len(p), nil |  | ||||||
| 			} |  | ||||||
| 			p = w.buf |  | ||||||
| 			w.buf = nil |  | ||||||
| 		} |  | ||||||
| 		w.sentFirst = true |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	power := uint8(30) |  | ||||||
| 	for len(p) > 0 { |  | ||||||
| 			l := 1 << power | 			l := 1 << power | ||||||
| 		if len(p) < l { | 			if bufLen >= l { | ||||||
| 			power = uint8(bits.Len32(uint32(len(p)))) - 1 | 				w.lengthByte[0] = 224 + uint8(power) | ||||||
| 			l = 1 << power |  | ||||||
| 		} |  | ||||||
| 		w.lengthByte[0] = 224 + power |  | ||||||
| 				_, err = w.w.Write(w.lengthByte[:]) | 				_, err = w.w.Write(w.lengthByte[:]) | ||||||
| 		if err == nil { |  | ||||||
| 			var m int |  | ||||||
| 			m, err = w.w.Write(p[:l]) |  | ||||||
| 			n += m |  | ||||||
| 		} |  | ||||||
| 				if err != nil { | 				if err != nil { | ||||||
| 			if n < off { | 					return | ||||||
| 				return 0, err |  | ||||||
| 				} | 				} | ||||||
| 			return n - off, err | 				var m int | ||||||
|  | 				m, err = w.w.Write(w.buf.Next(l)) | ||||||
|  | 				if err != nil { | ||||||
|  | 					return | ||||||
| 				} | 				} | ||||||
| 		p = p[l:] | 				if m != l { | ||||||
|  | 					return 0, io.ErrShortWrite | ||||||
| 				} | 				} | ||||||
| 	return n - off, nil | 				break | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return w.buf.Write(p) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (w *partialLengthWriter) Close() error { | func (w *partialLengthWriter) Close() (err error) { | ||||||
| 	if len(w.buf) > 0 { | 	len := w.buf.Len() | ||||||
| 		// In this case we can't send a 512 byte packet. | 	err = serializeLength(w.w, len) | ||||||
| 		// Just send what we have. | 	if err != nil { | ||||||
| 		p := w.buf |  | ||||||
| 		w.sentFirst = true |  | ||||||
| 		w.buf = nil |  | ||||||
| 		if _, err := w.Write(p); err != nil { |  | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 	} | 	_, err = w.buf.WriteTo(w.w) | ||||||
| 
 |  | ||||||
| 	w.lengthByte[0] = 0 |  | ||||||
| 	_, err := w.w.Write(w.lengthByte[:]) |  | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| @@ -246,25 +217,43 @@ func readHeader(r io.Reader) (tag packetType, length int64, contents io.Reader, | |||||||
| // serializeHeader writes an OpenPGP packet header to w. See RFC 4880, section | // serializeHeader writes an OpenPGP packet header to w. See RFC 4880, section | ||||||
| // 4.2. | // 4.2. | ||||||
| func serializeHeader(w io.Writer, ptype packetType, length int) (err error) { | func serializeHeader(w io.Writer, ptype packetType, length int) (err error) { | ||||||
| 	var buf [6]byte | 	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 | 	var n int | ||||||
| 
 | 
 | ||||||
| 	buf[0] = 0x80 | 0x40 | byte(ptype) |  | ||||||
| 	if length < 192 { | 	if length < 192 { | ||||||
| 		buf[1] = byte(length) | 		buf[0] = byte(length) | ||||||
| 		n = 2 | 		n = 1 | ||||||
| 	} else if length < 8384 { | 	} else if length < 8384 { | ||||||
| 		length -= 192 | 		length -= 192 | ||||||
| 		buf[1] = 192 + byte(length>>8) | 		buf[0] = 192 + byte(length>>8) | ||||||
| 		buf[2] = byte(length) | 		buf[1] = byte(length) | ||||||
| 		n = 3 | 		n = 2 | ||||||
| 	} else { | 	} else { | ||||||
| 		buf[1] = 255 | 		buf[0] = 255 | ||||||
| 		buf[2] = byte(length >> 24) | 		buf[1] = byte(length >> 24) | ||||||
| 		buf[3] = byte(length >> 16) | 		buf[2] = byte(length >> 16) | ||||||
| 		buf[4] = byte(length >> 8) | 		buf[3] = byte(length >> 8) | ||||||
| 		buf[5] = byte(length) | 		buf[4] = byte(length) | ||||||
| 		n = 6 | 		n = 5 | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	_, err = w.Write(buf[:n]) | 	_, err = w.Write(buf[:n]) | ||||||
| @@ -275,9 +264,7 @@ func serializeHeader(w io.Writer, ptype packetType, length int) (err error) { | |||||||
| // length of the packet is unknown. It returns a io.WriteCloser which can be | // 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. | // 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) { | func serializeStreamHeader(w io.WriteCloser, ptype packetType) (out io.WriteCloser, err error) { | ||||||
| 	var buf [1]byte | 	err = serializeType(w, ptype) | ||||||
| 	buf[0] = 0x80 | 0x40 | byte(ptype) |  | ||||||
| 	_, err = w.Write(buf[:]) |  | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| @@ -329,19 +316,13 @@ const ( | |||||||
| 	packetTypePublicSubkey              packetType = 14 | 	packetTypePublicSubkey              packetType = 14 | ||||||
| 	packetTypeUserAttribute             packetType = 17 | 	packetTypeUserAttribute             packetType = 17 | ||||||
| 	packetTypeSymmetricallyEncryptedMDC packetType = 18 | 	packetTypeSymmetricallyEncryptedMDC packetType = 18 | ||||||
|  | 	packetTypeAEADEncrypted             packetType = 20 | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // peekVersion detects the version of a public key packet about to | // EncryptedDataPacket holds encrypted data. It is currently implemented by | ||||||
| // be read. A bufio.Reader at the original position of the io.Reader | // SymmetricallyEncrypted and AEADEncrypted. | ||||||
| // is returned. | type EncryptedDataPacket interface { | ||||||
| func peekVersion(r io.Reader) (bufr *bufio.Reader, ver byte, err error) { | 	Decrypt(CipherFunction, []byte) (io.ReadCloser, error) | ||||||
| 	bufr = bufio.NewReader(r) |  | ||||||
| 	var verBuf []byte |  | ||||||
| 	if verBuf, err = bufr.Peek(1); err != nil { |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	ver = verBuf[0] |  | ||||||
| 	return |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Read reads a single OpenPGP packet from the given io.Reader. If there is an | // Read reads a single OpenPGP packet from the given io.Reader. If there is an | ||||||
| @@ -356,16 +337,7 @@ func Read(r io.Reader) (p Packet, err error) { | |||||||
| 	case packetTypeEncryptedKey: | 	case packetTypeEncryptedKey: | ||||||
| 		p = new(EncryptedKey) | 		p = new(EncryptedKey) | ||||||
| 	case packetTypeSignature: | 	case packetTypeSignature: | ||||||
| 		var version byte |  | ||||||
| 		// Detect signature version |  | ||||||
| 		if contents, version, err = peekVersion(contents); err != nil { |  | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
| 		if version < 4 { |  | ||||||
| 			p = new(SignatureV3) |  | ||||||
| 		} else { |  | ||||||
| 		p = new(Signature) | 		p = new(Signature) | ||||||
| 		} |  | ||||||
| 	case packetTypeSymmetricKeyEncrypted: | 	case packetTypeSymmetricKeyEncrypted: | ||||||
| 		p = new(SymmetricKeyEncrypted) | 		p = new(SymmetricKeyEncrypted) | ||||||
| 	case packetTypeOnePassSignature: | 	case packetTypeOnePassSignature: | ||||||
| @@ -377,20 +349,12 @@ func Read(r io.Reader) (p Packet, err error) { | |||||||
| 		} | 		} | ||||||
| 		p = pk | 		p = pk | ||||||
| 	case packetTypePublicKey, packetTypePublicSubkey: | 	case packetTypePublicKey, packetTypePublicSubkey: | ||||||
| 		var version byte |  | ||||||
| 		if contents, version, err = peekVersion(contents); err != nil { |  | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
| 		isSubkey := tag == packetTypePublicSubkey | 		isSubkey := tag == packetTypePublicSubkey | ||||||
| 		if version < 4 { |  | ||||||
| 			p = &PublicKeyV3{IsSubkey: isSubkey} |  | ||||||
| 		} else { |  | ||||||
| 		p = &PublicKey{IsSubkey: isSubkey} | 		p = &PublicKey{IsSubkey: isSubkey} | ||||||
| 		} |  | ||||||
| 	case packetTypeCompressed: | 	case packetTypeCompressed: | ||||||
| 		p = new(Compressed) | 		p = new(Compressed) | ||||||
| 	case packetTypeSymmetricallyEncrypted: | 	case packetTypeSymmetricallyEncrypted: | ||||||
| 		p = new(SymmetricallyEncrypted) | 		err = errors.UnsupportedError("Symmetrically encrypted packets without MDC are not supported") | ||||||
| 	case packetTypeLiteralData: | 	case packetTypeLiteralData: | ||||||
| 		p = new(LiteralData) | 		p = new(LiteralData) | ||||||
| 	case packetTypeUserId: | 	case packetTypeUserId: | ||||||
| @@ -401,6 +365,8 @@ func Read(r io.Reader) (p Packet, err error) { | |||||||
| 		se := new(SymmetricallyEncrypted) | 		se := new(SymmetricallyEncrypted) | ||||||
| 		se.MDC = true | 		se.MDC = true | ||||||
| 		p = se | 		p = se | ||||||
|  | 	case packetTypeAEADEncrypted: | ||||||
|  | 		p = new(AEADEncrypted) | ||||||
| 	default: | 	default: | ||||||
| 		err = errors.UnknownPacketTypeError(tag) | 		err = errors.UnknownPacketTypeError(tag) | ||||||
| 	} | 	} | ||||||
| @@ -418,8 +384,8 @@ func Read(r io.Reader) (p Packet, err error) { | |||||||
| type SignatureType uint8 | type SignatureType uint8 | ||||||
| 
 | 
 | ||||||
| const ( | const ( | ||||||
| 	SigTypeBinary            SignatureType = 0 | 	SigTypeBinary            SignatureType = 0x00 | ||||||
| 	SigTypeText                            = 1 | 	SigTypeText                            = 0x01 | ||||||
| 	SigTypeGenericCert                     = 0x10 | 	SigTypeGenericCert                     = 0x10 | ||||||
| 	SigTypePersonaCert                     = 0x11 | 	SigTypePersonaCert                     = 0x11 | ||||||
| 	SigTypeCasualCert                      = 0x12 | 	SigTypeCasualCert                      = 0x12 | ||||||
| @@ -443,6 +409,8 @@ const ( | |||||||
| 	// RFC 6637, Section 5. | 	// RFC 6637, Section 5. | ||||||
| 	PubKeyAlgoECDH  PublicKeyAlgorithm = 18 | 	PubKeyAlgoECDH  PublicKeyAlgorithm = 18 | ||||||
| 	PubKeyAlgoECDSA PublicKeyAlgorithm = 19 | 	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. | 	// Deprecated in RFC 4880, Section 13.5. Use key flags instead. | ||||||
| 	PubKeyAlgoRSAEncryptOnly PublicKeyAlgorithm = 2 | 	PubKeyAlgoRSAEncryptOnly PublicKeyAlgorithm = 2 | ||||||
| @@ -453,7 +421,7 @@ const ( | |||||||
| // key of the given type. | // key of the given type. | ||||||
| func (pka PublicKeyAlgorithm) CanEncrypt() bool { | func (pka PublicKeyAlgorithm) CanEncrypt() bool { | ||||||
| 	switch pka { | 	switch pka { | ||||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoElGamal: | 	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoElGamal, PubKeyAlgoECDH: | ||||||
| 		return true | 		return true | ||||||
| 	} | 	} | ||||||
| 	return false | 	return false | ||||||
| @@ -463,7 +431,7 @@ func (pka PublicKeyAlgorithm) CanEncrypt() bool { | |||||||
| // sign a message. | // sign a message. | ||||||
| func (pka PublicKeyAlgorithm) CanSign() bool { | func (pka PublicKeyAlgorithm) CanSign() bool { | ||||||
| 	switch pka { | 	switch pka { | ||||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA, PubKeyAlgoECDSA: | 	case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA, PubKeyAlgoECDSA, PubKeyAlgoEdDSA: | ||||||
| 		return true | 		return true | ||||||
| 	} | 	} | ||||||
| 	return false | 	return false | ||||||
| @@ -471,7 +439,7 @@ func (pka PublicKeyAlgorithm) CanSign() bool { | |||||||
| 
 | 
 | ||||||
| // CipherFunction represents the different block ciphers specified for OpenPGP. See | // CipherFunction represents the different block ciphers specified for OpenPGP. See | ||||||
| // http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-13 | // http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-13 | ||||||
| type CipherFunction uint8 | type CipherFunction algorithm.CipherFunction | ||||||
| 
 | 
 | ||||||
| const ( | const ( | ||||||
| 	Cipher3DES   CipherFunction = 2 | 	Cipher3DES   CipherFunction = 2 | ||||||
| @@ -483,81 +451,17 @@ const ( | |||||||
| 
 | 
 | ||||||
| // KeySize returns the key size, in bytes, of cipher. | // KeySize returns the key size, in bytes, of cipher. | ||||||
| func (cipher CipherFunction) KeySize() int { | func (cipher CipherFunction) KeySize() int { | ||||||
| 	switch cipher { | 	return algorithm.CipherFunction(cipher).KeySize() | ||||||
| 	case Cipher3DES: |  | ||||||
| 		return 24 |  | ||||||
| 	case CipherCAST5: |  | ||||||
| 		return cast5.KeySize |  | ||||||
| 	case CipherAES128: |  | ||||||
| 		return 16 |  | ||||||
| 	case CipherAES192: |  | ||||||
| 		return 24 |  | ||||||
| 	case CipherAES256: |  | ||||||
| 		return 32 |  | ||||||
| 	} |  | ||||||
| 	return 0 |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // blockSize returns the block size, in bytes, of cipher. | // blockSize returns the block size, in bytes, of cipher. | ||||||
| func (cipher CipherFunction) blockSize() int { | func (cipher CipherFunction) blockSize() int { | ||||||
| 	switch cipher { | 	return algorithm.CipherFunction(cipher).BlockSize() | ||||||
| 	case Cipher3DES: |  | ||||||
| 		return des.BlockSize |  | ||||||
| 	case CipherCAST5: |  | ||||||
| 		return 8 |  | ||||||
| 	case CipherAES128, CipherAES192, CipherAES256: |  | ||||||
| 		return 16 |  | ||||||
| 	} |  | ||||||
| 	return 0 |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // new returns a fresh instance of the given cipher. | // new returns a fresh instance of the given cipher. | ||||||
| func (cipher CipherFunction) new(key []byte) (block cipher.Block) { | func (cipher CipherFunction) new(key []byte) (block cipher.Block) { | ||||||
| 	switch cipher { | 	return algorithm.CipherFunction(cipher).New(key) | ||||||
| 	case Cipher3DES: |  | ||||||
| 		block, _ = des.NewTripleDESCipher(key) |  | ||||||
| 	case CipherCAST5: |  | ||||||
| 		block, _ = cast5.NewCipher(key) |  | ||||||
| 	case CipherAES128, CipherAES192, CipherAES256: |  | ||||||
| 		block, _ = aes.NewCipher(key) |  | ||||||
| 	} |  | ||||||
| 	return |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // readMPI reads a big integer from r. The bit length returned is the bit |  | ||||||
| // length that was specified in r. This is preserved so that the integer can be |  | ||||||
| // reserialized exactly. |  | ||||||
| func readMPI(r io.Reader) (mpi []byte, bitLength uint16, err error) { |  | ||||||
| 	var buf [2]byte |  | ||||||
| 	_, err = readFull(r, buf[0:]) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	bitLength = uint16(buf[0])<<8 | uint16(buf[1]) |  | ||||||
| 	numBytes := (int(bitLength) + 7) / 8 |  | ||||||
| 	mpi = make([]byte, numBytes) |  | ||||||
| 	_, err = readFull(r, mpi) |  | ||||||
| 	// According to RFC 4880 3.2. we should check that the MPI has no leading |  | ||||||
| 	// zeroes (at least when not an encrypted MPI?), but this implementation |  | ||||||
| 	// does generate leading zeroes, so we keep accepting them. |  | ||||||
| 	return |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // writeMPI serializes a big integer to w. |  | ||||||
| func writeMPI(w io.Writer, bitLength uint16, mpiBytes []byte) (err error) { |  | ||||||
| 	// Note that we can produce leading zeroes, in violation of RFC 4880 3.2. |  | ||||||
| 	// Implementations seem to be tolerant of them, and stripping them would |  | ||||||
| 	// make it complex to guarantee matching re-serialization. |  | ||||||
| 	_, err = w.Write([]byte{byte(bitLength >> 8), byte(bitLength)}) |  | ||||||
| 	if err == nil { |  | ||||||
| 		_, err = w.Write(mpiBytes) |  | ||||||
| 	} |  | ||||||
| 	return |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // writeBig serializes a *big.Int to w. |  | ||||||
| func writeBig(w io.Writer, i *big.Int) error { |  | ||||||
| 	return writeMPI(w, uint16(i.BitLen()), i.Bytes()) |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // padToKeySize left-pads a MPI with zeroes to match the length of the | // padToKeySize left-pads a MPI with zeroes to match the length of the | ||||||
| @@ -582,3 +486,37 @@ const ( | |||||||
| 	CompressionZIP  CompressionAlgo = 1 | 	CompressionZIP  CompressionAlgo = 1 | ||||||
| 	CompressionZLIB CompressionAlgo = 2 | 	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` | ||||||
| @@ -5,8 +5,9 @@ | |||||||
| package packet | package packet | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"golang.org/x/crypto/openpgp/errors" |  | ||||||
| 	"io" | 	"io" | ||||||
|  | 
 | ||||||
|  | 	"github.com/ProtonMail/go-crypto/openpgp/errors" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // Reader reads packets from an io.Reader and allows packets to be 'unread' so | // Reader reads packets from an io.Reader and allows packets to be 'unread' so | ||||||
| @@ -42,6 +43,7 @@ func (r *Reader) Next() (p Packet, err error) { | |||||||
| 			r.readers = r.readers[:len(r.readers)-1] | 			r.readers = r.readers[:len(r.readers)-1] | ||||||
| 			continue | 			continue | ||||||
| 		} | 		} | ||||||
|  | 		// TODO: Add strict mode that rejects unknown packets, instead of ignoring them. | ||||||
| 		if _, ok := err.(errors.UnknownPacketTypeError); !ok { | 		if _, ok := err.(errors.UnknownPacketTypeError); !ok { | ||||||
| 			return nil, err | 			return nil, err | ||||||
| 		} | 		} | ||||||
| @@ -17,8 +17,9 @@ import ( | |||||||
| 	"strconv" | 	"strconv" | ||||||
| 	"time" | 	"time" | ||||||
| 
 | 
 | ||||||
| 	"golang.org/x/crypto/openpgp/errors" | 	"github.com/ProtonMail/go-crypto/openpgp/errors" | ||||||
| 	"golang.org/x/crypto/openpgp/s2k" | 	"github.com/ProtonMail/go-crypto/openpgp/internal/encoding" | ||||||
|  | 	"github.com/ProtonMail/go-crypto/openpgp/s2k" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| const ( | const ( | ||||||
| @@ -31,6 +32,7 @@ const ( | |||||||
| 
 | 
 | ||||||
| // Signature represents a signature. See RFC 4880, section 5.2. | // Signature represents a signature. See RFC 4880, section 5.2. | ||||||
| type Signature struct { | type Signature struct { | ||||||
|  | 	Version    int | ||||||
| 	SigType    SignatureType | 	SigType    SignatureType | ||||||
| 	PubKeyAlgo PublicKeyAlgorithm | 	PubKeyAlgo PublicKeyAlgorithm | ||||||
| 	Hash       crypto.Hash | 	Hash       crypto.Hash | ||||||
| @@ -40,11 +42,18 @@ type Signature struct { | |||||||
| 	// HashTag contains the first two bytes of the hash for fast rejection | 	// HashTag contains the first two bytes of the hash for fast rejection | ||||||
| 	// of bad signed data. | 	// of bad signed data. | ||||||
| 	HashTag [2]byte | 	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 | 	CreationTime time.Time | ||||||
| 
 | 
 | ||||||
| 	RSASignature         parsedMPI | 	RSASignature         encoding.Field | ||||||
| 	DSASigR, DSASigS     parsedMPI | 	DSASigR, DSASigS     encoding.Field | ||||||
| 	ECDSASigR, ECDSASigS parsedMPI | 	ECDSASigR, ECDSASigS encoding.Field | ||||||
|  | 	EdDSASigR, EdDSASigS encoding.Field | ||||||
| 
 | 
 | ||||||
| 	// rawSubpackets contains the unparsed subpackets, in order. | 	// rawSubpackets contains the unparsed subpackets, in order. | ||||||
| 	rawSubpackets []outputSubpacket | 	rawSubpackets []outputSubpacket | ||||||
| @@ -54,9 +63,16 @@ type Signature struct { | |||||||
| 
 | 
 | ||||||
| 	SigLifetimeSecs, KeyLifetimeSecs                        *uint32 | 	SigLifetimeSecs, KeyLifetimeSecs                        *uint32 | ||||||
| 	PreferredSymmetric, PreferredHash, PreferredCompression []uint8 | 	PreferredSymmetric, PreferredHash, PreferredCompression []uint8 | ||||||
|  | 	PreferredAEAD                                           []uint8 | ||||||
| 	IssuerKeyId                                             *uint64 | 	IssuerKeyId                                             *uint64 | ||||||
|  | 	IssuerFingerprint                                       []byte | ||||||
| 	IsPrimaryId                                             *bool | 	IsPrimaryId                                             *bool | ||||||
| 
 | 
 | ||||||
|  | 	// PolicyURI can be set to the URI of a document that describes the | ||||||
|  | 	// policy under which the signature was issued. See RFC 4880, section | ||||||
|  | 	// 5.2.3.20 for details. | ||||||
|  | 	PolicyURI string | ||||||
|  | 
 | ||||||
| 	// FlagsValid is set if any flags were given. See RFC 4880, section | 	// FlagsValid is set if any flags were given. See RFC 4880, section | ||||||
| 	// 5.2.3.21 for details. | 	// 5.2.3.21 for details. | ||||||
| 	FlagsValid                                                           bool | 	FlagsValid                                                           bool | ||||||
| @@ -67,9 +83,10 @@ type Signature struct { | |||||||
| 	RevocationReason     *uint8 | 	RevocationReason     *uint8 | ||||||
| 	RevocationReasonText string | 	RevocationReasonText string | ||||||
| 
 | 
 | ||||||
| 	// MDC is set if this signature has a feature packet that indicates | 	// In a self-signature, these flags are set there is a features subpacket | ||||||
| 	// support for MDC subpackets. | 	// indicating that the issuer implementation supports these features | ||||||
| 	MDC bool | 	// (section 5.2.5.25). | ||||||
|  | 	MDC, AEAD, V5Keys bool | ||||||
| 
 | 
 | ||||||
| 	// EmbeddedSignature, if non-nil, is a signature of the parent key, by | 	// EmbeddedSignature, if non-nil, is a signature of the parent key, by | ||||||
| 	// this key. This prevents an attacker from claiming another's signing | 	// this key. This prevents an attacker from claiming another's signing | ||||||
| @@ -86,11 +103,11 @@ func (sig *Signature) parse(r io.Reader) (err error) { | |||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	if buf[0] != 4 { | 	if buf[0] != 4 && buf[0] != 5 { | ||||||
| 		err = errors.UnsupportedError("signature packet version " + strconv.Itoa(int(buf[0]))) | 		err = errors.UnsupportedError("signature packet version " + strconv.Itoa(int(buf[0]))) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 
 | 	sig.Version = int(buf[0]) | ||||||
| 	_, err = readFull(r, buf[:5]) | 	_, err = readFull(r, buf[:5]) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return | 		return | ||||||
| @@ -98,7 +115,7 @@ func (sig *Signature) parse(r io.Reader) (err error) { | |||||||
| 	sig.SigType = SignatureType(buf[0]) | 	sig.SigType = SignatureType(buf[0]) | ||||||
| 	sig.PubKeyAlgo = PublicKeyAlgorithm(buf[1]) | 	sig.PubKeyAlgo = PublicKeyAlgorithm(buf[1]) | ||||||
| 	switch sig.PubKeyAlgo { | 	switch sig.PubKeyAlgo { | ||||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA, PubKeyAlgoECDSA: | 	case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA, PubKeyAlgoECDSA, PubKeyAlgoEdDSA: | ||||||
| 	default: | 	default: | ||||||
| 		err = errors.UnsupportedError("public key algorithm " + strconv.Itoa(int(sig.PubKeyAlgo))) | 		err = errors.UnsupportedError("public key algorithm " + strconv.Itoa(int(sig.PubKeyAlgo))) | ||||||
| 		return | 		return | ||||||
| @@ -111,24 +128,12 @@ func (sig *Signature) parse(r io.Reader) (err error) { | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	hashedSubpacketsLength := int(buf[3])<<8 | int(buf[4]) | 	hashedSubpacketsLength := int(buf[3])<<8 | int(buf[4]) | ||||||
| 	l := 6 + hashedSubpacketsLength | 	hashedSubpackets := make([]byte, hashedSubpacketsLength) | ||||||
| 	sig.HashSuffix = make([]byte, l+6) |  | ||||||
| 	sig.HashSuffix[0] = 4 |  | ||||||
| 	copy(sig.HashSuffix[1:], buf[:5]) |  | ||||||
| 	hashedSubpackets := sig.HashSuffix[6:l] |  | ||||||
| 	_, err = readFull(r, hashedSubpackets) | 	_, err = readFull(r, hashedSubpackets) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	// See RFC 4880, section 5.2.4 | 	sig.buildHashSuffix(hashedSubpackets) | ||||||
| 	trailer := sig.HashSuffix[l:] |  | ||||||
| 	trailer[0] = 4 |  | ||||||
| 	trailer[1] = 0xff |  | ||||||
| 	trailer[2] = uint8(l >> 24) |  | ||||||
| 	trailer[3] = uint8(l >> 16) |  | ||||||
| 	trailer[4] = uint8(l >> 8) |  | ||||||
| 	trailer[5] = uint8(l) |  | ||||||
| 
 |  | ||||||
| 	err = parseSignatureSubpackets(sig, hashedSubpackets, true) | 	err = parseSignatureSubpackets(sig, hashedSubpackets, true) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return | 		return | ||||||
| @@ -156,16 +161,33 @@ func (sig *Signature) parse(r io.Reader) (err error) { | |||||||
| 
 | 
 | ||||||
| 	switch sig.PubKeyAlgo { | 	switch sig.PubKeyAlgo { | ||||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: | 	case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: | ||||||
| 		sig.RSASignature.bytes, sig.RSASignature.bitLength, err = readMPI(r) | 		sig.RSASignature = new(encoding.MPI) | ||||||
|  | 		_, err = sig.RSASignature.ReadFrom(r) | ||||||
| 	case PubKeyAlgoDSA: | 	case PubKeyAlgoDSA: | ||||||
| 		sig.DSASigR.bytes, sig.DSASigR.bitLength, err = readMPI(r) | 		sig.DSASigR = new(encoding.MPI) | ||||||
| 		if err == nil { | 		if _, err = sig.DSASigR.ReadFrom(r); err != nil { | ||||||
| 			sig.DSASigS.bytes, sig.DSASigS.bitLength, err = readMPI(r) | 			return | ||||||
| 		} | 		} | ||||||
|  | 
 | ||||||
|  | 		sig.DSASigS = new(encoding.MPI) | ||||||
|  | 		_, err = sig.DSASigS.ReadFrom(r) | ||||||
| 	case PubKeyAlgoECDSA: | 	case PubKeyAlgoECDSA: | ||||||
| 		sig.ECDSASigR.bytes, sig.ECDSASigR.bitLength, err = readMPI(r) | 		sig.ECDSASigR = new(encoding.MPI) | ||||||
| 		if err == nil { | 		if _, err = sig.ECDSASigR.ReadFrom(r); err != nil { | ||||||
| 			sig.ECDSASigS.bytes, sig.ECDSASigS.bitLength, err = readMPI(r) | 			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: | 	default: | ||||||
| 		panic("unreachable") | 		panic("unreachable") | ||||||
| @@ -201,10 +223,13 @@ const ( | |||||||
| 	prefHashAlgosSubpacket       signatureSubpacketType = 21 | 	prefHashAlgosSubpacket       signatureSubpacketType = 21 | ||||||
| 	prefCompressionSubpacket     signatureSubpacketType = 22 | 	prefCompressionSubpacket     signatureSubpacketType = 22 | ||||||
| 	primaryUserIdSubpacket       signatureSubpacketType = 25 | 	primaryUserIdSubpacket       signatureSubpacketType = 25 | ||||||
|  | 	policyUriSubpacket           signatureSubpacketType = 26 | ||||||
| 	keyFlagsSubpacket            signatureSubpacketType = 27 | 	keyFlagsSubpacket            signatureSubpacketType = 27 | ||||||
| 	reasonForRevocationSubpacket signatureSubpacketType = 29 | 	reasonForRevocationSubpacket signatureSubpacketType = 29 | ||||||
| 	featuresSubpacket            signatureSubpacketType = 30 | 	featuresSubpacket            signatureSubpacketType = 30 | ||||||
| 	embeddedSignatureSubpacket   signatureSubpacketType = 32 | 	embeddedSignatureSubpacket   signatureSubpacketType = 32 | ||||||
|  | 	issuerFingerprintSubpacket   signatureSubpacketType = 33 | ||||||
|  | 	prefAeadAlgosSubpacket       signatureSubpacketType = 34 | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // parseSignatureSubpacket parses a single subpacket. len(subpacket) is >= 1. | // parseSignatureSubpacket parses a single subpacket. len(subpacket) is >= 1. | ||||||
| @@ -290,6 +315,9 @@ func parseSignatureSubpacket(sig *Signature, subpacket []byte, isHashed bool) (r | |||||||
| 		sig.PreferredSymmetric = make([]byte, len(subpacket)) | 		sig.PreferredSymmetric = make([]byte, len(subpacket)) | ||||||
| 		copy(sig.PreferredSymmetric, subpacket) | 		copy(sig.PreferredSymmetric, subpacket) | ||||||
| 	case issuerSubpacket: | 	case issuerSubpacket: | ||||||
|  | 		if sig.Version > 4 { | ||||||
|  | 			err = errors.StructuralError("issuer subpacket found in v5 key") | ||||||
|  | 		} | ||||||
| 		// Issuer, section 5.2.3.5 | 		// Issuer, section 5.2.3.5 | ||||||
| 		if len(subpacket) != 8 { | 		if len(subpacket) != 8 { | ||||||
| 			err = errors.StructuralError("issuer subpacket with bad length") | 			err = errors.StructuralError("issuer subpacket with bad length") | ||||||
| @@ -361,9 +389,21 @@ func parseSignatureSubpacket(sig *Signature, subpacket []byte, isHashed bool) (r | |||||||
| 	case featuresSubpacket: | 	case featuresSubpacket: | ||||||
| 		// Features subpacket, section 5.2.3.24 specifies a very general | 		// Features subpacket, section 5.2.3.24 specifies a very general | ||||||
| 		// mechanism for OpenPGP implementations to signal support for new | 		// mechanism for OpenPGP implementations to signal support for new | ||||||
| 		// features. In practice, the subpacket is used exclusively to | 		// features. | ||||||
| 		// indicate support for MDC-protected encryption. | 		if !isHashed { | ||||||
| 		sig.MDC = len(subpacket) >= 1 && subpacket[0]&1 == 1 | 			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: | 	case embeddedSignatureSubpacket: | ||||||
| 		// Only usage is in signatures that cross-certify | 		// Only usage is in signatures that cross-certify | ||||||
| 		// signing subkeys. section 5.2.3.26 describes the | 		// signing subkeys. section 5.2.3.26 describes the | ||||||
| @@ -382,6 +422,32 @@ func parseSignatureSubpacket(sig *Signature, subpacket []byte, isHashed bool) (r | |||||||
| 		if sigType := sig.EmbeddedSignature.SigType; sigType != SigTypePrimaryKeyBinding { | 		if sigType := sig.EmbeddedSignature.SigType; sigType != SigTypePrimaryKeyBinding { | ||||||
| 			return nil, errors.StructuralError("cross-signature has unexpected type " + strconv.Itoa(int(sigType))) | 			return nil, errors.StructuralError("cross-signature has unexpected type " + strconv.Itoa(int(sigType))) | ||||||
| 		} | 		} | ||||||
|  | 	case policyUriSubpacket: | ||||||
|  | 		// Policy URI, section 5.2.3.20 | ||||||
|  | 		if !isHashed { | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 		sig.PolicyURI = string(subpacket) | ||||||
|  | 	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: | 	default: | ||||||
| 		if isCritical { | 		if isCritical { | ||||||
| 			err = errors.UnsupportedError("unknown critical signature subpacket type " + strconv.Itoa(int(packetType))) | 			err = errors.UnsupportedError("unknown critical signature subpacket type " + strconv.Itoa(int(packetType))) | ||||||
| @@ -406,6 +472,13 @@ func subpacketLengthLength(length int) int { | |||||||
| 	return 5 | 	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. | // serializeSubpacketLength marshals the given length into to. | ||||||
| func serializeSubpacketLength(to []byte, length int) int { | func serializeSubpacketLength(to []byte, length int) int { | ||||||
| 	// RFC 4880, Section 4.2.2. | 	// RFC 4880, Section 4.2.2. | ||||||
| @@ -446,6 +519,9 @@ func serializeSubpackets(to []byte, subpackets []outputSubpacket, hashed bool) { | |||||||
| 		if subpacket.hashed == hashed { | 		if subpacket.hashed == hashed { | ||||||
| 			n := serializeSubpacketLength(to, len(subpacket.contents)+1) | 			n := serializeSubpacketLength(to, len(subpacket.contents)+1) | ||||||
| 			to[n] = byte(subpacket.subpacketType) | 			to[n] = byte(subpacket.subpacketType) | ||||||
|  | 			if subpacket.isCritical { | ||||||
|  | 				to[n] |= 0x80 | ||||||
|  | 			} | ||||||
| 			to = to[1+n:] | 			to = to[1+n:] | ||||||
| 			n = copy(to, subpacket.contents) | 			n = copy(to, subpacket.contents) | ||||||
| 			to = to[n:] | 			to = to[n:] | ||||||
| @@ -454,49 +530,66 @@ func serializeSubpackets(to []byte, subpackets []outputSubpacket, hashed bool) { | |||||||
| 	return | 	return | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // KeyExpired returns whether sig is a self-signature of a key that has | // SigExpired returns whether sig is a signature that has expired or is created | ||||||
| // expired. | // in the future. | ||||||
| func (sig *Signature) KeyExpired(currentTime time.Time) bool { | func (sig *Signature) SigExpired(currentTime time.Time) bool { | ||||||
| 	if sig.KeyLifetimeSecs == nil { | 	if sig.CreationTime.After(currentTime) { | ||||||
|  | 		return true | ||||||
|  | 	} | ||||||
|  | 	if sig.SigLifetimeSecs == nil || *sig.SigLifetimeSecs == 0 { | ||||||
| 		return false | 		return false | ||||||
| 	} | 	} | ||||||
| 	expiry := sig.CreationTime.Add(time.Duration(*sig.KeyLifetimeSecs) * time.Second) | 	expiry := sig.CreationTime.Add(time.Duration(*sig.SigLifetimeSecs) * time.Second) | ||||||
| 	return currentTime.After(expiry) | 	return currentTime.After(expiry) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // buildHashSuffix constructs the HashSuffix member of sig in preparation for signing. | // buildHashSuffix constructs the HashSuffix member of sig in preparation for signing. | ||||||
| func (sig *Signature) buildHashSuffix() (err error) { | func (sig *Signature) buildHashSuffix(hashedSubpackets []byte) (err error) { | ||||||
| 	hashedSubpacketsLen := subpacketsLength(sig.outSubpackets, true) | 	hash, ok := s2k.HashToHashId(sig.Hash) | ||||||
| 
 |  | ||||||
| 	var ok bool |  | ||||||
| 	l := 6 + hashedSubpacketsLen |  | ||||||
| 	sig.HashSuffix = make([]byte, l+6) |  | ||||||
| 	sig.HashSuffix[0] = 4 |  | ||||||
| 	sig.HashSuffix[1] = uint8(sig.SigType) |  | ||||||
| 	sig.HashSuffix[2] = uint8(sig.PubKeyAlgo) |  | ||||||
| 	sig.HashSuffix[3], ok = s2k.HashToHashId(sig.Hash) |  | ||||||
| 	if !ok { | 	if !ok { | ||||||
| 		sig.HashSuffix = nil | 		sig.HashSuffix = nil | ||||||
| 		return errors.InvalidArgumentError("hash cannot be represented in OpenPGP: " + strconv.Itoa(int(sig.Hash))) | 		return errors.InvalidArgumentError("hash cannot be represented in OpenPGP: " + strconv.Itoa(int(sig.Hash))) | ||||||
| 	} | 	} | ||||||
| 	sig.HashSuffix[4] = byte(hashedSubpacketsLen >> 8) | 
 | ||||||
| 	sig.HashSuffix[5] = byte(hashedSubpacketsLen) | 	hashedFields := bytes.NewBuffer([]byte{ | ||||||
| 	serializeSubpackets(sig.HashSuffix[6:l], sig.outSubpackets, true) | 		uint8(sig.Version), | ||||||
| 	trailer := sig.HashSuffix[l:] | 		uint8(sig.SigType), | ||||||
| 	trailer[0] = 4 | 		uint8(sig.PubKeyAlgo), | ||||||
| 	trailer[1] = 0xff | 		uint8(hash), | ||||||
| 	trailer[2] = byte(l >> 24) | 		uint8(len(hashedSubpackets) >> 8), | ||||||
| 	trailer[3] = byte(l >> 16) | 		uint8(len(hashedSubpackets)), | ||||||
| 	trailer[4] = byte(l >> 8) | 	}) | ||||||
| 	trailer[5] = byte(l) | 	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 | 	return | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (sig *Signature) signPrepareHash(h hash.Hash) (digest []byte, err error) { | func (sig *Signature) signPrepareHash(h hash.Hash) (digest []byte, err error) { | ||||||
| 	err = sig.buildHashSuffix() | 	hashedSubpacketsLen := subpacketsLength(sig.outSubpackets, true) | ||||||
|  | 	hashedSubpackets := make([]byte, hashedSubpacketsLen) | ||||||
|  | 	serializeSubpackets(hashedSubpackets, sig.outSubpackets, true) | ||||||
|  | 	err = sig.buildHashSuffix(hashedSubpackets) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  | 	if sig.Version == 5 && (sig.SigType == 0x00 || sig.SigType == 0x01) { | ||||||
|  | 		sig.AddMetadataToHashSuffix() | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	h.Write(sig.HashSuffix) | 	h.Write(sig.HashSuffix) | ||||||
| 	digest = h.Sum(nil) | 	digest = h.Sum(nil) | ||||||
| @@ -509,17 +602,26 @@ func (sig *Signature) signPrepareHash(h hash.Hash) (digest []byte, err error) { | |||||||
| // On success, the signature is stored in sig. Call Serialize to write it out. | // On success, the signature is stored in sig. Call Serialize to write it out. | ||||||
| // If config is nil, sensible defaults will be used. | // If config is nil, sensible defaults will be used. | ||||||
| func (sig *Signature) Sign(h hash.Hash, priv *PrivateKey, config *Config) (err error) { | func (sig *Signature) Sign(h hash.Hash, priv *PrivateKey, config *Config) (err error) { | ||||||
| 	sig.outSubpackets = sig.buildSubpackets() | 	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) | 	digest, err := sig.signPrepareHash(h) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 
 |  | ||||||
| 	switch priv.PubKeyAlgo { | 	switch priv.PubKeyAlgo { | ||||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: | 	case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: | ||||||
| 		// supports both *rsa.PrivateKey and crypto.Signer | 		// supports both *rsa.PrivateKey and crypto.Signer | ||||||
| 		sig.RSASignature.bytes, err = priv.PrivateKey.(crypto.Signer).Sign(config.Random(), digest, sig.Hash) | 		sigdata, err := priv.PrivateKey.(crypto.Signer).Sign(config.Random(), digest, sig.Hash) | ||||||
| 		sig.RSASignature.bitLength = uint16(8 * len(sig.RSASignature.bytes)) | 		if err == nil { | ||||||
|  | 			sig.RSASignature = encoding.NewMPI(sigdata) | ||||||
|  | 		} | ||||||
| 	case PubKeyAlgoDSA: | 	case PubKeyAlgoDSA: | ||||||
| 		dsaPriv := priv.PrivateKey.(*dsa.PrivateKey) | 		dsaPriv := priv.PrivateKey.(*dsa.PrivateKey) | ||||||
| 
 | 
 | ||||||
| @@ -530,10 +632,8 @@ func (sig *Signature) Sign(h hash.Hash, priv *PrivateKey, config *Config) (err e | |||||||
| 		} | 		} | ||||||
| 		r, s, err := dsa.Sign(config.Random(), dsaPriv, digest) | 		r, s, err := dsa.Sign(config.Random(), dsaPriv, digest) | ||||||
| 		if err == nil { | 		if err == nil { | ||||||
| 			sig.DSASigR.bytes = r.Bytes() | 			sig.DSASigR = new(encoding.MPI).SetBig(r) | ||||||
| 			sig.DSASigR.bitLength = uint16(8 * len(sig.DSASigR.bytes)) | 			sig.DSASigS = new(encoding.MPI).SetBig(s) | ||||||
| 			sig.DSASigS.bytes = s.Bytes() |  | ||||||
| 			sig.DSASigS.bitLength = uint16(8 * len(sig.DSASigS.bytes)) |  | ||||||
| 		} | 		} | ||||||
| 	case PubKeyAlgoECDSA: | 	case PubKeyAlgoECDSA: | ||||||
| 		var r, s *big.Int | 		var r, s *big.Int | ||||||
| @@ -548,8 +648,14 @@ func (sig *Signature) Sign(h hash.Hash, priv *PrivateKey, config *Config) (err e | |||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		if err == nil { | 		if err == nil { | ||||||
| 			sig.ECDSASigR = fromBig(r) | 			sig.ECDSASigR = new(encoding.MPI).SetBig(r) | ||||||
| 			sig.ECDSASigS = fromBig(s) | 			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: | 	default: | ||||||
| 		err = errors.UnsupportedError("public key algorithm: " + strconv.Itoa(int(sig.PubKeyAlgo))) | 		err = errors.UnsupportedError("public key algorithm: " + strconv.Itoa(int(sig.PubKeyAlgo))) | ||||||
| @@ -576,6 +682,9 @@ func unwrapECDSASig(b []byte) (r, s *big.Int, err error) { | |||||||
| // Serialize to write it out. | // Serialize to write it out. | ||||||
| // If config is nil, sensible defaults will be used. | // If config is nil, sensible defaults will be used. | ||||||
| func (sig *Signature) SignUserId(id string, pub *PublicKey, priv *PrivateKey, config *Config) error { | 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) | 	h, err := userIdSignatureHash(id, pub, sig.Hash) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| @@ -583,10 +692,25 @@ func (sig *Signature) SignUserId(id string, pub *PublicKey, priv *PrivateKey, co | |||||||
| 	return sig.Sign(h, priv, config) | 	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 | // 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. | // success, the signature is stored in sig. Call Serialize to write it out. | ||||||
| // If config is nil, sensible defaults will be used. | // If config is nil, sensible defaults will be used. | ||||||
| func (sig *Signature) SignKey(pub *PublicKey, priv *PrivateKey, config *Config) error { | 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) | 	h, err := keySignatureHash(&priv.PublicKey, pub, sig.Hash) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| @@ -594,26 +718,40 @@ func (sig *Signature) SignKey(pub *PublicKey, priv *PrivateKey, config *Config) | |||||||
| 	return sig.Sign(h, priv, config) | 	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 | // Serialize marshals sig to w. Sign, SignUserId or SignKey must have been | ||||||
| // called first. | // called first. | ||||||
| func (sig *Signature) Serialize(w io.Writer) (err error) { | func (sig *Signature) Serialize(w io.Writer) (err error) { | ||||||
| 	if len(sig.outSubpackets) == 0 { | 	if len(sig.outSubpackets) == 0 { | ||||||
| 		sig.outSubpackets = sig.rawSubpackets | 		sig.outSubpackets = sig.rawSubpackets | ||||||
| 	} | 	} | ||||||
| 	if sig.RSASignature.bytes == nil && sig.DSASigR.bytes == nil && sig.ECDSASigR.bytes == nil { | 	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") | 		return errors.InvalidArgumentError("Signature: need to call Sign, SignUserId or SignKey before Serialize") | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	sigLength := 0 | 	sigLength := 0 | ||||||
| 	switch sig.PubKeyAlgo { | 	switch sig.PubKeyAlgo { | ||||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: | 	case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: | ||||||
| 		sigLength = 2 + len(sig.RSASignature.bytes) | 		sigLength = int(sig.RSASignature.EncodedLength()) | ||||||
| 	case PubKeyAlgoDSA: | 	case PubKeyAlgoDSA: | ||||||
| 		sigLength = 2 + len(sig.DSASigR.bytes) | 		sigLength = int(sig.DSASigR.EncodedLength()) | ||||||
| 		sigLength += 2 + len(sig.DSASigS.bytes) | 		sigLength += int(sig.DSASigS.EncodedLength()) | ||||||
| 	case PubKeyAlgoECDSA: | 	case PubKeyAlgoECDSA: | ||||||
| 		sigLength = 2 + len(sig.ECDSASigR.bytes) | 		sigLength = int(sig.ECDSASigR.EncodedLength()) | ||||||
| 		sigLength += 2 + len(sig.ECDSASigS.bytes) | 		sigLength += int(sig.ECDSASigS.EncodedLength()) | ||||||
|  | 	case PubKeyAlgoEdDSA: | ||||||
|  | 		sigLength = int(sig.EdDSASigR.EncodedLength()) | ||||||
|  | 		sigLength += int(sig.EdDSASigS.EncodedLength()) | ||||||
| 	default: | 	default: | ||||||
| 		panic("impossible") | 		panic("impossible") | ||||||
| 	} | 	} | ||||||
| @@ -622,16 +760,29 @@ func (sig *Signature) Serialize(w io.Writer) (err error) { | |||||||
| 	length := len(sig.HashSuffix) - 6 /* trailer not included */ + | 	length := len(sig.HashSuffix) - 6 /* trailer not included */ + | ||||||
| 		2 /* length of unhashed subpackets */ + unhashedSubpacketsLen + | 		2 /* length of unhashed subpackets */ + unhashedSubpacketsLen + | ||||||
| 		2 /* hash tag */ + sigLength | 		2 /* hash tag */ + sigLength | ||||||
|  | 	if sig.Version == 5 { | ||||||
|  | 		length -= 4 // eight-octet instead of four-octet big endian | ||||||
|  | 	} | ||||||
| 	err = serializeHeader(w, packetTypeSignature, length) | 	err = serializeHeader(w, packetTypeSignature, length) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  | 	err = sig.serializeBody(w) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| 	_, err = w.Write(sig.HashSuffix[:len(sig.HashSuffix)-6]) | 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 { | 	if err != nil { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	unhashedSubpacketsLen := subpacketsLength(sig.outSubpackets, false) | ||||||
| 	unhashedSubpackets := make([]byte, 2+unhashedSubpacketsLen) | 	unhashedSubpackets := make([]byte, 2+unhashedSubpacketsLen) | ||||||
| 	unhashedSubpackets[0] = byte(unhashedSubpacketsLen >> 8) | 	unhashedSubpackets[0] = byte(unhashedSubpacketsLen >> 8) | ||||||
| 	unhashedSubpackets[1] = byte(unhashedSubpacketsLen) | 	unhashedSubpackets[1] = byte(unhashedSubpacketsLen) | ||||||
| @@ -648,11 +799,22 @@ func (sig *Signature) Serialize(w io.Writer) (err error) { | |||||||
| 
 | 
 | ||||||
| 	switch sig.PubKeyAlgo { | 	switch sig.PubKeyAlgo { | ||||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: | 	case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: | ||||||
| 		err = writeMPIs(w, sig.RSASignature) | 		_, err = w.Write(sig.RSASignature.EncodedBytes()) | ||||||
| 	case PubKeyAlgoDSA: | 	case PubKeyAlgoDSA: | ||||||
| 		err = writeMPIs(w, sig.DSASigR, sig.DSASigS) | 		if _, err = w.Write(sig.DSASigR.EncodedBytes()); err != nil { | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 		_, err = w.Write(sig.DSASigS.EncodedBytes()) | ||||||
| 	case PubKeyAlgoECDSA: | 	case PubKeyAlgoECDSA: | ||||||
| 		err = writeMPIs(w, sig.ECDSASigR, sig.ECDSASigS) | 		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: | 	default: | ||||||
| 		panic("impossible") | 		panic("impossible") | ||||||
| 	} | 	} | ||||||
| @@ -667,17 +829,20 @@ type outputSubpacket struct { | |||||||
| 	contents      []byte | 	contents      []byte | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (sig *Signature) buildSubpackets() (subpackets []outputSubpacket) { | func (sig *Signature) buildSubpackets(issuer PublicKey) (subpackets []outputSubpacket, err error) { | ||||||
| 	creationTime := make([]byte, 4) | 	creationTime := make([]byte, 4) | ||||||
| 	binary.BigEndian.PutUint32(creationTime, uint32(sig.CreationTime.Unix())) | 	binary.BigEndian.PutUint32(creationTime, uint32(sig.CreationTime.Unix())) | ||||||
| 	subpackets = append(subpackets, outputSubpacket{true, creationTimeSubpacket, false, creationTime}) | 	subpackets = append(subpackets, outputSubpacket{true, creationTimeSubpacket, false, creationTime}) | ||||||
| 
 | 
 | ||||||
| 	if sig.IssuerKeyId != nil { | 	if sig.IssuerKeyId != nil && sig.Version == 4 { | ||||||
| 		keyId := make([]byte, 8) | 		keyId := make([]byte, 8) | ||||||
| 		binary.BigEndian.PutUint64(keyId, *sig.IssuerKeyId) | 		binary.BigEndian.PutUint64(keyId, *sig.IssuerKeyId) | ||||||
| 		subpackets = append(subpackets, outputSubpacket{true, issuerSubpacket, false, keyId}) | 		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 { | 	if sig.SigLifetimeSecs != nil && *sig.SigLifetimeSecs != 0 { | ||||||
| 		sigLifetime := make([]byte, 4) | 		sigLifetime := make([]byte, 4) | ||||||
| 		binary.BigEndian.PutUint32(sigLifetime, *sig.SigLifetimeSecs) | 		binary.BigEndian.PutUint32(sigLifetime, *sig.SigLifetimeSecs) | ||||||
| @@ -703,7 +868,22 @@ func (sig *Signature) buildSubpackets() (subpackets []outputSubpacket) { | |||||||
| 		subpackets = append(subpackets, outputSubpacket{true, keyFlagsSubpacket, false, []byte{flags}}) | 		subpackets = append(subpackets, outputSubpacket{true, keyFlagsSubpacket, false, []byte{flags}}) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// The following subpackets may only appear in self-signatures | 	// 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 { | 	if sig.KeyLifetimeSecs != nil && *sig.KeyLifetimeSecs != 0 { | ||||||
| 		keyLifetime := make([]byte, 4) | 		keyLifetime := make([]byte, 4) | ||||||
| @@ -727,5 +907,77 @@ func (sig *Signature) buildSubpackets() (subpackets []outputSubpacket) { | |||||||
| 		subpackets = append(subpackets, outputSubpacket{true, prefCompressionSubpacket, false, sig.PreferredCompression}) | 		subpackets = append(subpackets, outputSubpacket{true, prefCompressionSubpacket, false, sig.PreferredCompression}) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	if len(sig.PolicyURI) > 0 { | ||||||
|  | 		subpackets = append(subpackets, outputSubpacket{true, policyUriSubpacket, false, []uint8(sig.PolicyURI)}) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	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 | 	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 | ||||||
|  | } | ||||||
| @@ -8,18 +8,19 @@ import ( | |||||||
| 	"crypto/cipher" | 	"crypto/cipher" | ||||||
| 	"crypto/sha1" | 	"crypto/sha1" | ||||||
| 	"crypto/subtle" | 	"crypto/subtle" | ||||||
| 	"golang.org/x/crypto/openpgp/errors" |  | ||||||
| 	"hash" | 	"hash" | ||||||
| 	"io" | 	"io" | ||||||
| 	"strconv" | 	"strconv" | ||||||
|  | 
 | ||||||
|  | 	"github.com/ProtonMail/go-crypto/openpgp/errors" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // SymmetricallyEncrypted represents a symmetrically encrypted byte string. The | // SymmetricallyEncrypted represents a symmetrically encrypted byte string. The | ||||||
| // encrypted contents will consist of more OpenPGP packets. See RFC 4880, | // encrypted Contents will consist of more OpenPGP packets. See RFC 4880, | ||||||
| // sections 5.7 and 5.13. | // sections 5.7 and 5.13. | ||||||
| type SymmetricallyEncrypted struct { | type SymmetricallyEncrypted struct { | ||||||
| 	MDC      bool // true iff this is a type 18 packet and thus has an embedded MAC. | 	MDC      bool // true iff this is a type 18 packet and thus has an embedded MAC. | ||||||
| 	contents io.Reader | 	Contents io.Reader | ||||||
| 	prefix   []byte | 	prefix   []byte | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @@ -37,13 +38,13 @@ func (se *SymmetricallyEncrypted) parse(r io.Reader) error { | |||||||
| 			return errors.UnsupportedError("unknown SymmetricallyEncrypted version") | 			return errors.UnsupportedError("unknown SymmetricallyEncrypted version") | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	se.contents = r | 	se.Contents = r | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Decrypt returns a ReadCloser, from which the decrypted contents of the | // Decrypt returns a ReadCloser, from which the decrypted Contents of the | ||||||
| // packet can be read. An incorrect key can, with high probability, be detected | // packet can be read. An incorrect key will only be detected after trying | ||||||
| // immediately and this will result in a KeyIncorrect error being returned. | // to decrypt the entire data. | ||||||
| func (se *SymmetricallyEncrypted) Decrypt(c CipherFunction, key []byte) (io.ReadCloser, error) { | func (se *SymmetricallyEncrypted) Decrypt(c CipherFunction, key []byte) (io.ReadCloser, error) { | ||||||
| 	keySize := c.KeySize() | 	keySize := c.KeySize() | ||||||
| 	if keySize == 0 { | 	if keySize == 0 { | ||||||
| @@ -55,7 +56,7 @@ func (se *SymmetricallyEncrypted) Decrypt(c CipherFunction, key []byte) (io.Read | |||||||
| 
 | 
 | ||||||
| 	if se.prefix == nil { | 	if se.prefix == nil { | ||||||
| 		se.prefix = make([]byte, c.blockSize()+2) | 		se.prefix = make([]byte, c.blockSize()+2) | ||||||
| 		_, err := readFull(se.contents, se.prefix) | 		_, err := readFull(se.Contents, se.prefix) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return nil, err | 			return nil, err | ||||||
| 		} | 		} | ||||||
| @@ -70,11 +71,8 @@ func (se *SymmetricallyEncrypted) Decrypt(c CipherFunction, key []byte) (io.Read | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	s := NewOCFBDecrypter(c.new(key), se.prefix, ocfbResync) | 	s := NewOCFBDecrypter(c.new(key), se.prefix, ocfbResync) | ||||||
| 	if s == nil { |  | ||||||
| 		return nil, errors.ErrKeyIncorrect |  | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	plaintext := cipher.StreamReader{S: s, R: se.contents} | 	plaintext := cipher.StreamReader{S: s, R: se.Contents} | ||||||
| 
 | 
 | ||||||
| 	if se.MDC { | 	if se.MDC { | ||||||
| 		// MDC packets have an embedded hash that we need to check. | 		// MDC packets have an embedded hash that we need to check. | ||||||
| @@ -104,7 +102,7 @@ const mdcTrailerSize = 1 /* tag byte */ + 1 /* length byte */ + sha1.Size | |||||||
| 
 | 
 | ||||||
| // An seMDCReader wraps an io.Reader, maintains a running hash and keeps hold | // 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 | // 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 | // MDC packet containing a hash of the previous Contents which is checked | ||||||
| // against the running hash. See RFC 4880, section 5.13. | // against the running hash. See RFC 4880, section 5.13. | ||||||
| type seMDCReader struct { | type seMDCReader struct { | ||||||
| 	in          io.Reader | 	in          io.Reader | ||||||
| @@ -180,7 +178,7 @@ const mdcPacketTagByte = byte(0x80) | 0x40 | 19 | |||||||
| 
 | 
 | ||||||
| func (ser *seMDCReader) Close() error { | func (ser *seMDCReader) Close() error { | ||||||
| 	if ser.error { | 	if ser.error { | ||||||
| 		return errors.SignatureError("error during reading") | 		return errors.ErrMDCMissing | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	for !ser.eof { | 	for !ser.eof { | ||||||
| @@ -191,18 +189,20 @@ func (ser *seMDCReader) Close() error { | |||||||
| 			break | 			break | ||||||
| 		} | 		} | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return errors.SignatureError("error during reading") | 			return errors.ErrMDCMissing | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if ser.trailer[0] != mdcPacketTagByte || ser.trailer[1] != sha1.Size { |  | ||||||
| 		return errors.SignatureError("MDC packet not found") |  | ||||||
| 	} |  | ||||||
| 	ser.h.Write(ser.trailer[:2]) | 	ser.h.Write(ser.trailer[:2]) | ||||||
| 
 | 
 | ||||||
| 	final := ser.h.Sum(nil) | 	final := ser.h.Sum(nil) | ||||||
| 	if subtle.ConstantTimeCompare(final, ser.trailer[2:]) != 1 { | 	if subtle.ConstantTimeCompare(final, ser.trailer[2:]) != 1 { | ||||||
| 		return errors.SignatureError("hash mismatch") | 		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 | 	return nil | ||||||
| } | } | ||||||
| @@ -253,7 +253,7 @@ func (c noOpCloser) Close() error { | |||||||
| // to w and returns a WriteCloser to which the to-be-encrypted packets can be | // to w and returns a WriteCloser to which the to-be-encrypted packets can be | ||||||
| // written. | // written. | ||||||
| // If config is nil, sensible defaults will be used. | // 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) { | func SerializeSymmetricallyEncrypted(w io.Writer, c CipherFunction, key []byte, config *Config) (Contents io.WriteCloser, err error) { | ||||||
| 	if c.KeySize() != len(key) { | 	if c.KeySize() != len(key) { | ||||||
| 		return nil, errors.InvalidArgumentError("SymmetricallyEncrypted.Serialize: bad key length") | 		return nil, errors.InvalidArgumentError("SymmetricallyEncrypted.Serialize: bad key length") | ||||||
| 	} | 	} | ||||||
| @@ -285,6 +285,6 @@ func SerializeSymmetricallyEncrypted(w io.Writer, c CipherFunction, key []byte, | |||||||
| 	h := sha1.New() | 	h := sha1.New() | ||||||
| 	h.Write(iv) | 	h.Write(iv) | ||||||
| 	h.Write(iv[blockSize-2:]) | 	h.Write(iv[blockSize-2:]) | ||||||
| 	contents = &seMDCWriter{w: plaintext, h: h} | 	Contents = &seMDCWriter{w: plaintext, h: h} | ||||||
| 	return | 	return | ||||||
| } | } | ||||||
| @@ -69,7 +69,10 @@ func (uat *UserAttribute) parse(r io.Reader) (err error) { | |||||||
| func (uat *UserAttribute) Serialize(w io.Writer) (err error) { | func (uat *UserAttribute) Serialize(w io.Writer) (err error) { | ||||||
| 	var buf bytes.Buffer | 	var buf bytes.Buffer | ||||||
| 	for _, sp := range uat.Contents { | 	for _, sp := range uat.Contents { | ||||||
| 		sp.Serialize(&buf) | 		err = sp.Serialize(&buf) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 	if err = serializeHeader(w, packetTypeUserAttribute, buf.Len()); err != nil { | 	if err = serializeHeader(w, packetTypeUserAttribute, buf.Len()); err != nil { | ||||||
| 		return err | 		return err | ||||||
| @@ -3,7 +3,7 @@ | |||||||
| // license that can be found in the LICENSE file. | // license that can be found in the LICENSE file. | ||||||
| 
 | 
 | ||||||
| // Package openpgp implements high level operations on OpenPGP messages. | // Package openpgp implements high level operations on OpenPGP messages. | ||||||
| package openpgp // import "golang.org/x/crypto/openpgp" | package openpgp // import "github.com/ProtonMail/go-crypto/openpgp" | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"crypto" | 	"crypto" | ||||||
| @@ -12,9 +12,9 @@ import ( | |||||||
| 	"io" | 	"io" | ||||||
| 	"strconv" | 	"strconv" | ||||||
| 
 | 
 | ||||||
| 	"golang.org/x/crypto/openpgp/armor" | 	"github.com/ProtonMail/go-crypto/openpgp/armor" | ||||||
| 	"golang.org/x/crypto/openpgp/errors" | 	"github.com/ProtonMail/go-crypto/openpgp/errors" | ||||||
| 	"golang.org/x/crypto/openpgp/packet" | 	"github.com/ProtonMail/go-crypto/openpgp/packet" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // SignatureType is the armor type for a PGP signature. | // SignatureType is the armor type for a PGP signature. | ||||||
| @@ -56,9 +56,9 @@ type MessageDetails struct { | |||||||
| 	// been consumed. Once EOF has been seen, the following fields are | 	// been consumed. Once EOF has been seen, the following fields are | ||||||
| 	// valid. (An authentication code failure is reported as a | 	// valid. (An authentication code failure is reported as a | ||||||
| 	// SignatureError error when reading from UnverifiedBody.) | 	// SignatureError error when reading from UnverifiedBody.) | ||||||
|  | 	Signature            *packet.Signature   // the signature packet itself. | ||||||
| 	SignatureError       error               // nil if the signature is good. | 	SignatureError       error               // nil if the signature is good. | ||||||
| 	Signature      *packet.Signature   // the signature packet itself, if v4 (default) | 	UnverifiedSignatures []*packet.Signature // all other unverified signature packets. | ||||||
| 	SignatureV3    *packet.SignatureV3 // the signature packet if it is a v2 or v3 signature |  | ||||||
| 
 | 
 | ||||||
| 	decrypted io.ReadCloser | 	decrypted io.ReadCloser | ||||||
| } | } | ||||||
| @@ -88,7 +88,8 @@ func ReadMessage(r io.Reader, keyring KeyRing, prompt PromptFunction, config *pa | |||||||
| 
 | 
 | ||||||
| 	var symKeys []*packet.SymmetricKeyEncrypted | 	var symKeys []*packet.SymmetricKeyEncrypted | ||||||
| 	var pubKeys []keyEnvelopePair | 	var pubKeys []keyEnvelopePair | ||||||
| 	var se *packet.SymmetricallyEncrypted | 	// Integrity protected encrypted packet: SymmetricallyEncrypted or AEADEncrypted | ||||||
|  | 	var edp packet.EncryptedDataPacket | ||||||
| 
 | 
 | ||||||
| 	packets := packet.NewReader(r) | 	packets := packet.NewReader(r) | ||||||
| 	md = new(MessageDetails) | 	md = new(MessageDetails) | ||||||
| @@ -113,7 +114,7 @@ ParsePackets: | |||||||
| 			// This packet contains the decryption key encrypted to a public key. | 			// This packet contains the decryption key encrypted to a public key. | ||||||
| 			md.EncryptedToKeyIds = append(md.EncryptedToKeyIds, p.KeyId) | 			md.EncryptedToKeyIds = append(md.EncryptedToKeyIds, p.KeyId) | ||||||
| 			switch p.Algo { | 			switch p.Algo { | ||||||
| 			case packet.PubKeyAlgoRSA, packet.PubKeyAlgoRSAEncryptOnly, packet.PubKeyAlgoElGamal: | 			case packet.PubKeyAlgoRSA, packet.PubKeyAlgoRSAEncryptOnly, packet.PubKeyAlgoElGamal, packet.PubKeyAlgoECDH: | ||||||
| 				break | 				break | ||||||
| 			default: | 			default: | ||||||
| 				continue | 				continue | ||||||
| @@ -127,8 +128,8 @@ ParsePackets: | |||||||
| 			for _, k := range keys { | 			for _, k := range keys { | ||||||
| 				pubKeys = append(pubKeys, keyEnvelopePair{k, p}) | 				pubKeys = append(pubKeys, keyEnvelopePair{k, p}) | ||||||
| 			} | 			} | ||||||
| 		case *packet.SymmetricallyEncrypted: | 		case *packet.SymmetricallyEncrypted, *packet.AEADEncrypted: | ||||||
| 			se = p | 			edp = p.(packet.EncryptedDataPacket) | ||||||
| 			break ParsePackets | 			break ParsePackets | ||||||
| 		case *packet.Compressed, *packet.LiteralData, *packet.OnePassSignature: | 		case *packet.Compressed, *packet.LiteralData, *packet.OnePassSignature: | ||||||
| 			// This message isn't encrypted. | 			// This message isn't encrypted. | ||||||
| @@ -136,7 +137,7 @@ ParsePackets: | |||||||
| 				return nil, errors.StructuralError("key material not followed by encrypted message") | 				return nil, errors.StructuralError("key material not followed by encrypted message") | ||||||
| 			} | 			} | ||||||
| 			packets.Unread(p) | 			packets.Unread(p) | ||||||
| 			return readSignedMessage(packets, nil, keyring) | 			return readSignedMessage(packets, nil, keyring, config) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @@ -158,12 +159,13 @@ FindKey: | |||||||
| 			} | 			} | ||||||
| 			if !pk.key.PrivateKey.Encrypted { | 			if !pk.key.PrivateKey.Encrypted { | ||||||
| 				if len(pk.encryptedKey.Key) == 0 { | 				if len(pk.encryptedKey.Key) == 0 { | ||||||
| 					pk.encryptedKey.Decrypt(pk.key.PrivateKey, config) | 					errDec := pk.encryptedKey.Decrypt(pk.key.PrivateKey, config) | ||||||
| 				} | 					if errDec != nil { | ||||||
| 				if len(pk.encryptedKey.Key) == 0 { |  | ||||||
| 						continue | 						continue | ||||||
| 					} | 					} | ||||||
| 				decrypted, err = se.Decrypt(pk.encryptedKey.CipherFunc, pk.encryptedKey.Key) | 				} | ||||||
|  | 				// Try to decrypt symmetrically encrypted | ||||||
|  | 				decrypted, err = edp.Decrypt(pk.encryptedKey.CipherFunc, pk.encryptedKey.Key) | ||||||
| 				if err != nil && err != errors.ErrKeyIncorrect { | 				if err != nil && err != errors.ErrKeyIncorrect { | ||||||
| 					return nil, err | 					return nil, err | ||||||
| 				} | 				} | ||||||
| @@ -198,8 +200,12 @@ FindKey: | |||||||
| 		if len(symKeys) != 0 && passphrase != nil { | 		if len(symKeys) != 0 && passphrase != nil { | ||||||
| 			for _, s := range symKeys { | 			for _, s := range symKeys { | ||||||
| 				key, cipherFunc, err := s.Decrypt(passphrase) | 				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 { | 				if err == nil { | ||||||
| 					decrypted, err = se.Decrypt(cipherFunc, key) | 					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 { | 					if err != nil && err != errors.ErrKeyIncorrect { | ||||||
| 						return nil, err | 						return nil, err | ||||||
| 					} | 					} | ||||||
| @@ -207,7 +213,6 @@ FindKey: | |||||||
| 						break FindKey | 						break FindKey | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
| 
 |  | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @@ -216,13 +221,17 @@ FindKey: | |||||||
| 	if err := packets.Push(decrypted); err != nil { | 	if err := packets.Push(decrypted); err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 	return readSignedMessage(packets, md, keyring) | 	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 | // readSignedMessage reads a possibly signed message if mdin is non-zero then | ||||||
| // that structure is updated and returned. Otherwise a fresh MessageDetails is | // that structure is updated and returned. Otherwise a fresh MessageDetails is | ||||||
| // used. | // used. | ||||||
| func readSignedMessage(packets *packet.Reader, mdin *MessageDetails, keyring KeyRing) (md *MessageDetails, err error) { | func readSignedMessage(packets *packet.Reader, mdin *MessageDetails, keyring KeyRing, config *packet.Config) (md *MessageDetails, err error) { | ||||||
| 	if mdin == nil { | 	if mdin == nil { | ||||||
| 		mdin = new(MessageDetails) | 		mdin = new(MessageDetails) | ||||||
| 	} | 	} | ||||||
| @@ -231,6 +240,7 @@ func readSignedMessage(packets *packet.Reader, mdin *MessageDetails, keyring Key | |||||||
| 	var p packet.Packet | 	var p packet.Packet | ||||||
| 	var h hash.Hash | 	var h hash.Hash | ||||||
| 	var wrappedHash hash.Hash | 	var wrappedHash hash.Hash | ||||||
|  | 	var prevLast bool | ||||||
| FindLiteralData: | FindLiteralData: | ||||||
| 	for { | 	for { | ||||||
| 		p, err = packets.Next() | 		p, err = packets.Next() | ||||||
| @@ -243,14 +253,17 @@ FindLiteralData: | |||||||
| 				return nil, err | 				return nil, err | ||||||
| 			} | 			} | ||||||
| 		case *packet.OnePassSignature: | 		case *packet.OnePassSignature: | ||||||
| 			if !p.IsLast { | 			if prevLast { | ||||||
| 				return nil, errors.UnsupportedError("nested signatures") | 				return nil, errors.UnsupportedError("nested signature packets") | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			if p.IsLast { | ||||||
|  | 				prevLast = true | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			h, wrappedHash, err = hashForSignature(p.Hash, p.SigType) | 			h, wrappedHash, err = hashForSignature(p.Hash, p.SigType) | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				md = nil | 				md.SignatureError = err | ||||||
| 				return |  | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			md.IsSigned = true | 			md.IsSigned = true | ||||||
| @@ -265,8 +278,8 @@ FindLiteralData: | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if md.SignedBy != nil { | 	if md.IsSigned && md.SignatureError == nil { | ||||||
| 		md.UnverifiedBody = &signatureCheckReader{packets, h, wrappedHash, md} | 		md.UnverifiedBody = &signatureCheckReader{packets, h, wrappedHash, md, config} | ||||||
| 	} else if md.decrypted != nil { | 	} else if md.decrypted != nil { | ||||||
| 		md.UnverifiedBody = checkReader{md} | 		md.UnverifiedBody = checkReader{md} | ||||||
| 	} else { | 	} else { | ||||||
| @@ -282,6 +295,9 @@ FindLiteralData: | |||||||
| // returns two hashes. The second should be used to hash the message itself and | // returns two hashes. The second should be used to hash the message itself and | ||||||
| // performs any needed preprocessing. | // performs any needed preprocessing. | ||||||
| func hashForSignature(hashId crypto.Hash, sigType packet.SignatureType) (hash.Hash, hash.Hash, error) { | 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() { | 	if !hashId.Available() { | ||||||
| 		return nil, nil, errors.UnsupportedError("hash not available: " + strconv.Itoa(int(hashId))) | 		return nil, nil, errors.UnsupportedError("hash not available: " + strconv.Itoa(int(hashId))) | ||||||
| 	} | 	} | ||||||
| @@ -304,15 +320,21 @@ type checkReader struct { | |||||||
| 	md *MessageDetails | 	md *MessageDetails | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (cr checkReader) Read(buf []byte) (n int, err error) { | func (cr checkReader) Read(buf []byte) (int, error) { | ||||||
| 	n, err = cr.md.LiteralData.Body.Read(buf) | 	n, sensitiveParsingError := cr.md.LiteralData.Body.Read(buf) | ||||||
| 	if err == io.EOF { | 	if sensitiveParsingError == io.EOF { | ||||||
| 		mdcErr := cr.md.decrypted.Close() | 		mdcErr := cr.md.decrypted.Close() | ||||||
| 		if mdcErr != nil { | 		if mdcErr != nil { | ||||||
| 			err = mdcErr | 			return n, mdcErr | ||||||
| 		} | 		} | ||||||
|  | 		return n, io.EOF | ||||||
| 	} | 	} | ||||||
| 	return | 
 | ||||||
|  | 	if sensitiveParsingError != nil { | ||||||
|  | 		return n, errors.StructuralError("parsing error") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return n, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // signatureCheckReader wraps an io.Reader from a LiteralData packet and hashes | // signatureCheckReader wraps an io.Reader from a LiteralData packet and hashes | ||||||
| @@ -322,26 +344,51 @@ type signatureCheckReader struct { | |||||||
| 	packets        *packet.Reader | 	packets        *packet.Reader | ||||||
| 	h, wrappedHash hash.Hash | 	h, wrappedHash hash.Hash | ||||||
| 	md             *MessageDetails | 	md             *MessageDetails | ||||||
|  | 	config         *packet.Config | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (scr *signatureCheckReader) Read(buf []byte) (n int, err error) { | func (scr *signatureCheckReader) Read(buf []byte) (int, error) { | ||||||
| 	n, err = scr.md.LiteralData.Body.Read(buf) | 	n, sensitiveParsingError := scr.md.LiteralData.Body.Read(buf) | ||||||
|  | 
 | ||||||
|  | 	// Hash only if required | ||||||
|  | 	if scr.md.SignedBy != nil { | ||||||
| 		scr.wrappedHash.Write(buf[:n]) | 		scr.wrappedHash.Write(buf[:n]) | ||||||
| 	if err == io.EOF { |  | ||||||
| 		var p packet.Packet |  | ||||||
| 		p, scr.md.SignatureError = scr.packets.Next() |  | ||||||
| 		if scr.md.SignatureError != nil { |  | ||||||
| 			return |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	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 | 			var ok bool | ||||||
| 		if scr.md.Signature, ok = p.(*packet.Signature); ok { | 			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) | 					scr.md.SignatureError = scr.md.SignedBy.PublicKey.VerifySignature(scr.h, scr.md.Signature) | ||||||
| 		} else if scr.md.SignatureV3, ok = p.(*packet.SignatureV3); ok { | 					if scr.md.SignatureError == nil && scr.md.Signature.SigExpired(scr.config.Now()) { | ||||||
| 			scr.md.SignatureError = scr.md.SignedBy.PublicKey.VerifySignatureV3(scr.h, scr.md.SignatureV3) | 						scr.md.SignatureError = errors.ErrSignatureExpired | ||||||
|  | 					} | ||||||
| 				} else { | 				} else { | ||||||
| 			scr.md.SignatureError = errors.StructuralError("LiteralData not followed by Signature") | 					scr.md.UnverifiedSignatures = append(scr.md.UnverifiedSignatures, sig) | ||||||
| 			return | 				} | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			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 | 		// The SymmetricallyEncrypted packet, if any, might have an | ||||||
| @@ -350,24 +397,39 @@ func (scr *signatureCheckReader) Read(buf []byte) (n int, err error) { | |||||||
| 		if scr.md.decrypted != nil { | 		if scr.md.decrypted != nil { | ||||||
| 			mdcErr := scr.md.decrypted.Close() | 			mdcErr := scr.md.decrypted.Close() | ||||||
| 			if mdcErr != nil { | 			if mdcErr != nil { | ||||||
| 				err = mdcErr | 				return n, mdcErr | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  | 		return n, io.EOF | ||||||
| 	} | 	} | ||||||
| 	return | 
 | ||||||
|  | 	if sensitiveParsingError != nil { | ||||||
|  | 		return n, errors.StructuralError("parsing error") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return n, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // CheckDetachedSignature takes a signed file and a detached signature and | // CheckDetachedSignature takes a signed file and a detached signature and | ||||||
| // returns the signer if the signature is valid. If the signer isn't known, | // returns the signer if the signature is valid. If the signer isn't known, | ||||||
| // ErrUnknownIssuer is returned. | // ErrUnknownIssuer is returned. | ||||||
| func CheckDetachedSignature(keyring KeyRing, signed, signature io.Reader) (signer *Entity, err error) { | 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 issuerKeyId uint64 | ||||||
| 	var hashFunc crypto.Hash | 	var hashFunc crypto.Hash | ||||||
| 	var sigType packet.SignatureType | 	var sigType packet.SignatureType | ||||||
| 	var keys []Key | 	var keys []Key | ||||||
| 	var p packet.Packet | 	var p packet.Packet | ||||||
| 
 | 
 | ||||||
|  | 	expectedHashesLen := len(expectedHashes) | ||||||
| 	packets := packet.NewReader(signature) | 	packets := packet.NewReader(signature) | ||||||
|  | 	var sig *packet.Signature | ||||||
| 	for { | 	for { | ||||||
| 		p, err = packets.Next() | 		p, err = packets.Next() | ||||||
| 		if err == io.EOF { | 		if err == io.EOF { | ||||||
| @@ -377,20 +439,25 @@ func CheckDetachedSignature(keyring KeyRing, signed, signature io.Reader) (signe | |||||||
| 			return nil, err | 			return nil, err | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		switch sig := p.(type) { | 		var ok bool | ||||||
| 		case *packet.Signature: | 		sig, ok = p.(*packet.Signature) | ||||||
|  | 		if !ok { | ||||||
|  | 			return nil, errors.StructuralError("non signature packet found") | ||||||
|  | 		} | ||||||
| 		if sig.IssuerKeyId == nil { | 		if sig.IssuerKeyId == nil { | ||||||
| 			return nil, errors.StructuralError("signature doesn't have an issuer") | 			return nil, errors.StructuralError("signature doesn't have an issuer") | ||||||
| 		} | 		} | ||||||
| 		issuerKeyId = *sig.IssuerKeyId | 		issuerKeyId = *sig.IssuerKeyId | ||||||
| 		hashFunc = sig.Hash | 		hashFunc = sig.Hash | ||||||
| 		sigType = sig.SigType | 		sigType = sig.SigType | ||||||
| 		case *packet.SignatureV3: | 
 | ||||||
| 			issuerKeyId = sig.IssuerKeyId | 		for i, expectedHash := range expectedHashes { | ||||||
| 			hashFunc = sig.Hash | 			if hashFunc == expectedHash { | ||||||
| 			sigType = sig.SigType | 				break | ||||||
| 		default: | 			} | ||||||
| 			return nil, errors.StructuralError("non signature packet found") | 			if i+1 == expectedHashesLen { | ||||||
|  | 				return nil, errors.StructuralError("hash algorithm mismatch with cleartext message headers") | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		keys = keyring.KeysByIdUsage(issuerKeyId, packet.KeyFlagSign) | 		keys = keyring.KeysByIdUsage(issuerKeyId, packet.KeyFlagSign) | ||||||
| @@ -413,16 +480,15 @@ func CheckDetachedSignature(keyring KeyRing, signed, signature io.Reader) (signe | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	for _, key := range keys { | 	for _, key := range keys { | ||||||
| 		switch sig := p.(type) { |  | ||||||
| 		case *packet.Signature: |  | ||||||
| 		err = key.PublicKey.VerifySignature(h, sig) | 		err = key.PublicKey.VerifySignature(h, sig) | ||||||
| 		case *packet.SignatureV3: |  | ||||||
| 			err = key.PublicKey.VerifySignatureV3(h, sig) |  | ||||||
| 		default: |  | ||||||
| 			panic("unreachable") |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if err == nil { | 		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 key.Entity, nil | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @@ -432,11 +498,11 @@ func CheckDetachedSignature(keyring KeyRing, signed, signature io.Reader) (signe | |||||||
| 
 | 
 | ||||||
| // CheckArmoredDetachedSignature performs the same actions as | // CheckArmoredDetachedSignature performs the same actions as | ||||||
| // CheckDetachedSignature but expects the signature to be armored. | // CheckDetachedSignature but expects the signature to be armored. | ||||||
| func CheckArmoredDetachedSignature(keyring KeyRing, signed, signature io.Reader) (signer *Entity, err error) { | func CheckArmoredDetachedSignature(keyring KeyRing, signed, signature io.Reader, config *packet.Config) (signer *Entity, err error) { | ||||||
| 	body, err := readArmored(signature, SignatureType) | 	body, err := readArmored(signature, SignatureType) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return CheckDetachedSignature(keyring, signed, body) | 	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
											
										
									
								
							| @@ -4,7 +4,7 @@ | |||||||
| 
 | 
 | ||||||
| // Package s2k implements the various OpenPGP string-to-key transforms as | // Package s2k implements the various OpenPGP string-to-key transforms as | ||||||
| // specified in RFC 4800 section 3.7.1. | // specified in RFC 4800 section 3.7.1. | ||||||
| package s2k // import "golang.org/x/crypto/openpgp/s2k" | package s2k // import "github.com/ProtonMail/go-crypto/openpgp/s2k" | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"crypto" | 	"crypto" | ||||||
| @@ -12,49 +12,67 @@ import ( | |||||||
| 	"io" | 	"io" | ||||||
| 	"strconv" | 	"strconv" | ||||||
| 
 | 
 | ||||||
| 	"golang.org/x/crypto/openpgp/errors" | 	"github.com/ProtonMail/go-crypto/openpgp/errors" | ||||||
|  | 	"github.com/ProtonMail/go-crypto/openpgp/internal/algorithm" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // Config collects configuration parameters for s2k key-stretching | // Config collects configuration parameters for s2k key-stretching | ||||||
| // transformatioms. A nil *Config is valid and results in all default | // transformations. A nil *Config is valid and results in all default | ||||||
| // values. Currently, Config is used only by the Serialize function in | // values. Currently, Config is used only by the Serialize function in | ||||||
| // this package. | // this package. | ||||||
| type Config struct { | 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 | 	// Hash is the default hash function to be used. If | ||||||
| 	// nil, SHA1 is used. | 	// nil, SHA256 is used. | ||||||
| 	Hash crypto.Hash | 	Hash crypto.Hash | ||||||
| 	// S2KCount is only used for symmetric encryption. It | 	// S2KCount is only used for symmetric encryption. It | ||||||
| 	// determines the strength of the passphrase stretching when | 	// determines the strength of the passphrase stretching when | ||||||
| 	// the said passphrase is hashed to produce a key. S2KCount | 	// the said passphrase is hashed to produce a key. S2KCount | ||||||
| 	// should be between 1024 and 65011712, inclusive. If Config | 	// should be between 65536 and 65011712, inclusive. If Config | ||||||
| 	// is nil or S2KCount is 0, the value 65536 used. Not all | 	// is nil or S2KCount is 0, the value 16777216 used. Not all | ||||||
| 	// values in the above range can be represented. S2KCount will | 	// values in the above range can be represented. S2KCount will | ||||||
| 	// be rounded up to the next representable value if it cannot | 	// be rounded up to the next representable value if it cannot | ||||||
| 	// be encoded exactly. When set, it is strongly encrouraged to | 	// be encoded exactly. See RFC 4880 Section 3.7.1.3. | ||||||
| 	// use a value that is at least 65536. See RFC 4880 Section |  | ||||||
| 	// 3.7.1.3. |  | ||||||
| 	S2KCount int | 	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 { | func (c *Config) hash() crypto.Hash { | ||||||
| 	if c == nil || uint(c.Hash) == 0 { | 	if c == nil || uint(c.Hash) == 0 { | ||||||
| 		// SHA1 is the historical default in this package. | 		return crypto.SHA256 | ||||||
| 		return crypto.SHA1 |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return c.Hash | 	return c.Hash | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (c *Config) encodedCount() uint8 { | // EncodedCount get encoded count | ||||||
|  | func (c *Config) EncodedCount() uint8 { | ||||||
| 	if c == nil || c.S2KCount == 0 { | 	if c == nil || c.S2KCount == 0 { | ||||||
| 		return 96 // The common case. Correspoding to 65536 | 		return 224 // The common case. Corresponding to 16777216 | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	i := c.S2KCount | 	i := c.S2KCount | ||||||
|  | 
 | ||||||
| 	switch { | 	switch { | ||||||
| 	// Behave like GPG. Should we make 65536 the lowest value used? | 	case i < 65536: | ||||||
| 	case i < 1024: | 		i = 65536 | ||||||
| 		i = 1024 |  | ||||||
| 	case i > 65011712: | 	case i > 65011712: | ||||||
| 		i = 65011712 | 		i = 65011712 | ||||||
| 	} | 	} | ||||||
| @@ -68,11 +86,11 @@ func (c *Config) encodedCount() uint8 { | |||||||
| // if i is not in the above range (encodedCount above takes care to | // 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. | // pass i in the correct range). See RFC 4880 Section 3.7.7.1. | ||||||
| func encodeCount(i int) uint8 { | func encodeCount(i int) uint8 { | ||||||
| 	if i < 1024 || i > 65011712 { | 	if i < 65536 || i > 65011712 { | ||||||
| 		panic("count arg i outside the required range") | 		panic("count arg i outside the required range") | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	for encoded := 0; encoded < 256; encoded++ { | 	for encoded := 96; encoded < 256; encoded++ { | ||||||
| 		count := decodeCount(uint8(encoded)) | 		count := decodeCount(uint8(encoded)) | ||||||
| 		if count >= i { | 		if count >= i { | ||||||
| 			return uint8(encoded) | 			return uint8(encoded) | ||||||
| @@ -151,9 +169,44 @@ func Iterated(out []byte, h hash.Hash, in []byte, salt []byte, count int) { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // 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 | // Parse reads a binary specification for a string-to-key transformation from r | ||||||
| // and returns a function which performs that transform. | // 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) { | 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 | 	var buf [9]byte | ||||||
| 
 | 
 | ||||||
| 	_, err = io.ReadFull(r, buf[:2]) | 	_, err = io.ReadFull(r, buf[:2]) | ||||||
| @@ -161,91 +214,135 @@ func Parse(r io.Reader) (f func(out, in []byte), err error) { | |||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	hash, ok := HashIdToHash(buf[1]) | 	params = &Params{ | ||||||
| 	if !ok { | 		mode:   buf[0], | ||||||
| 		return nil, errors.UnsupportedError("hash for S2K function: " + strconv.Itoa(int(buf[1]))) | 		hashId: buf[1], | ||||||
| 	} | 	} | ||||||
| 	if !hash.Available() { |  | ||||||
| 		return nil, errors.UnsupportedError("hash not available: " + strconv.Itoa(int(hash))) |  | ||||||
| 	} |  | ||||||
| 	h := hash.New() |  | ||||||
| 
 | 
 | ||||||
| 	switch buf[0] { | 	switch params.mode { | ||||||
| 	case 0: | 	case 0: | ||||||
| 		f := func(out, in []byte) { | 		return params, nil | ||||||
| 			Simple(out, h, in) |  | ||||||
| 		} |  | ||||||
| 		return f, nil |  | ||||||
| 	case 1: | 	case 1: | ||||||
| 		_, err = io.ReadFull(r, buf[:8]) | 		_, err = io.ReadFull(r, buf[:8]) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return | 			return nil, err | ||||||
| 		} | 		} | ||||||
| 		f := func(out, in []byte) { | 
 | ||||||
| 			Salted(out, h, in, buf[:8]) | 		params.salt = buf[:8] | ||||||
| 		} | 		return params, nil | ||||||
| 		return f, nil |  | ||||||
| 	case 3: | 	case 3: | ||||||
| 		_, err = io.ReadFull(r, buf[:9]) | 		_, err = io.ReadFull(r, buf[:9]) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return | 			return nil, err | ||||||
| 		} | 		} | ||||||
| 		count := decodeCount(buf[8]) | 
 | ||||||
|  | 		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) { | 		f := func(out, in []byte) { | ||||||
| 			Iterated(out, h, in, buf[:8], count) | 			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 f, nil | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return nil, errors.UnsupportedError("S2K function") | 	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 | // Serialize salts and stretches the given passphrase and writes the | ||||||
| // resulting key into key. It also serializes an S2K descriptor to | // resulting key into key. It also serializes an S2K descriptor to | ||||||
| // w. The key stretching can be configured with c, which may be | // w. The key stretching can be configured with c, which may be | ||||||
| // nil. In that case, sensible defaults will be used. | // nil. In that case, sensible defaults will be used. | ||||||
| func Serialize(w io.Writer, key []byte, rand io.Reader, passphrase []byte, c *Config) error { | func Serialize(w io.Writer, key []byte, rand io.Reader, passphrase []byte, c *Config) error { | ||||||
| 	var buf [11]byte | 	params, err := Generate(rand, c) | ||||||
| 	buf[0] = 3 /* iterated and salted */ | 	if err != nil { | ||||||
| 	buf[1], _ = HashToHashId(c.hash()) |  | ||||||
| 	salt := buf[2:10] |  | ||||||
| 	if _, err := io.ReadFull(rand, salt); err != nil { |  | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 	encodedCount := c.encodedCount() | 	err = params.Serialize(w) | ||||||
| 	count := decodeCount(encodedCount) | 	if err != nil { | ||||||
| 	buf[10] = encodedCount |  | ||||||
| 	if _, err := w.Write(buf[:]); err != nil { |  | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	Iterated(key, c.hash().New(), passphrase, salt, count) | 	f, err := params.Function() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	f(key, passphrase) | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // hashToHashIdMapping contains pairs relating OpenPGP's hash identifier with |  | ||||||
| // Go's crypto.Hash type. See RFC 4880, section 9.4. |  | ||||||
| var hashToHashIdMapping = []struct { |  | ||||||
| 	id   byte |  | ||||||
| 	hash crypto.Hash |  | ||||||
| 	name string |  | ||||||
| }{ |  | ||||||
| 	{1, crypto.MD5, "MD5"}, |  | ||||||
| 	{2, crypto.SHA1, "SHA1"}, |  | ||||||
| 	{3, crypto.RIPEMD160, "RIPEMD160"}, |  | ||||||
| 	{8, crypto.SHA256, "SHA256"}, |  | ||||||
| 	{9, crypto.SHA384, "SHA384"}, |  | ||||||
| 	{10, crypto.SHA512, "SHA512"}, |  | ||||||
| 	{11, crypto.SHA224, "SHA224"}, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // HashIdToHash returns a crypto.Hash which corresponds to the given OpenPGP | // HashIdToHash returns a crypto.Hash which corresponds to the given OpenPGP | ||||||
| // hash id. | // hash id. | ||||||
| func HashIdToHash(id byte) (h crypto.Hash, ok bool) { | func HashIdToHash(id byte) (h crypto.Hash, ok bool) { | ||||||
| 	for _, m := range hashToHashIdMapping { | 	if hash, ok := algorithm.HashById[id]; ok { | ||||||
| 		if m.id == id { | 		return hash.HashFunc(), true | ||||||
| 			return m.hash, true |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
| 	return 0, false | 	return 0, false | ||||||
| } | } | ||||||
| @@ -253,20 +350,17 @@ func HashIdToHash(id byte) (h crypto.Hash, ok bool) { | |||||||
| // HashIdToString returns the name of the hash function corresponding to the | // HashIdToString returns the name of the hash function corresponding to the | ||||||
| // given OpenPGP hash id. | // given OpenPGP hash id. | ||||||
| func HashIdToString(id byte) (name string, ok bool) { | func HashIdToString(id byte) (name string, ok bool) { | ||||||
| 	for _, m := range hashToHashIdMapping { | 	if hash, ok := algorithm.HashById[id]; ok { | ||||||
| 		if m.id == id { | 		return hash.String(), true | ||||||
| 			return m.name, true |  | ||||||
| 	} | 	} | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return "", false | 	return "", false | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // HashIdToHash returns an OpenPGP hash id which corresponds the given Hash. | // HashIdToHash returns an OpenPGP hash id which corresponds the given Hash. | ||||||
| func HashToHashId(h crypto.Hash) (id byte, ok bool) { | func HashToHashId(h crypto.Hash) (id byte, ok bool) { | ||||||
| 	for _, m := range hashToHashIdMapping { | 	for id, hash := range algorithm.HashById { | ||||||
| 		if m.hash == h { | 		if hash.HashFunc() == h { | ||||||
| 			return m.id, true | 			return id, true | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return 0, false | 	return 0, false | ||||||
| @@ -11,10 +11,10 @@ import ( | |||||||
| 	"strconv" | 	"strconv" | ||||||
| 	"time" | 	"time" | ||||||
| 
 | 
 | ||||||
| 	"golang.org/x/crypto/openpgp/armor" | 	"github.com/ProtonMail/go-crypto/openpgp/armor" | ||||||
| 	"golang.org/x/crypto/openpgp/errors" | 	"github.com/ProtonMail/go-crypto/openpgp/errors" | ||||||
| 	"golang.org/x/crypto/openpgp/packet" | 	"github.com/ProtonMail/go-crypto/openpgp/packet" | ||||||
| 	"golang.org/x/crypto/openpgp/s2k" | 	"github.com/ProtonMail/go-crypto/openpgp/s2k" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // DetachSign signs message with the private key from signer (which must | // DetachSign signs message with the private key from signer (which must | ||||||
| @@ -60,27 +60,35 @@ func armoredDetachSign(w io.Writer, signer *Entity, message io.Reader, sigType p | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func detachSign(w io.Writer, signer *Entity, message io.Reader, sigType packet.SignatureType, config *packet.Config) (err error) { | func detachSign(w io.Writer, signer *Entity, message io.Reader, sigType packet.SignatureType, config *packet.Config) (err error) { | ||||||
| 	if signer.PrivateKey == nil { | 	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") | 		return errors.InvalidArgumentError("signing key doesn't have a private key") | ||||||
| 	} | 	} | ||||||
| 	if signer.PrivateKey.Encrypted { | 	if signingKey.PrivateKey.Encrypted { | ||||||
| 		return errors.InvalidArgumentError("signing key is encrypted") | 		return errors.InvalidArgumentError("signing key is encrypted") | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	sig := new(packet.Signature) | 	sig := new(packet.Signature) | ||||||
| 	sig.SigType = sigType | 	sig.SigType = sigType | ||||||
| 	sig.PubKeyAlgo = signer.PrivateKey.PubKeyAlgo | 	sig.PubKeyAlgo = signingKey.PrivateKey.PubKeyAlgo | ||||||
| 	sig.Hash = config.Hash() | 	sig.Hash = config.Hash() | ||||||
| 	sig.CreationTime = config.Now() | 	sig.CreationTime = config.Now() | ||||||
| 	sig.IssuerKeyId = &signer.PrivateKey.KeyId | 	sigLifetimeSecs := config.SigLifetime() | ||||||
|  | 	sig.SigLifetimeSecs = &sigLifetimeSecs | ||||||
|  | 	sig.IssuerKeyId = &signingKey.PrivateKey.KeyId | ||||||
| 
 | 
 | ||||||
| 	h, wrappedHash, err := hashForSignature(sig.Hash, sig.SigType) | 	h, wrappedHash, err := hashForSignature(sig.Hash, sig.SigType) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	io.Copy(wrappedHash, message) | 	if _, err = io.Copy(wrappedHash, message); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	err = sig.Sign(h, signer.PrivateKey, config) | 	err = sig.Sign(h, signingKey.PrivateKey, config) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| @@ -115,18 +123,27 @@ func SymmetricallyEncrypt(ciphertext io.Writer, passphrase []byte, hints *FileHi | |||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	w, err := packet.SerializeSymmetricallyEncrypted(ciphertext, config.Cipher(), key, config) | 
 | ||||||
|  | 	var w io.WriteCloser | ||||||
|  | 	if config.AEAD() != nil { | ||||||
|  | 		w, err = packet.SerializeAEADEncrypted(ciphertext, key, config.Cipher(), config.AEAD().Mode(), config) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
|  | 	} else { | ||||||
|  | 		w, err = packet.SerializeSymmetricallyEncrypted(ciphertext, config.Cipher(), key, config) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	literaldata := w | 	literalData := w | ||||||
| 	if algo := config.Compression(); algo != packet.CompressionNone { | 	if algo := config.Compression(); algo != packet.CompressionNone { | ||||||
| 		var compConfig *packet.CompressionConfig | 		var compConfig *packet.CompressionConfig | ||||||
| 		if config != nil { | 		if config != nil { | ||||||
| 			compConfig = config.CompressionConfig | 			compConfig = config.CompressionConfig | ||||||
| 		} | 		} | ||||||
| 		literaldata, err = packet.SerializeCompressed(w, algo, compConfig) | 		literalData, err = packet.SerializeCompressed(w, algo, compConfig) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
| @@ -136,7 +153,7 @@ func SymmetricallyEncrypt(ciphertext io.Writer, passphrase []byte, hints *FileHi | |||||||
| 	if !hints.ModTime.IsZero() { | 	if !hints.ModTime.IsZero() { | ||||||
| 		epochSeconds = uint32(hints.ModTime.Unix()) | 		epochSeconds = uint32(hints.ModTime.Unix()) | ||||||
| 	} | 	} | ||||||
| 	return packet.SerializeLiteral(literaldata, hints.IsBinary, hints.FileName, epochSeconds) | 	return packet.SerializeLiteral(literalData, hints.IsBinary, hints.FileName, epochSeconds) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // intersectPreferences mutates and returns a prefix of a that contains only | // intersectPreferences mutates and returns a prefix of a that contains only | ||||||
| @@ -164,15 +181,51 @@ func hashToHashId(h crypto.Hash) uint8 { | |||||||
| 	return v | 	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 | // writeAndSign writes the data as a payload package and, optionally, signs | ||||||
| // it. hints contains optional information, that is also encrypted, | // it. hints contains optional information, that is also encrypted, | ||||||
| // that aids the recipients in processing the message. The resulting | // that aids the recipients in processing the message. The resulting | ||||||
| // WriteCloser must be closed after the contents of the file have been | // WriteCloser must be closed after the contents of the file have been | ||||||
| // written. If config is nil, sensible defaults will be used. | // written. If config is nil, sensible defaults will be used. | ||||||
| func writeAndSign(payload io.WriteCloser, candidateHashes []uint8, signed *Entity, hints *FileHints, config *packet.Config) (plaintext io.WriteCloser, err error) { | 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 | 	var signer *packet.PrivateKey | ||||||
| 	if signed != nil { | 	if signed != nil { | ||||||
| 		signKey, ok := signed.signingKey(config.Now()) | 		signKey, ok := signed.SigningKeyById(config.Now(), config.SigningKey()) | ||||||
| 		if !ok { | 		if !ok { | ||||||
| 			return nil, errors.InvalidArgumentError("no valid signing keys") | 			return nil, errors.InvalidArgumentError("no valid signing keys") | ||||||
| 		} | 		} | ||||||
| @@ -214,7 +267,7 @@ func writeAndSign(payload io.WriteCloser, candidateHashes []uint8, signed *Entit | |||||||
| 
 | 
 | ||||||
| 	if signer != nil { | 	if signer != nil { | ||||||
| 		ops := &packet.OnePassSignature{ | 		ops := &packet.OnePassSignature{ | ||||||
| 			SigType:    packet.SigTypeBinary, | 			SigType:    sigType, | ||||||
| 			Hash:       hash, | 			Hash:       hash, | ||||||
| 			PubKeyAlgo: signer.PubKeyAlgo, | 			PubKeyAlgo: signer.PubKeyAlgo, | ||||||
| 			KeyId:      signer.KeyId, | 			KeyId:      signer.KeyId, | ||||||
| @@ -247,17 +300,29 @@ func writeAndSign(payload io.WriteCloser, candidateHashes []uint8, signed *Entit | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if signer != nil { | 	if signer != nil { | ||||||
| 		return signatureWriter{payload, literalData, hash, hash.New(), signer, config}, 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 | 	return literalData, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Encrypt encrypts a message to a number of recipients and, optionally, signs | // encrypt encrypts a message to a number of recipients and, optionally, signs | ||||||
| // it. hints contains optional information, that is also encrypted, that aids | // it. hints contains optional information, that is also encrypted, that aids | ||||||
| // the recipients in processing the message. The resulting WriteCloser must | // the recipients in processing the message. The resulting WriteCloser must | ||||||
| // be closed after the contents of the file have been written. | // be closed after the contents of the file have been written. | ||||||
| // If config is nil, sensible defaults will be used. | // 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) { | 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 { | 	if len(to) == 0 { | ||||||
| 		return nil, errors.InvalidArgumentError("no encryption recipient provided") | 		return nil, errors.InvalidArgumentError("no encryption recipient provided") | ||||||
| 	} | 	} | ||||||
| @@ -276,21 +341,39 @@ func Encrypt(ciphertext io.Writer, to []*Entity, signed *Entity, hints *FileHint | |||||||
| 		hashToHashId(crypto.SHA1), | 		hashToHashId(crypto.SHA1), | ||||||
| 		hashToHashId(crypto.RIPEMD160), | 		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 | 	// In the event that a recipient doesn't specify any supported ciphers | ||||||
| 	// or hash functions, these are the ones that we assume that every | 	// or hash functions, these are the ones that we assume that every | ||||||
| 	// implementation supports. | 	// implementation supports. | ||||||
| 	defaultCiphers := candidateCiphers[len(candidateCiphers)-1:] | 	defaultCiphers := candidateCiphers[0:1] | ||||||
| 	defaultHashes := candidateHashes[len(candidateHashes)-1:] | 	defaultHashes := candidateHashes[0:1] | ||||||
|  | 	defaultAeadModes := candidateAeadModes[0:1] | ||||||
|  | 	defaultCompression := candidateCompression[0:1] | ||||||
| 
 | 
 | ||||||
| 	encryptKeys := make([]Key, len(to)) | 	encryptKeys := make([]Key, len(to)) | ||||||
|  | 	// AEAD is used only if every key supports it. | ||||||
|  | 	aeadSupported := true | ||||||
|  | 
 | ||||||
| 	for i := range to { | 	for i := range to { | ||||||
| 		var ok bool | 		var ok bool | ||||||
| 		encryptKeys[i], ok = to[i].encryptionKey(config.Now()) | 		encryptKeys[i], ok = to[i].EncryptionKey(config.Now()) | ||||||
| 		if !ok { | 		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") | 			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 | 		sig := to[i].PrimaryIdentity().SelfSignature | ||||||
|  | 		if sig.AEAD == false { | ||||||
|  | 			aeadSupported = false | ||||||
|  | 		} | ||||||
| 
 | 
 | ||||||
| 		preferredSymmetric := sig.PreferredSymmetric | 		preferredSymmetric := sig.PreferredSymmetric | ||||||
| 		if len(preferredSymmetric) == 0 { | 		if len(preferredSymmetric) == 0 { | ||||||
| @@ -300,15 +383,26 @@ func Encrypt(ciphertext io.Writer, to []*Entity, signed *Entity, hints *FileHint | |||||||
| 		if len(preferredHashes) == 0 { | 		if len(preferredHashes) == 0 { | ||||||
| 			preferredHashes = defaultHashes | 			preferredHashes = defaultHashes | ||||||
| 		} | 		} | ||||||
|  | 		preferredAeadModes := sig.PreferredAEAD | ||||||
|  | 		if len(preferredAeadModes) == 0 { | ||||||
|  | 			preferredAeadModes = defaultAeadModes | ||||||
|  | 		} | ||||||
|  | 		preferredCompression := sig.PreferredCompression | ||||||
|  | 		if len(preferredCompression) == 0 { | ||||||
|  | 			preferredCompression = defaultCompression | ||||||
|  | 		} | ||||||
| 		candidateCiphers = intersectPreferences(candidateCiphers, preferredSymmetric) | 		candidateCiphers = intersectPreferences(candidateCiphers, preferredSymmetric) | ||||||
| 		candidateHashes = intersectPreferences(candidateHashes, preferredHashes) | 		candidateHashes = intersectPreferences(candidateHashes, preferredHashes) | ||||||
|  | 		candidateAeadModes = intersectPreferences(candidateAeadModes, preferredAeadModes) | ||||||
|  | 		candidateCompression = intersectPreferences(candidateCompression, preferredCompression) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if len(candidateCiphers) == 0 || len(candidateHashes) == 0 { | 	if len(candidateCiphers) == 0 || len(candidateHashes) == 0 || len(candidateAeadModes) == 0 { | ||||||
| 		return nil, errors.InvalidArgumentError("cannot encrypt because recipient set shares no common algorithms") | 		return nil, errors.InvalidArgumentError("cannot encrypt because recipient set shares no common algorithms") | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	cipher := packet.CipherFunction(candidateCiphers[0]) | 	cipher := packet.CipherFunction(candidateCiphers[0]) | ||||||
|  | 	mode := packet.AEADMode(candidateAeadModes[0]) | ||||||
| 	// If the cipher specified by config is a candidate, we'll use that. | 	// If the cipher specified by config is a candidate, we'll use that. | ||||||
| 	configuredCipher := config.Cipher() | 	configuredCipher := config.Cipher() | ||||||
| 	for _, c := range candidateCiphers { | 	for _, c := range candidateCiphers { | ||||||
| @@ -325,17 +419,29 @@ func Encrypt(ciphertext io.Writer, to []*Entity, signed *Entity, hints *FileHint | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	for _, key := range encryptKeys { | 	for _, key := range encryptKeys { | ||||||
| 		if err := packet.SerializeEncryptedKey(ciphertext, key.PublicKey, cipher, symKey, config); err != nil { | 		if err := packet.SerializeEncryptedKey(keyWriter, key.PublicKey, cipher, symKey, config); err != nil { | ||||||
| 			return nil, err | 			return nil, err | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	payload, err := packet.SerializeSymmetricallyEncrypted(ciphertext, cipher, symKey, config) | 	var payload io.WriteCloser | ||||||
|  | 	if aeadSupported { | ||||||
|  | 		payload, err = packet.SerializeAEADEncrypted(dataWriter, symKey, cipher, mode, config) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return | 			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, config) | 	return writeAndSign(payload, candidateHashes, signed, hints, sigType, config) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Sign signs a message. The resulting WriteCloser must be closed after the | // Sign signs a message. The resulting WriteCloser must be closed after the | ||||||
| @@ -355,13 +461,17 @@ func Sign(output io.Writer, signed *Entity, hints *FileHints, config *packet.Con | |||||||
| 		hashToHashId(crypto.SHA1), | 		hashToHashId(crypto.SHA1), | ||||||
| 		hashToHashId(crypto.RIPEMD160), | 		hashToHashId(crypto.RIPEMD160), | ||||||
| 	} | 	} | ||||||
| 	defaultHashes := candidateHashes[len(candidateHashes)-1:] | 	defaultHashes := candidateHashes[0:1] | ||||||
| 	preferredHashes := signed.primaryIdentity().SelfSignature.PreferredHash | 	preferredHashes := signed.PrimaryIdentity().SelfSignature.PreferredHash | ||||||
| 	if len(preferredHashes) == 0 { | 	if len(preferredHashes) == 0 { | ||||||
| 		preferredHashes = defaultHashes | 		preferredHashes = defaultHashes | ||||||
| 	} | 	} | ||||||
| 	candidateHashes = intersectPreferences(candidateHashes, preferredHashes) | 	candidateHashes = intersectPreferences(candidateHashes, preferredHashes) | ||||||
| 	return writeAndSign(noOpCloser{output}, candidateHashes, signed, hints, config) | 	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 | // signatureWriter hashes the contents of a message while passing it along to | ||||||
| @@ -371,23 +481,35 @@ type signatureWriter struct { | |||||||
| 	encryptedData io.WriteCloser | 	encryptedData io.WriteCloser | ||||||
| 	literalData   io.WriteCloser | 	literalData   io.WriteCloser | ||||||
| 	hashType      crypto.Hash | 	hashType      crypto.Hash | ||||||
|  | 	wrappedHash   hash.Hash | ||||||
| 	h             hash.Hash | 	h             hash.Hash | ||||||
| 	signer        *packet.PrivateKey | 	signer        *packet.PrivateKey | ||||||
|  | 	sigType       packet.SignatureType | ||||||
| 	config        *packet.Config | 	config        *packet.Config | ||||||
|  | 	metadata      *packet.LiteralData // V5 signatures protect document metadata | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (s signatureWriter) Write(data []byte) (int, error) { | func (s signatureWriter) Write(data []byte) (int, error) { | ||||||
| 	s.h.Write(data) | 	s.wrappedHash.Write(data) | ||||||
|  | 	switch s.sigType { | ||||||
|  | 	case packet.SigTypeBinary: | ||||||
| 		return s.literalData.Write(data) | 		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 { | func (s signatureWriter) Close() error { | ||||||
| 	sig := &packet.Signature{ | 	sig := &packet.Signature{ | ||||||
| 		SigType:      packet.SigTypeBinary, | 		Version:      s.signer.Version, | ||||||
|  | 		SigType:      s.sigType, | ||||||
| 		PubKeyAlgo:   s.signer.PubKeyAlgo, | 		PubKeyAlgo:   s.signer.PubKeyAlgo, | ||||||
| 		Hash:         s.hashType, | 		Hash:         s.hashType, | ||||||
| 		CreationTime: s.config.Now(), | 		CreationTime: s.config.Now(), | ||||||
| 		IssuerKeyId:  &s.signer.KeyId, | 		IssuerKeyId:  &s.signer.KeyId, | ||||||
|  | 		Metadata:     s.metadata, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if err := sig.Sign(s.h, s.signer, s.config); err != nil { | 	if err := sig.Sign(s.h, s.signer, s.config); err != nil { | ||||||
| @@ -416,3 +538,31 @@ func (c noOpCloser) Write(data []byte) (n int, err error) { | |||||||
| func (c noOpCloser) Close() error { | func (c noOpCloser) Close() error { | ||||||
| 	return nil | 	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 | ||||||
|  | } | ||||||
							
								
								
									
										42
									
								
								vendor/github.com/acomagu/bufpipe/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								vendor/github.com/acomagu/bufpipe/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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) | ||||||
							
								
								
									
										128
									
								
								vendor/github.com/acomagu/bufpipe/bufpipe.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								vendor/github.com/acomagu/bufpipe/bufpipe.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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 | ||||||
|  | } | ||||||
							
								
								
									
										2
									
								
								vendor/github.com/acomagu/bufpipe/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/acomagu/bufpipe/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | |||||||
|  | // Package bufpipe provides a IO pipe, has variable-sized buffer. | ||||||
|  | package bufpipe | ||||||
							
								
								
									
										5
									
								
								vendor/github.com/acomagu/bufpipe/go.mod
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								vendor/github.com/acomagu/bufpipe/go.mod
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | |||||||
|  | module github.com/acomagu/bufpipe | ||||||
|  |  | ||||||
|  | go 1.12 | ||||||
|  |  | ||||||
|  | require github.com/matryer/is v1.2.0 | ||||||
							
								
								
									
										2
									
								
								vendor/github.com/acomagu/bufpipe/go.sum
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/acomagu/bufpipe/go.sum
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | |||||||
|  | github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A= | ||||||
|  | github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= | ||||||
							
								
								
									
										98
									
								
								vendor/github.com/adrg/xdg/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										98
									
								
								vendor/github.com/adrg/xdg/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,6 +1,6 @@ | |||||||
| <h1 align="center"> | <h1 align="center"> | ||||||
|   <div> |   <div> | ||||||
|     <img src="https://raw.githubusercontent.com/adrg/adrg.github.io/master/assets/projects/xdg/logo.png" height="80px" alt="xdg logo"/> |     <img src="https://raw.githubusercontent.com/adrg/adrg.github.io/master/assets/projects/xdg/logo.svg" alt="xdg logo"/> | ||||||
|   </div> |   </div> | ||||||
| </h1> | </h1> | ||||||
|  |  | ||||||
| @@ -44,7 +44,7 @@ applications should use the XDG defined locations instead of hardcoding paths. | |||||||
|  |  | ||||||
| The package also includes the locations of well known [user directories](https://wiki.archlinux.org/index.php/XDG_user_directories) | The package also includes the locations of well known [user directories](https://wiki.archlinux.org/index.php/XDG_user_directories) | ||||||
| and an implementation of the [state directory](https://wiki.debian.org/XDGBaseDirectorySpecification#Proposal:_STATE_directory) proposal. | and an implementation of the [state directory](https://wiki.debian.org/XDGBaseDirectorySpecification#Proposal:_STATE_directory) proposal. | ||||||
| Windows, macOS and most flavors of Unix are supported. | Most flavors of Unix, Windows, macOS and Plan 9 are supported. | ||||||
|  |  | ||||||
| Full documentation can be found at: https://pkg.go.dev/github.com/adrg/xdg. | Full documentation can be found at: https://pkg.go.dev/github.com/adrg/xdg. | ||||||
|  |  | ||||||
| @@ -58,75 +58,56 @@ present in the environment. | |||||||
|  |  | ||||||
| #### XDG Base Directory | #### XDG Base Directory | ||||||
|  |  | ||||||
| |                 | Unix                                | macOS                                                                                 | Windows                                 | | |                                                | Unix                                                  | macOS                                                                                                            | Windows                                                   | Plan 9                     | | ||||||
| | :-------------- | :---------------------------------- | :------------------------------------------------------------------------------------ | :-------------------------------------- | | | :--------------------------------------------- | :---------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------- | :------------------------- | | ||||||
| | XDG_DATA_HOME   | `~/.local/share`                    | `~/Library/Application Support`                                                       | `%LOCALAPPDATA%`                        | | | <kbd><b><samp>XDG_DATA_HOME</samp></b></kbd>   | <kbd>~/.local/share</kbd>                             | <kbd>~/Library/Application Support</kbd>                                                                         | <kbd>%LOCALAPPDATA%</kbd>                                 | <kbd>$home/lib</kbd>       | | ||||||
| | XDG_DATA_DIRS   | `/usr/local/share`<br/>`/usr/share` | `/Library/Application Support`                                                        | `%APPDATA%\Roaming`<br/>`%PROGRAMDATA%` | | | <kbd><b><samp>XDG_DATA_DIRS</samp></b></kbd>   | <kbd>/usr/local/share</kbd><br/><kbd>/usr/share</kbd> | <kbd>/Library/Application Support</kbd>                                                                          | <kbd>%APPDATA%\Roaming</kbd><br/><kbd>%PROGRAMDATA%</kbd> | <kbd>/lib</kbd>            | | ||||||
| | XDG_CONFIG_HOME | `~/.config`                         | `~/Library/Application Support`                                                       | `%LOCALAPPDATA%`                        | | | <kbd><b><samp>XDG_CONFIG_HOME</samp></b></kbd> | <kbd>~/.config</kbd>                                  | <kbd>~/Library/Application Support</kbd>                                                                         | <kbd>%LOCALAPPDATA%</kbd>                                 | <kbd>$home/lib</kbd>       | | ||||||
| | XDG_CONFIG_DIRS | `/etc/xdg`                          | `~/Library/Preferences`<br/>`/Library/Application Support`<br/>`/Library/Preferences` | `%PROGRAMDATA%`                         | | | <kbd><b><samp>XDG_CONFIG_DIRS</samp></b></kbd> | <kbd>/etc/xdg</kbd>                                   | <kbd>~/Library/Preferences</kbd><br/><kbd>/Library/Application Support</kbd><br/><kbd>/Library/Preferences</kbd> | <kbd>%PROGRAMDATA%</kbd>                                  | <kbd>/lib</kbd>            | | ||||||
| | XDG_CACHE_HOME  | `~/.cache`                          | `~/Library/Caches`                                                                    | `%LOCALAPPDATA%\cache`                  | | | <kbd><b><samp>XDG_CACHE_HOME</samp></b></kbd>  | <kbd>~/.cache</kbd>                                   | <kbd>~/Library/Caches</kbd>                                                                                      | <kbd>%LOCALAPPDATA%\cache</kbd>                           | <kbd>$home/lib/cache</kbd> | | ||||||
| | XDG_RUNTIME_DIR | `/run/user/UID`                     | `~/Library/Application Support`                                                       | `%LOCALAPPDATA%`                        | | | <kbd><b><samp>XDG_RUNTIME_DIR</samp></b></kbd> | <kbd>/run/user/UID</kbd>                              | <kbd>~/Library/Application Support</kbd>                                                                         | <kbd>%LOCALAPPDATA%</kbd>                                 | <kbd>/tmp</kbd>            | | ||||||
|  |  | ||||||
| #### XDG user directories | #### XDG user directories | ||||||
|  |  | ||||||
| |                     | Unix          | macOS         | Windows                   | | |                                                    | Unix                   | macOS                  | Windows                            | Plan 9                     | | ||||||
| | :------------------ | :------------ | :------------ | :------------------------ | | | :------------------------------------------------- | :--------------------- | :--------------------- | :--------------------------------- | :------------------------- | | ||||||
| | XDG_DESKTOP_DIR     | `~/Desktop`   | `~/Desktop`   | `%USERPROFILE%/Desktop`   | | | <kbd><b><samp>XDG_DESKTOP_DIR</samp></b></kbd>     | <kbd>~/Desktop</kbd>   | <kbd>~/Desktop</kbd>   | <kbd>%USERPROFILE%\Desktop</kbd>   | <kbd>$home/desktop</kbd>   | | ||||||
| | XDG_DOWNLOAD_DIR    | `~/Downloads` | `~/Downloads` | `%USERPROFILE%/Downloads` | | | <kbd><b><samp>XDG_DOWNLOAD_DIR</samp></b></kbd>    | <kbd>~/Downloads</kbd> | <kbd>~/Downloads</kbd> | <kbd>%USERPROFILE%\Downloads</kbd> | <kbd>$home/downloads</kbd> | | ||||||
| | XDG_DOCUMENTS_DIR   | `~/Documents` | `~/Documents` | `%USERPROFILE%/Documents` | | | <kbd><b><samp>XDG_DOCUMENTS_DIR</samp></b></kbd>   | <kbd>~/Documents</kbd> | <kbd>~/Documents</kbd> | <kbd>%USERPROFILE%\Documents</kbd> | <kbd>$home/documents</kbd> | | ||||||
| | XDG_MUSIC_DIR       | `~/Music`     | `~/Music`     | `%USERPROFILE%/Music`     | | | <kbd><b><samp>XDG_MUSIC_DIR</samp></b></kbd>       | <kbd>~/Music</kbd>     | <kbd>~/Music</kbd>     | <kbd>%USERPROFILE%\Music</kbd>     | <kbd>$home/music</kbd>     | | ||||||
| | XDG_PICTURES_DIR    | `~/Pictures`  | `~/Pictures`  | `%USERPROFILE%/Pictures`  | | | <kbd><b><samp>XDG_PICTURES_DIR</samp></b></kbd>    | <kbd>~/Pictures</kbd>  | <kbd>~/Pictures</kbd>  | <kbd>%USERPROFILE%\Pictures</kbd>  | <kbd>$home/pictures</kbd>  | | ||||||
| | XDG_VIDEOS_DIR      | `~/Videos`    | `~/Movies`    | `%USERPROFILE%/Videos`    | | | <kbd><b><samp>XDG_VIDEOS_DIR</samp></b></kbd>      | <kbd>~/Videos</kbd>    | <kbd>~/Movies</kbd>    | <kbd>%USERPROFILE%\Videos</kbd>    | <kbd>$home/videos</kbd>    | | ||||||
| | XDG_TEMPLATES_DIR   | `~/Templates` | `~/Templates` | `%USERPROFILE%/Templates` | | | <kbd><b><samp>XDG_TEMPLATES_DIR</samp></b></kbd>   | <kbd>~/Templates</kbd> | <kbd>~/Templates</kbd> | <kbd>%USERPROFILE%\Templates</kbd> | <kbd>$home/templates</kbd> | | ||||||
| | XDG_PUBLICSHARE_DIR | `~/Public`    | `~/Public`    | `%PUBLIC%`                | | | <kbd><b><samp>XDG_PUBLICSHARE_DIR</samp></b></kbd> | <kbd>~/Public</kbd>    | <kbd>~/Public</kbd>    | <kbd>%PUBLIC%</kbd>                | <kbd>$home/public</kbd>    | | ||||||
|  |  | ||||||
| #### Non-standard directories | #### Non-standard directories | ||||||
|  |  | ||||||
| State directory | State directory | ||||||
|  |  | ||||||
| ``` | |                                               | Unix                      | macOS                                    | Windows                   | Plan 9                     | | ||||||
| Unix | | :-------------------------------------------- | :------------------------ | :--------------------------------------- | :------------------------ | :------------------------- | | ||||||
|   • ~/.local/state | | <kbd><b><samp>XDG_STATE_HOME</samp></b></kbd> | <kbd>~/.local/state</kbd> | <kbd>~/Library/Application Support</kbd> | <kbd>%LOCALAPPDATA%</kbd> | <kbd>$home/lib/state</kbd> | | ||||||
| macOS |  | ||||||
|   • ~/Library/Application Support |  | ||||||
| Windows |  | ||||||
|   • %LOCALAPPDATA% |  | ||||||
| ``` |  | ||||||
|  |  | ||||||
| Application directories | Application directories | ||||||
|  |  | ||||||
| ``` | | Unix                                     | macOS                    | Windows                                                            | Plan 9                | | ||||||
| Unix | | :--------------------------------------- | :----------------------- | :----------------------------------------------------------------- | :-------------------- | | ||||||
|   • $XDG_DATA_HOME/applications | | <kbd>$XDG_DATA_HOME/applications</kbd>   | <kbd>/Applications</kbd> | <kbd>%APPDATA%\Roaming\Microsoft\Windows\Start Menu\Programs</kbd> | <kbd>$home/bin</kbd>  | | ||||||
|   • ~/.local/share/applications | | <kbd>~/.local/share/applications</kbd>   |                          |                                                                    | <kbd>/bin</kbd>       | | ||||||
|   • /usr/local/share/applications | | <kbd>/usr/local/share/applications</kbd> |                          |                                                                    |                       | | ||||||
|   • /usr/share/applications | | <kbd>/usr/share/applications</kbd>       |                          |                                                                    |                       | | ||||||
|   • $XDG_DATA_DIRS/applications | | <kbd>$XDG_DATA_DIRS/applications</kbd>   |                          |                                                                    |                       | | ||||||
| macOS |  | ||||||
|   • /Applications |  | ||||||
| Windows |  | ||||||
|   • %APPDATA%\Roaming\Microsoft\Windows\Start Menu\Programs |  | ||||||
| ``` |  | ||||||
|  |  | ||||||
| Font directories | Font directories | ||||||
|  |  | ||||||
| ``` | | Unix                              | macOS                             | Windows                                           | Plan 9                    | | ||||||
| Unix | | :-------------------------------- | :-------------------------------- | :------------------------------------------------ | :------------------------ | | ||||||
|   • $XDG_DATA_HOME/fonts | | <kbd>$XDG_DATA_HOME/fonts</kbd>   | <kbd>~/Library/Fonts</kbd>        | <kbd>%windir%\Fonts</kbd>                         | <kbd>$home/lib/font</kbd> | | ||||||
|   • ~/.fonts | | <kbd>~/.fonts</kbd>               | <kbd>/Library/Fonts</kbd>         | <kbd>%LOCALAPPDATA%\Microsoft\Windows\Fonts</kbd> | <kbd>/lib/font</kbd>      | | ||||||
|   • ~/.local/share/fonts | | <kbd>~/.local/share/fonts</kbd>   | <kbd>/System/Library/Fonts</kbd>  |                                                   |                           | | ||||||
|   • /usr/local/share/fonts | | <kbd>/usr/local/share/fonts</kbd> | <kbd>/Network/Library/Fonts</kbd> |                                                   |                           | | ||||||
|   • /usr/share/fonts | | <kbd>/usr/share/fonts</kbd>       |                                   |                                                   |                           | | ||||||
|   • $XDG_DATA_DIRS/fonts | | <kbd>$XDG_DATA_DIRS/fonts</kbd>   |                                   |                                                   |                           | | ||||||
| macOS |  | ||||||
|   • ~/Library/Fonts |  | ||||||
|   • /Library/Fonts |  | ||||||
|   • /System/Library/Fonts |  | ||||||
|   • /Network/Library/Fonts |  | ||||||
| Windows |  | ||||||
|   • %windir%\Fonts |  | ||||||
|   • %LOCALAPPDATA%\Microsoft\Windows\Fonts |  | ||||||
| ``` |  | ||||||
|  |  | ||||||
| ## Usage | ## Usage | ||||||
|  |  | ||||||
| @@ -228,7 +209,8 @@ See [CONTRIBUTING.MD](CONTRIBUTING.md). | |||||||
| [wichert](https://github.com/wichert), | [wichert](https://github.com/wichert), | ||||||
| [bouncepaw](https://github.com/bouncepaw), | [bouncepaw](https://github.com/bouncepaw), | ||||||
| [gabriel-vasile](https://github.com/gabriel-vasile), | [gabriel-vasile](https://github.com/gabriel-vasile), | ||||||
| [KalleDK](https://github.com/KalleDK). | [KalleDK](https://github.com/KalleDK), | ||||||
|  | [djdv](https://github.com/djdv). | ||||||
|  |  | ||||||
| ## References | ## References | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										11
									
								
								vendor/github.com/adrg/xdg/codecov.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								vendor/github.com/adrg/xdg/codecov.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | |||||||
|  | coverage: | ||||||
|  |   status: | ||||||
|  |     project: | ||||||
|  |       default: | ||||||
|  |         target: 90% | ||||||
|  |         threshold: 1% | ||||||
|  |     patch: | ||||||
|  |       default: | ||||||
|  |         target: 100% | ||||||
|  | ignore: | ||||||
|  |   - "paths_plan9.go" | ||||||
							
								
								
									
										2
									
								
								vendor/github.com/adrg/xdg/go.mod
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/adrg/xdg/go.mod
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -2,4 +2,4 @@ module github.com/adrg/xdg | |||||||
|  |  | ||||||
| go 1.14 | go 1.14 | ||||||
|  |  | ||||||
| require github.com/stretchr/testify v1.6.1 | require github.com/stretchr/testify v1.7.0 | ||||||
|   | |||||||
							
								
								
									
										5
									
								
								vendor/github.com/adrg/xdg/go.sum
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								vendor/github.com/adrg/xdg/go.sum
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -2,9 +2,10 @@ github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8 | |||||||
| github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||||||
| github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | 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/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||||||
|  | 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/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||||||
| github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= | ||||||
| github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | ||||||
| gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= | ||||||
| gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||||||
| gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= | ||||||
|   | |||||||
							
								
								
									
										42
									
								
								vendor/github.com/adrg/xdg/paths_plan9.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								vendor/github.com/adrg/xdg/paths_plan9.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | |||||||
|  | package xdg | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"path/filepath" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func initBaseDirs(home string) { | ||||||
|  | 	homeLibDir := filepath.Join(home, "lib") | ||||||
|  | 	rootLibDir := "/lib" | ||||||
|  |  | ||||||
|  | 	// Initialize base directories. | ||||||
|  | 	baseDirs.dataHome = xdgPath(envDataHome, homeLibDir) | ||||||
|  | 	baseDirs.data = xdgPaths(envDataDirs, rootLibDir) | ||||||
|  | 	baseDirs.configHome = xdgPath(envConfigHome, homeLibDir) | ||||||
|  | 	baseDirs.config = xdgPaths(envConfigDirs, rootLibDir) | ||||||
|  | 	baseDirs.cacheHome = xdgPath(envCacheHome, filepath.Join(homeLibDir, "cache")) | ||||||
|  | 	baseDirs.runtime = xdgPath(envRuntimeDir, "/tmp") | ||||||
|  |  | ||||||
|  | 	// Initialize non-standard directories. | ||||||
|  | 	baseDirs.stateHome = xdgPath(envStateHome, filepath.Join(homeLibDir, "state")) | ||||||
|  |  | ||||||
|  | 	baseDirs.applications = []string{ | ||||||
|  | 		filepath.Join(home, "bin"), | ||||||
|  | 		"/bin", | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	baseDirs.fonts = []string{ | ||||||
|  | 		filepath.Join(homeLibDir, "font"), | ||||||
|  | 		"/lib/font", | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func initUserDirs(home string) { | ||||||
|  | 	UserDirs.Desktop = xdgPath(envDesktopDir, filepath.Join(home, "desktop")) | ||||||
|  | 	UserDirs.Download = xdgPath(envDownloadDir, filepath.Join(home, "downloads")) | ||||||
|  | 	UserDirs.Documents = xdgPath(envDocumentsDir, filepath.Join(home, "documents")) | ||||||
|  | 	UserDirs.Music = xdgPath(envMusicDir, filepath.Join(home, "music")) | ||||||
|  | 	UserDirs.Pictures = xdgPath(envPicturesDir, filepath.Join(home, "pictures")) | ||||||
|  | 	UserDirs.Videos = xdgPath(envVideosDir, filepath.Join(home, "videos")) | ||||||
|  | 	UserDirs.Templates = xdgPath(envTemplatesDir, filepath.Join(home, "templates")) | ||||||
|  | 	UserDirs.PublicShare = xdgPath(envPublicShareDir, filepath.Join(home, "public")) | ||||||
|  | } | ||||||
							
								
								
									
										2
									
								
								vendor/github.com/adrg/xdg/paths_unix.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/adrg/xdg/paths_unix.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,4 +1,4 @@ | |||||||
| // +build aix dragonfly freebsd linux nacl netbsd openbsd solaris | // +build aix dragonfly freebsd js,wasm nacl linux netbsd openbsd solaris | ||||||
|  |  | ||||||
| package xdg | package xdg | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										10
									
								
								vendor/github.com/adrg/xdg/stat.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								vendor/github.com/adrg/xdg/stat.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | |||||||
|  | // +build !windows | ||||||
|  |  | ||||||
|  | package xdg | ||||||
|  |  | ||||||
|  | import "os" | ||||||
|  |  | ||||||
|  | func pathExists(path string) bool { | ||||||
|  | 	_, err := os.Stat(path) | ||||||
|  | 	return err == nil || os.IsExist(err) | ||||||
|  | } | ||||||
							
								
								
									
										15
									
								
								vendor/github.com/adrg/xdg/stat_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								vendor/github.com/adrg/xdg/stat_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | |||||||
|  | package xdg | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"os" | ||||||
|  | 	"path/filepath" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func pathExists(path string) bool { | ||||||
|  | 	fi, err := os.Lstat(path) | ||||||
|  | 	if fi != nil && fi.Mode()&os.ModeSymlink != 0 { | ||||||
|  | 		_, err = filepath.EvalSymlinks(path) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return err == nil || os.IsExist(err) | ||||||
|  | } | ||||||
							
								
								
									
										9
									
								
								vendor/github.com/adrg/xdg/utils.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										9
									
								
								vendor/github.com/adrg/xdg/utils.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -33,11 +33,6 @@ func homeDir() string { | |||||||
| 	return "" | 	return "" | ||||||
| } | } | ||||||
|  |  | ||||||
| func exists(path string) bool { |  | ||||||
| 	_, err := os.Stat(path) |  | ||||||
| 	return err == nil || os.IsExist(err) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func expandPath(path, homeDir string) string { | func expandPath(path, homeDir string) string { | ||||||
| 	if path == "" || homeDir == "" { | 	if path == "" || homeDir == "" { | ||||||
| 		return path | 		return path | ||||||
| @@ -58,7 +53,7 @@ func createPath(name string, paths []string) (string, error) { | |||||||
| 		path := filepath.Join(p, name) | 		path := filepath.Join(p, name) | ||||||
| 		dir := filepath.Dir(path) | 		dir := filepath.Dir(path) | ||||||
|  |  | ||||||
| 		if exists(dir) { | 		if pathExists(dir) { | ||||||
| 			return path, nil | 			return path, nil | ||||||
| 		} | 		} | ||||||
| 		if err := os.MkdirAll(dir, os.ModeDir|0700); err == nil { | 		if err := os.MkdirAll(dir, os.ModeDir|0700); err == nil { | ||||||
| @@ -76,7 +71,7 @@ func searchFile(name string, paths []string) (string, error) { | |||||||
| 	var searchedPaths []string | 	var searchedPaths []string | ||||||
| 	for _, p := range paths { | 	for _, p := range paths { | ||||||
| 		path := filepath.Join(p, name) | 		path := filepath.Join(p, name) | ||||||
| 		if exists(path) { | 		if pathExists(path) { | ||||||
| 			return path, nil | 			return path, nil | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										16
									
								
								vendor/github.com/alecthomas/chroma/.golangci.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										16
									
								
								vendor/github.com/alecthomas/chroma/.golangci.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -25,6 +25,17 @@ linters: | |||||||
|     - testpackage |     - testpackage | ||||||
|     - godot |     - godot | ||||||
|     - nestif |     - nestif | ||||||
|  |     - paralleltest | ||||||
|  |     - nlreturn | ||||||
|  |     - cyclop | ||||||
|  |     - exhaustivestruct | ||||||
|  |     - gci | ||||||
|  |     - gofumpt | ||||||
|  |     - errorlint | ||||||
|  |     - exhaustive | ||||||
|  |     - ifshort | ||||||
|  |     - wrapcheck | ||||||
|  |     - stylecheck | ||||||
|  |  | ||||||
| linters-settings: | linters-settings: | ||||||
|   govet: |   govet: | ||||||
| @@ -36,6 +47,11 @@ linters-settings: | |||||||
|   goconst: |   goconst: | ||||||
|     min-len: 8 |     min-len: 8 | ||||||
|     min-occurrences: 3 |     min-occurrences: 3 | ||||||
|  |   forbidigo: | ||||||
|  |     forbid: | ||||||
|  |       - (Must)?NewLexer | ||||||
|  |     exclude_godoc_examples: false | ||||||
|  |  | ||||||
|  |  | ||||||
| issues: | issues: | ||||||
|   max-per-linter: 0 |   max-per-linter: 0 | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								vendor/github.com/alecthomas/chroma/.goreleaser.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/alecthomas/chroma/.goreleaser.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -6,6 +6,8 @@ release: | |||||||
| brews: | brews: | ||||||
|   - |   - | ||||||
|     install: bin.install "chroma" |     install: bin.install "chroma" | ||||||
|  | env: | ||||||
|  |   - CGO_ENABLED=0 | ||||||
| builds: | builds: | ||||||
| - goos: | - goos: | ||||||
|     - linux |     - linux | ||||||
|   | |||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user
	 Norwin
					Norwin