mirror of
				https://github.com/cheat/cheat.git
				synced 2025-11-03 23:35:27 +01:00 
			
		
		
		
	@@ -9,13 +9,13 @@ On Unix-like systems, you may simply paste the following snippet into your termi
 | 
			
		||||
 | 
			
		||||
```sh
 | 
			
		||||
cd /tmp \
 | 
			
		||||
  && wget https://github.com/cheat/cheat/releases/download/4.3.2/cheat-linux-amd64.gz \
 | 
			
		||||
  && wget https://github.com/cheat/cheat/releases/download/4.3.3/cheat-linux-amd64.gz \
 | 
			
		||||
  && gunzip cheat-linux-amd64.gz \
 | 
			
		||||
  && chmod +x cheat-linux-amd64 \
 | 
			
		||||
  && sudo mv cheat-linux-amd64 /usr/local/bin/cheat
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
You may need to need to change the version number (`4.3.2`) and the archive
 | 
			
		||||
You may need to need to change the version number (`4.3.3`) and the archive
 | 
			
		||||
(`cheat-linux-amd64.gz`) depending on your platform.
 | 
			
		||||
 | 
			
		||||
See the [releases page][releases] for a list of supported platforms.
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,7 @@ import (
 | 
			
		||||
	"github.com/cheat/cheat/internal/installer"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const version = "4.3.2"
 | 
			
		||||
const version = "4.3.3"
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										19
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								go.mod
									
									
									
									
									
								
							@@ -6,6 +6,7 @@ require (
 | 
			
		||||
	github.com/alecthomas/chroma v0.10.0
 | 
			
		||||
	github.com/davecgh/go-spew v1.1.1
 | 
			
		||||
	github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815
 | 
			
		||||
	github.com/go-git/go-git/v5 v5.4.2
 | 
			
		||||
	github.com/mattn/go-isatty v0.0.16
 | 
			
		||||
	github.com/mitchellh/go-homedir v1.1.0
 | 
			
		||||
	gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0
 | 
			
		||||
@@ -13,9 +14,21 @@ require (
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
require (
 | 
			
		||||
	github.com/Microsoft/go-winio v0.5.2 // indirect
 | 
			
		||||
	github.com/ProtonMail/go-crypto v0.0.0-20220824120805-4b6e5c587895 // indirect
 | 
			
		||||
	github.com/acomagu/bufpipe v1.0.3 // indirect
 | 
			
		||||
	github.com/cloudflare/circl v1.2.0 // indirect
 | 
			
		||||
	github.com/dlclark/regexp2 v1.7.0 // indirect
 | 
			
		||||
	github.com/kr/text v0.2.0 // indirect
 | 
			
		||||
	github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
 | 
			
		||||
	github.com/emirpasic/gods v1.18.1 // indirect
 | 
			
		||||
	github.com/go-git/gcfg v1.5.0 // indirect
 | 
			
		||||
	github.com/go-git/go-billy/v5 v5.3.1 // indirect
 | 
			
		||||
	github.com/imdario/mergo v0.3.13 // indirect
 | 
			
		||||
	github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
 | 
			
		||||
	github.com/kevinburke/ssh_config v1.2.0 // indirect
 | 
			
		||||
	github.com/sergi/go-diff v1.2.0 // indirect
 | 
			
		||||
	github.com/xanzy/ssh-agent v0.3.2 // indirect
 | 
			
		||||
	golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d // indirect
 | 
			
		||||
	golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b // indirect
 | 
			
		||||
	golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64 // indirect
 | 
			
		||||
	gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
 | 
			
		||||
	gopkg.in/warnings.v0 v0.1.2 // indirect
 | 
			
		||||
)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										111
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										111
									
								
								go.sum
									
									
									
									
									
								
							@@ -1,5 +1,23 @@
 | 
			
		||||
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
 | 
			
		||||
github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
 | 
			
		||||
github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA=
 | 
			
		||||
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
 | 
			
		||||
github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo=
 | 
			
		||||
github.com/ProtonMail/go-crypto v0.0.0-20220824120805-4b6e5c587895 h1:NsReiLpErIPzRrnogAXYwSoU7txA977LjDGrbkewJbg=
 | 
			
		||||
github.com/ProtonMail/go-crypto v0.0.0-20220824120805-4b6e5c587895/go.mod h1:UBYPn8k0D56RtnR8RFQMjmh4KrZzWJ5o7Z9SYjossQ8=
 | 
			
		||||
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/alecthomas/chroma v0.10.0 h1:7XDcGkCQopCNKjZHfYrNLraA+M7e0fMiJ/Mfikbfjek=
 | 
			
		||||
github.com/alecthomas/chroma v0.10.0/go.mod h1:jtJATyUxlIORhUOFNA9NZDWGAQ8wpxQQqNSB4rjA/1s=
 | 
			
		||||
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/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/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
 | 
			
		||||
github.com/bwesterb/go-ristretto v1.2.1/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
 | 
			
		||||
github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I=
 | 
			
		||||
github.com/cloudflare/circl v1.2.0 h1:NheeISPSUcYftKlfrLuOo4T62FkmD4t4jviLfFFYaec=
 | 
			
		||||
github.com/cloudflare/circl v1.2.0/go.mod h1:Ch2UgYr6ti2KTtlejELlROl0YIYj7SLjAC8M+INXlMk=
 | 
			
		||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
 | 
			
		||||
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=
 | 
			
		||||
@@ -9,30 +27,117 @@ github.com/dlclark/regexp2 v1.7.0 h1:7lJfhqlPssTb1WQx4yvTHN0uElPEv52sbaECrAQxjAo
 | 
			
		||||
github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
 | 
			
		||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815 h1:bWDMxwH3px2JBh6AyO7hdCn/PkvCZXii8TGj7sbtEbQ=
 | 
			
		||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
 | 
			
		||||
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
 | 
			
		||||
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
 | 
			
		||||
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
 | 
			
		||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
 | 
			
		||||
github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0=
 | 
			
		||||
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/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E=
 | 
			
		||||
github.com/go-git/go-billy/v5 v5.2.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
 | 
			
		||||
github.com/go-git/go-billy/v5 v5.3.1 h1:CPiOUAzKtMRvolEKw+bG1PLRpT7D3LIs3/3ey4Aiu34=
 | 
			
		||||
github.com/go-git/go-billy/v5 v5.3.1/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
 | 
			
		||||
github.com/go-git/go-git-fixtures/v4 v4.2.1 h1:n9gGL1Ct/yIw+nfsfr8s4+sbhT+Ncu2SubfXjIWgci8=
 | 
			
		||||
github.com/go-git/go-git-fixtures/v4 v4.2.1/go.mod h1:K8zd3kDUAykwTdDCr+I0per6Y6vMiRR/nnVTBtavnB0=
 | 
			
		||||
github.com/go-git/go-git/v5 v5.4.2 h1:BXyZu9t0VkbiHtqrsvdq39UDhGJTl1h55VW6CSC4aY4=
 | 
			
		||||
github.com/go-git/go-git/v5 v5.4.2/go.mod h1:gQ1kArt6d+n+BGd+/B/I74HwRTLhth2+zti4ihgckDc=
 | 
			
		||||
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
 | 
			
		||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
 | 
			
		||||
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
 | 
			
		||||
github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk=
 | 
			
		||||
github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg=
 | 
			
		||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
 | 
			
		||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
 | 
			
		||||
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
 | 
			
		||||
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
 | 
			
		||||
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
 | 
			
		||||
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
 | 
			
		||||
github.com/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.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/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/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
 | 
			
		||||
github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A=
 | 
			
		||||
github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA=
 | 
			
		||||
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
 | 
			
		||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
 | 
			
		||||
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/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
 | 
			
		||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
 | 
			
		||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 | 
			
		||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 | 
			
		||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 | 
			
		||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 | 
			
		||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 | 
			
		||||
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/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.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 | 
			
		||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 | 
			
		||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 | 
			
		||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
 | 
			
		||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
 | 
			
		||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 | 
			
		||||
github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0=
 | 
			
		||||
github.com/xanzy/ssh-agent v0.3.2 h1:eKj4SX2Fe7mui28ZgnFW5fmTz1EIr7ugo5s6wDxdHBM=
 | 
			
		||||
github.com/xanzy/ssh-agent v0.3.2/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
 | 
			
		||||
golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 | 
			
		||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
 | 
			
		||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
 | 
			
		||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 | 
			
		||||
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 | 
			
		||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 | 
			
		||||
golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d h1:3qF+Z8Hkrw9sOhrFHti9TlB1Hkac1x+DNRkv0XQiFjo=
 | 
			
		||||
golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 | 
			
		||||
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-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 | 
			
		||||
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b h1:ZmngSVLe/wycRns9MKikG9OWIEjGcGAkacif7oYQaUY=
 | 
			
		||||
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
 | 
			
		||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 | 
			
		||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/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-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
			
		||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
			
		||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
			
		||||
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
			
		||||
golang.org/x/sys v0.0.0-20210324051608-47abb6519492/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-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
			
		||||
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
			
		||||
golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
			
		||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
			
		||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
			
		||||
golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64 h1:UiNENfZ8gDvpiWw7IpOMQ27spWmThO1RwwdQVbJahJM=
 | 
			
		||||
golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
			
		||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 | 
			
		||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
 | 
			
		||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 | 
			
		||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 | 
			
		||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
 | 
			
		||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 | 
			
		||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/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-20190902080502-41f04d3bba15/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/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
 | 
			
		||||
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0 h1:POO/ycCATvegFmVuPpQzZFJ+pGZeX22Ufu6fibxDVjU=
 | 
			
		||||
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg=
 | 
			
		||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 | 
			
		||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 | 
			
		||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 | 
			
		||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
 | 
			
		||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
 | 
			
		||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
 | 
			
		||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 | 
			
		||||
gopkg.in/yaml.v3 v3.0.0 h1:hjy8E9ON/egN1tAYqKb61G10WtihqetD4sz2H+8nIeA=
 | 
			
		||||
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 | 
			
		||||
 
 | 
			
		||||
@@ -1,24 +0,0 @@
 | 
			
		||||
package installer
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
	"os/exec"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const cloneURL = "https://github.com/cheat/cheatsheets.git"
 | 
			
		||||
 | 
			
		||||
// clone clones the community cheatsheets
 | 
			
		||||
func clone(path string) error {
 | 
			
		||||
 | 
			
		||||
	// perform the clone in a shell
 | 
			
		||||
	cmd := exec.Command("git", "clone", cloneURL, path)
 | 
			
		||||
	cmd.Stdout = os.Stdout
 | 
			
		||||
	cmd.Stderr = os.Stderr
 | 
			
		||||
	err := cmd.Run()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("failed to clone cheatsheets: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
@@ -7,6 +7,7 @@ import (
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/cheat/cheat/internal/config"
 | 
			
		||||
	"github.com/cheat/cheat/internal/repo"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Run runs the installer
 | 
			
		||||
@@ -45,7 +46,7 @@ func Run(configs string, confpath string) error {
 | 
			
		||||
	if yes {
 | 
			
		||||
		// clone the community cheatsheets
 | 
			
		||||
		fmt.Printf("Cloning community cheatsheets to %s.\n", community)
 | 
			
		||||
		if err := clone(community); err != nil {
 | 
			
		||||
		if err := repo.Clone(community); err != nil {
 | 
			
		||||
			return fmt.Errorf("failed to clone cheatsheets: %v", err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										25
									
								
								internal/repo/clone.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								internal/repo/clone.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
			
		||||
package repo
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
 | 
			
		||||
	"github.com/go-git/go-git/v5"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Clone clones the repo available at `url`
 | 
			
		||||
func Clone(url string) error {
 | 
			
		||||
 | 
			
		||||
	// clone the community cheatsheets
 | 
			
		||||
	_, err := git.PlainClone(url, false, &git.CloneOptions{
 | 
			
		||||
		URL:      "https://github.com/cheat/cheatsheets.git",
 | 
			
		||||
		Depth:    1,
 | 
			
		||||
		Progress: os.Stdout,
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("failed to clone cheatsheets: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										109
									
								
								internal/repo/gitdir.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								internal/repo/gitdir.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,109 @@
 | 
			
		||||
package repo
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// GitDir returns `true` if we are iterating over a directory contained within
 | 
			
		||||
// a repositories `.git` directory.
 | 
			
		||||
func GitDir(path string) (bool, error) {
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
		A bit of context is called for here, because this functionality has
 | 
			
		||||
		previously caused a number of tricky, subtle bugs.
 | 
			
		||||
 | 
			
		||||
		Fundamentally, here we are simply trying to avoid walking over the
 | 
			
		||||
		contents of the `.git` directory. Doing so potentially makes
 | 
			
		||||
		hundreds/thousands of needless syscalls, and can noticeably harm
 | 
			
		||||
		performance on machines with slow disks.
 | 
			
		||||
 | 
			
		||||
		The earliest effort to solve this problem involved simply returning
 | 
			
		||||
		`fs.SkipDir` when the cheatsheet file path began with `.`, signifying a
 | 
			
		||||
		hidden directory. This, however, caused two problems:
 | 
			
		||||
 | 
			
		||||
		1. The `.cheat` directory was ignored
 | 
			
		||||
		2. Cheatsheets installed by `brew` (which were by default installed to
 | 
			
		||||
		`~/.config/cheat`) were ignored
 | 
			
		||||
 | 
			
		||||
		See: https://github.com/cheat/cheat/issues/690
 | 
			
		||||
 | 
			
		||||
		To remedy this, the exclusion criteria were narrowed, and the search
 | 
			
		||||
		for a literal `.` was replaced with a search for a literal `.git`.
 | 
			
		||||
		This, however, broke user installations that stored cheatsheets in
 | 
			
		||||
		`git` submodules, because such an installation would contain a `.git`
 | 
			
		||||
		file that pointed to the upstream repository.
 | 
			
		||||
 | 
			
		||||
		See: https://github.com/cheat/cheat/issues/694
 | 
			
		||||
 | 
			
		||||
		The next attempt at solving this was to search for a `.git` literal
 | 
			
		||||
		string in the cheatsheet file path. If a match was not found, we would
 | 
			
		||||
		continue to walk the directory, as before.
 | 
			
		||||
 | 
			
		||||
		If a match *was* found, we determined whether `.git` referred to a file
 | 
			
		||||
		or directory, and would only stop walking the path in the latter case.
 | 
			
		||||
 | 
			
		||||
		This, however, caused crashes if a cheatpath contained a `.gitignore`
 | 
			
		||||
		file. (Presumably, a crash would likewise occur on the presence of
 | 
			
		||||
		`.gitattributes`, `.gitmodules`, etc.)
 | 
			
		||||
 | 
			
		||||
		See: https://github.com/cheat/cheat/issues/699
 | 
			
		||||
 | 
			
		||||
		Accounting for all of the above (hopefully?), the current solution is
 | 
			
		||||
		not to search for `.git`, but `.git/` (including the directory
 | 
			
		||||
		separator), and then only ceasing to walk the directory on a match.
 | 
			
		||||
 | 
			
		||||
		To summarize, this code must account for the following possibilities:
 | 
			
		||||
 | 
			
		||||
		1. A cheatpath is not a repository
 | 
			
		||||
		2. A cheatpath is a repository
 | 
			
		||||
		3. A cheatpath is a repository, and contains a `.git*` file
 | 
			
		||||
		4. A cheatpath is a submodule
 | 
			
		||||
 | 
			
		||||
		Care must be taken to support the above on both Unix and Windows
 | 
			
		||||
		systems, which have different directory separators and line-endings.
 | 
			
		||||
 | 
			
		||||
		There is a lot of nuance to all of this, and it would be worthwhile to
 | 
			
		||||
		do two things to stop writing bugs here:
 | 
			
		||||
 | 
			
		||||
		1. Build integration tests around all of this
 | 
			
		||||
		2. Discard string-matching solutions entirely, and use `go-git` instead
 | 
			
		||||
 | 
			
		||||
		NB: A reasonable smoke-test for ensuring that skipping is being applied
 | 
			
		||||
		correctly is to run the following command:
 | 
			
		||||
 | 
			
		||||
		    make && strace ./dist/cheat -l | wc -l
 | 
			
		||||
 | 
			
		||||
		That check should be run twice: once normally, and once after
 | 
			
		||||
		commenting out the "skip" check in `sheets.Load`.
 | 
			
		||||
 | 
			
		||||
		The specific line counts don't matter; what matters is that the number
 | 
			
		||||
		of syscalls should be significantly lower with the skip check enabled.
 | 
			
		||||
	*/
 | 
			
		||||
 | 
			
		||||
	// determine if the literal string `.git` appears within `path`
 | 
			
		||||
	pos := strings.Index(path, fmt.Sprintf(".git%s", string(os.PathSeparator)))
 | 
			
		||||
 | 
			
		||||
	// if it does not, we know for certain that we are not within a `.git`
 | 
			
		||||
	// directory.
 | 
			
		||||
	if pos == -1 {
 | 
			
		||||
		return false, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// If `path` does contain the string `.git`, we need to determine if we're
 | 
			
		||||
	// inside of a `.git` directory, or if `path` points to a cheatsheet that's
 | 
			
		||||
	// stored within a `git` submodule.
 | 
			
		||||
	//
 | 
			
		||||
	// See: https://github.com/cheat/cheat/issues/694
 | 
			
		||||
 | 
			
		||||
	// truncate `path` to the occurrence of `.git`
 | 
			
		||||
	f, err := os.Stat(path[:pos+5])
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false, fmt.Errorf("failed to stat path %s: %v", path, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// return true or false depending on whether the truncated path is a
 | 
			
		||||
	// directory
 | 
			
		||||
	return f.Mode().IsDir(), nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1
									
								
								internal/repo/update.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								internal/repo/update.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
package repo
 | 
			
		||||
@@ -1,72 +0,0 @@
 | 
			
		||||
package sheets
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// isGitDir returns `true` if `path` is within a `.git` directory, or `false`
 | 
			
		||||
// otherwise
 | 
			
		||||
func isGitDir(path string) (bool, error) {
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
		A bit of context is called for here, because this functionality has
 | 
			
		||||
		previously caused a number of tricky, subtle bugs.
 | 
			
		||||
 | 
			
		||||
		Fundamentally, here we are simply trying to avoid walking over the
 | 
			
		||||
		contents of the `.git` directory. Doing so potentially makes
 | 
			
		||||
		hundreds/thousands of needless syscalls, and can noticeably harm
 | 
			
		||||
		performance on machines with slow disks.
 | 
			
		||||
 | 
			
		||||
		The earliest effort to solve this problem involved simply returning
 | 
			
		||||
		`fs.SkipDir` when the cheatsheet file path began with `.`, signifying a
 | 
			
		||||
		hidden directory. This, however, caused two problems:
 | 
			
		||||
 | 
			
		||||
		1. The `.cheat` directory was ignored
 | 
			
		||||
		2. Cheatsheets installed by `brew` (which were by default installed to
 | 
			
		||||
		`~/.config/cheat`) were ignored
 | 
			
		||||
 | 
			
		||||
		See: https://github.com/cheat/cheat/issues/690
 | 
			
		||||
 | 
			
		||||
		To remedy this, the exclusion criteria were narrowed, and the search
 | 
			
		||||
		for a literal `.` was replaced with a search for a literal `.git`.
 | 
			
		||||
		This, however, broke user installations that stored cheatsheets in
 | 
			
		||||
		`git` submodules, because such an installation would contain a `.git`
 | 
			
		||||
		file that pointed to the upstream repository.
 | 
			
		||||
 | 
			
		||||
		See: https://github.com/cheat/cheat/issues/694
 | 
			
		||||
 | 
			
		||||
		Accounting for all of the above, we are now searching for the presence
 | 
			
		||||
		of a `.git` literal string in the cheatsheet file path. If it is not
 | 
			
		||||
		found, we continue to walk the directory, as before.
 | 
			
		||||
 | 
			
		||||
		If it *is* found, we determine if `.git` refers to a file or directory,
 | 
			
		||||
		and only stop walking the path in the latter case.
 | 
			
		||||
	*/
 | 
			
		||||
 | 
			
		||||
	// determine if the literal string `.git` appears within `path`
 | 
			
		||||
	pos := strings.Index(path, ".git")
 | 
			
		||||
 | 
			
		||||
	// if it does not, we know for certain that we are not within a `.git`
 | 
			
		||||
	// directory.
 | 
			
		||||
	if pos == -1 {
 | 
			
		||||
		return false, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// If `path` does contain the string `.git`, we need to determine if we're
 | 
			
		||||
	// inside of a `.git` directory, or if `path` points to a cheatsheet that's
 | 
			
		||||
	// stored within a `git` submodule.
 | 
			
		||||
	//
 | 
			
		||||
	// See: https://github.com/cheat/cheat/issues/694
 | 
			
		||||
 | 
			
		||||
	// truncate `path` to the occurrence of `.git`
 | 
			
		||||
	f, err := os.Stat(path[:pos+4])
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false, fmt.Errorf("failed to stat path %s: %v", path, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// return true or false depending on whether the truncated path is a
 | 
			
		||||
	// directory
 | 
			
		||||
	return f.Mode().IsDir(), nil
 | 
			
		||||
}
 | 
			
		||||
@@ -8,6 +8,7 @@ import (
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	cp "github.com/cheat/cheat/internal/cheatpath"
 | 
			
		||||
	"github.com/cheat/cheat/internal/repo"
 | 
			
		||||
	"github.com/cheat/cheat/internal/sheet"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@@ -52,7 +53,7 @@ func Load(cheatpaths []cp.Cheatpath) ([]map[string]sheet.Sheet, error) {
 | 
			
		||||
				// Don't walk the `.git` directory. Doing so creates
 | 
			
		||||
				// hundreds/thousands of needless syscalls and could
 | 
			
		||||
				// potentially harm performance on machines with slow disks.
 | 
			
		||||
				skip, err := isGitDir(path)
 | 
			
		||||
				skip, err := repo.GitDir(path)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return fmt.Errorf("failed to identify .git directory: %v", err)
 | 
			
		||||
				}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1
									
								
								vendor/github.com/Microsoft/go-winio/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								vendor/github.com/Microsoft/go-winio/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
*.exe
 | 
			
		||||
							
								
								
									
										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
 | 
			
		||||
							
								
								
									
										22
									
								
								vendor/github.com/Microsoft/go-winio/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								vendor/github.com/Microsoft/go-winio/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
			
		||||
The MIT License (MIT)
 | 
			
		||||
 | 
			
		||||
Copyright (c) 2015 Microsoft
 | 
			
		||||
 | 
			
		||||
Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
in the Software without restriction, including without limitation the rights
 | 
			
		||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
furnished to do so, subject to the following conditions:
 | 
			
		||||
 | 
			
		||||
The above copyright notice and this permission notice shall be included in all
 | 
			
		||||
copies or substantial portions of the Software.
 | 
			
		||||
 | 
			
		||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
			
		||||
SOFTWARE.
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										37
									
								
								vendor/github.com/Microsoft/go-winio/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								vendor/github.com/Microsoft/go-winio/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
			
		||||
# go-winio [](https://github.com/microsoft/go-winio/actions/workflows/ci.yml)
 | 
			
		||||
 | 
			
		||||
This repository contains utilities for efficiently performing Win32 IO operations in
 | 
			
		||||
Go. Currently, this is focused on accessing named pipes and other file handles, and
 | 
			
		||||
for using named pipes as a net transport.
 | 
			
		||||
 | 
			
		||||
This code relies on IO completion ports to avoid blocking IO on system threads, allowing Go
 | 
			
		||||
to reuse the thread to schedule another goroutine. This limits support to Windows Vista and
 | 
			
		||||
newer operating systems. This is similar to the implementation of network sockets in Go's net
 | 
			
		||||
package.
 | 
			
		||||
 | 
			
		||||
Please see the LICENSE file for licensing information.
 | 
			
		||||
 | 
			
		||||
## Contributing
 | 
			
		||||
 | 
			
		||||
This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA)
 | 
			
		||||
declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://cla.microsoft.com.
 | 
			
		||||
 | 
			
		||||
When you submit a pull request, a CLA-bot will automatically determine whether you need to provide a CLA and decorate the PR
 | 
			
		||||
appropriately (e.g., label, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA.
 | 
			
		||||
 | 
			
		||||
We also require that contributors sign their commits using git commit -s or git commit --signoff to certify they either authored the work themselves
 | 
			
		||||
or otherwise have permission to use it in this project. Please see https://developercertificate.org/ for more info, as well as to make sure that you can
 | 
			
		||||
attest to the rules listed. Our CI uses the DCO Github app to ensure that all commits in a given PR are signed-off.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## Code of Conduct
 | 
			
		||||
 | 
			
		||||
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
 | 
			
		||||
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
 | 
			
		||||
contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## Special Thanks
 | 
			
		||||
Thanks to natefinch for the inspiration for this library. See https://github.com/natefinch/npipe
 | 
			
		||||
for another named pipe implementation.
 | 
			
		||||
							
								
								
									
										280
									
								
								vendor/github.com/Microsoft/go-winio/backup.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										280
									
								
								vendor/github.com/Microsoft/go-winio/backup.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,280 @@
 | 
			
		||||
// +build windows
 | 
			
		||||
 | 
			
		||||
package winio
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/binary"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"os"
 | 
			
		||||
	"runtime"
 | 
			
		||||
	"syscall"
 | 
			
		||||
	"unicode/utf16"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
//sys backupRead(h syscall.Handle, b []byte, bytesRead *uint32, abort bool, processSecurity bool, context *uintptr) (err error) = BackupRead
 | 
			
		||||
//sys backupWrite(h syscall.Handle, b []byte, bytesWritten *uint32, abort bool, processSecurity bool, context *uintptr) (err error) = BackupWrite
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	BackupData = uint32(iota + 1)
 | 
			
		||||
	BackupEaData
 | 
			
		||||
	BackupSecurity
 | 
			
		||||
	BackupAlternateData
 | 
			
		||||
	BackupLink
 | 
			
		||||
	BackupPropertyData
 | 
			
		||||
	BackupObjectId
 | 
			
		||||
	BackupReparseData
 | 
			
		||||
	BackupSparseBlock
 | 
			
		||||
	BackupTxfsData
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	StreamSparseAttributes = uint32(8)
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	WRITE_DAC              = 0x40000
 | 
			
		||||
	WRITE_OWNER            = 0x80000
 | 
			
		||||
	ACCESS_SYSTEM_SECURITY = 0x1000000
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// BackupHeader represents a backup stream of a file.
 | 
			
		||||
type BackupHeader struct {
 | 
			
		||||
	Id         uint32 // The backup stream ID
 | 
			
		||||
	Attributes uint32 // Stream attributes
 | 
			
		||||
	Size       int64  // The size of the stream in bytes
 | 
			
		||||
	Name       string // The name of the stream (for BackupAlternateData only).
 | 
			
		||||
	Offset     int64  // The offset of the stream in the file (for BackupSparseBlock only).
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type win32StreamId struct {
 | 
			
		||||
	StreamId   uint32
 | 
			
		||||
	Attributes uint32
 | 
			
		||||
	Size       uint64
 | 
			
		||||
	NameSize   uint32
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// BackupStreamReader reads from a stream produced by the BackupRead Win32 API and produces a series
 | 
			
		||||
// of BackupHeader values.
 | 
			
		||||
type BackupStreamReader struct {
 | 
			
		||||
	r         io.Reader
 | 
			
		||||
	bytesLeft int64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewBackupStreamReader produces a BackupStreamReader from any io.Reader.
 | 
			
		||||
func NewBackupStreamReader(r io.Reader) *BackupStreamReader {
 | 
			
		||||
	return &BackupStreamReader{r, 0}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Next returns the next backup stream and prepares for calls to Read(). It skips the remainder of the current stream if
 | 
			
		||||
// it was not completely read.
 | 
			
		||||
func (r *BackupStreamReader) Next() (*BackupHeader, error) {
 | 
			
		||||
	if r.bytesLeft > 0 {
 | 
			
		||||
		if s, ok := r.r.(io.Seeker); ok {
 | 
			
		||||
			// Make sure Seek on io.SeekCurrent sometimes succeeds
 | 
			
		||||
			// before trying the actual seek.
 | 
			
		||||
			if _, err := s.Seek(0, io.SeekCurrent); err == nil {
 | 
			
		||||
				if _, err = s.Seek(r.bytesLeft, io.SeekCurrent); err != nil {
 | 
			
		||||
					return nil, err
 | 
			
		||||
				}
 | 
			
		||||
				r.bytesLeft = 0
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if _, err := io.Copy(ioutil.Discard, r); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	var wsi win32StreamId
 | 
			
		||||
	if err := binary.Read(r.r, binary.LittleEndian, &wsi); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	hdr := &BackupHeader{
 | 
			
		||||
		Id:         wsi.StreamId,
 | 
			
		||||
		Attributes: wsi.Attributes,
 | 
			
		||||
		Size:       int64(wsi.Size),
 | 
			
		||||
	}
 | 
			
		||||
	if wsi.NameSize != 0 {
 | 
			
		||||
		name := make([]uint16, int(wsi.NameSize/2))
 | 
			
		||||
		if err := binary.Read(r.r, binary.LittleEndian, name); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		hdr.Name = syscall.UTF16ToString(name)
 | 
			
		||||
	}
 | 
			
		||||
	if wsi.StreamId == BackupSparseBlock {
 | 
			
		||||
		if err := binary.Read(r.r, binary.LittleEndian, &hdr.Offset); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		hdr.Size -= 8
 | 
			
		||||
	}
 | 
			
		||||
	r.bytesLeft = hdr.Size
 | 
			
		||||
	return hdr, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Read reads from the current backup stream.
 | 
			
		||||
func (r *BackupStreamReader) Read(b []byte) (int, error) {
 | 
			
		||||
	if r.bytesLeft == 0 {
 | 
			
		||||
		return 0, io.EOF
 | 
			
		||||
	}
 | 
			
		||||
	if int64(len(b)) > r.bytesLeft {
 | 
			
		||||
		b = b[:r.bytesLeft]
 | 
			
		||||
	}
 | 
			
		||||
	n, err := r.r.Read(b)
 | 
			
		||||
	r.bytesLeft -= int64(n)
 | 
			
		||||
	if err == io.EOF {
 | 
			
		||||
		err = io.ErrUnexpectedEOF
 | 
			
		||||
	} else if r.bytesLeft == 0 && err == nil {
 | 
			
		||||
		err = io.EOF
 | 
			
		||||
	}
 | 
			
		||||
	return n, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// BackupStreamWriter writes a stream compatible with the BackupWrite Win32 API.
 | 
			
		||||
type BackupStreamWriter struct {
 | 
			
		||||
	w         io.Writer
 | 
			
		||||
	bytesLeft int64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewBackupStreamWriter produces a BackupStreamWriter on top of an io.Writer.
 | 
			
		||||
func NewBackupStreamWriter(w io.Writer) *BackupStreamWriter {
 | 
			
		||||
	return &BackupStreamWriter{w, 0}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WriteHeader writes the next backup stream header and prepares for calls to Write().
 | 
			
		||||
func (w *BackupStreamWriter) WriteHeader(hdr *BackupHeader) error {
 | 
			
		||||
	if w.bytesLeft != 0 {
 | 
			
		||||
		return fmt.Errorf("missing %d bytes", w.bytesLeft)
 | 
			
		||||
	}
 | 
			
		||||
	name := utf16.Encode([]rune(hdr.Name))
 | 
			
		||||
	wsi := win32StreamId{
 | 
			
		||||
		StreamId:   hdr.Id,
 | 
			
		||||
		Attributes: hdr.Attributes,
 | 
			
		||||
		Size:       uint64(hdr.Size),
 | 
			
		||||
		NameSize:   uint32(len(name) * 2),
 | 
			
		||||
	}
 | 
			
		||||
	if hdr.Id == BackupSparseBlock {
 | 
			
		||||
		// Include space for the int64 block offset
 | 
			
		||||
		wsi.Size += 8
 | 
			
		||||
	}
 | 
			
		||||
	if err := binary.Write(w.w, binary.LittleEndian, &wsi); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if len(name) != 0 {
 | 
			
		||||
		if err := binary.Write(w.w, binary.LittleEndian, name); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if hdr.Id == BackupSparseBlock {
 | 
			
		||||
		if err := binary.Write(w.w, binary.LittleEndian, hdr.Offset); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	w.bytesLeft = hdr.Size
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Write writes to the current backup stream.
 | 
			
		||||
func (w *BackupStreamWriter) Write(b []byte) (int, error) {
 | 
			
		||||
	if w.bytesLeft < int64(len(b)) {
 | 
			
		||||
		return 0, fmt.Errorf("too many bytes by %d", int64(len(b))-w.bytesLeft)
 | 
			
		||||
	}
 | 
			
		||||
	n, err := w.w.Write(b)
 | 
			
		||||
	w.bytesLeft -= int64(n)
 | 
			
		||||
	return n, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// BackupFileReader provides an io.ReadCloser interface on top of the BackupRead Win32 API.
 | 
			
		||||
type BackupFileReader struct {
 | 
			
		||||
	f               *os.File
 | 
			
		||||
	includeSecurity bool
 | 
			
		||||
	ctx             uintptr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewBackupFileReader returns a new BackupFileReader from a file handle. If includeSecurity is true,
 | 
			
		||||
// Read will attempt to read the security descriptor of the file.
 | 
			
		||||
func NewBackupFileReader(f *os.File, includeSecurity bool) *BackupFileReader {
 | 
			
		||||
	r := &BackupFileReader{f, includeSecurity, 0}
 | 
			
		||||
	return r
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Read reads a backup stream from the file by calling the Win32 API BackupRead().
 | 
			
		||||
func (r *BackupFileReader) Read(b []byte) (int, error) {
 | 
			
		||||
	var bytesRead uint32
 | 
			
		||||
	err := backupRead(syscall.Handle(r.f.Fd()), b, &bytesRead, false, r.includeSecurity, &r.ctx)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, &os.PathError{"BackupRead", r.f.Name(), err}
 | 
			
		||||
	}
 | 
			
		||||
	runtime.KeepAlive(r.f)
 | 
			
		||||
	if bytesRead == 0 {
 | 
			
		||||
		return 0, io.EOF
 | 
			
		||||
	}
 | 
			
		||||
	return int(bytesRead), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Close frees Win32 resources associated with the BackupFileReader. It does not close
 | 
			
		||||
// the underlying file.
 | 
			
		||||
func (r *BackupFileReader) Close() error {
 | 
			
		||||
	if r.ctx != 0 {
 | 
			
		||||
		backupRead(syscall.Handle(r.f.Fd()), nil, nil, true, false, &r.ctx)
 | 
			
		||||
		runtime.KeepAlive(r.f)
 | 
			
		||||
		r.ctx = 0
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// BackupFileWriter provides an io.WriteCloser interface on top of the BackupWrite Win32 API.
 | 
			
		||||
type BackupFileWriter struct {
 | 
			
		||||
	f               *os.File
 | 
			
		||||
	includeSecurity bool
 | 
			
		||||
	ctx             uintptr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewBackupFileWriter returns a new BackupFileWriter from a file handle. If includeSecurity is true,
 | 
			
		||||
// Write() will attempt to restore the security descriptor from the stream.
 | 
			
		||||
func NewBackupFileWriter(f *os.File, includeSecurity bool) *BackupFileWriter {
 | 
			
		||||
	w := &BackupFileWriter{f, includeSecurity, 0}
 | 
			
		||||
	return w
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Write restores a portion of the file using the provided backup stream.
 | 
			
		||||
func (w *BackupFileWriter) Write(b []byte) (int, error) {
 | 
			
		||||
	var bytesWritten uint32
 | 
			
		||||
	err := backupWrite(syscall.Handle(w.f.Fd()), b, &bytesWritten, false, w.includeSecurity, &w.ctx)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, &os.PathError{"BackupWrite", w.f.Name(), err}
 | 
			
		||||
	}
 | 
			
		||||
	runtime.KeepAlive(w.f)
 | 
			
		||||
	if int(bytesWritten) != len(b) {
 | 
			
		||||
		return int(bytesWritten), errors.New("not all bytes could be written")
 | 
			
		||||
	}
 | 
			
		||||
	return len(b), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Close frees Win32 resources associated with the BackupFileWriter. It does not
 | 
			
		||||
// close the underlying file.
 | 
			
		||||
func (w *BackupFileWriter) Close() error {
 | 
			
		||||
	if w.ctx != 0 {
 | 
			
		||||
		backupWrite(syscall.Handle(w.f.Fd()), nil, nil, true, false, &w.ctx)
 | 
			
		||||
		runtime.KeepAlive(w.f)
 | 
			
		||||
		w.ctx = 0
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// OpenForBackup opens a file or directory, potentially skipping access checks if the backup
 | 
			
		||||
// or restore privileges have been acquired.
 | 
			
		||||
//
 | 
			
		||||
// If the file opened was a directory, it cannot be used with Readdir().
 | 
			
		||||
func OpenForBackup(path string, access uint32, share uint32, createmode uint32) (*os.File, error) {
 | 
			
		||||
	winPath, err := syscall.UTF16FromString(path)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	h, err := syscall.CreateFile(&winPath[0], access, share, nil, createmode, syscall.FILE_FLAG_BACKUP_SEMANTICS|syscall.FILE_FLAG_OPEN_REPARSE_POINT, 0)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		err = &os.PathError{Op: "open", Path: path, Err: err}
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return os.NewFile(uintptr(h), path), nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										137
									
								
								vendor/github.com/Microsoft/go-winio/ea.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										137
									
								
								vendor/github.com/Microsoft/go-winio/ea.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,137 @@
 | 
			
		||||
package winio
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"encoding/binary"
 | 
			
		||||
	"errors"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type fileFullEaInformation struct {
 | 
			
		||||
	NextEntryOffset uint32
 | 
			
		||||
	Flags           uint8
 | 
			
		||||
	NameLength      uint8
 | 
			
		||||
	ValueLength     uint16
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	fileFullEaInformationSize = binary.Size(&fileFullEaInformation{})
 | 
			
		||||
 | 
			
		||||
	errInvalidEaBuffer = errors.New("invalid extended attribute buffer")
 | 
			
		||||
	errEaNameTooLarge  = errors.New("extended attribute name too large")
 | 
			
		||||
	errEaValueTooLarge = errors.New("extended attribute value too large")
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ExtendedAttribute represents a single Windows EA.
 | 
			
		||||
type ExtendedAttribute struct {
 | 
			
		||||
	Name  string
 | 
			
		||||
	Value []byte
 | 
			
		||||
	Flags uint8
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func parseEa(b []byte) (ea ExtendedAttribute, nb []byte, err error) {
 | 
			
		||||
	var info fileFullEaInformation
 | 
			
		||||
	err = binary.Read(bytes.NewReader(b), binary.LittleEndian, &info)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		err = errInvalidEaBuffer
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	nameOffset := fileFullEaInformationSize
 | 
			
		||||
	nameLen := int(info.NameLength)
 | 
			
		||||
	valueOffset := nameOffset + int(info.NameLength) + 1
 | 
			
		||||
	valueLen := int(info.ValueLength)
 | 
			
		||||
	nextOffset := int(info.NextEntryOffset)
 | 
			
		||||
	if valueLen+valueOffset > len(b) || nextOffset < 0 || nextOffset > len(b) {
 | 
			
		||||
		err = errInvalidEaBuffer
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ea.Name = string(b[nameOffset : nameOffset+nameLen])
 | 
			
		||||
	ea.Value = b[valueOffset : valueOffset+valueLen]
 | 
			
		||||
	ea.Flags = info.Flags
 | 
			
		||||
	if info.NextEntryOffset != 0 {
 | 
			
		||||
		nb = b[info.NextEntryOffset:]
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DecodeExtendedAttributes decodes a list of EAs from a FILE_FULL_EA_INFORMATION
 | 
			
		||||
// buffer retrieved from BackupRead, ZwQueryEaFile, etc.
 | 
			
		||||
func DecodeExtendedAttributes(b []byte) (eas []ExtendedAttribute, err error) {
 | 
			
		||||
	for len(b) != 0 {
 | 
			
		||||
		ea, nb, err := parseEa(b)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		eas = append(eas, ea)
 | 
			
		||||
		b = nb
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func writeEa(buf *bytes.Buffer, ea *ExtendedAttribute, last bool) error {
 | 
			
		||||
	if int(uint8(len(ea.Name))) != len(ea.Name) {
 | 
			
		||||
		return errEaNameTooLarge
 | 
			
		||||
	}
 | 
			
		||||
	if int(uint16(len(ea.Value))) != len(ea.Value) {
 | 
			
		||||
		return errEaValueTooLarge
 | 
			
		||||
	}
 | 
			
		||||
	entrySize := uint32(fileFullEaInformationSize + len(ea.Name) + 1 + len(ea.Value))
 | 
			
		||||
	withPadding := (entrySize + 3) &^ 3
 | 
			
		||||
	nextOffset := uint32(0)
 | 
			
		||||
	if !last {
 | 
			
		||||
		nextOffset = withPadding
 | 
			
		||||
	}
 | 
			
		||||
	info := fileFullEaInformation{
 | 
			
		||||
		NextEntryOffset: nextOffset,
 | 
			
		||||
		Flags:           ea.Flags,
 | 
			
		||||
		NameLength:      uint8(len(ea.Name)),
 | 
			
		||||
		ValueLength:     uint16(len(ea.Value)),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err := binary.Write(buf, binary.LittleEndian, &info)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, err = buf.Write([]byte(ea.Name))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = buf.WriteByte(0)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, err = buf.Write(ea.Value)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, err = buf.Write([]byte{0, 0, 0}[0 : withPadding-entrySize])
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// EncodeExtendedAttributes encodes a list of EAs into a FILE_FULL_EA_INFORMATION
 | 
			
		||||
// buffer for use with BackupWrite, ZwSetEaFile, etc.
 | 
			
		||||
func EncodeExtendedAttributes(eas []ExtendedAttribute) ([]byte, error) {
 | 
			
		||||
	var buf bytes.Buffer
 | 
			
		||||
	for i := range eas {
 | 
			
		||||
		last := false
 | 
			
		||||
		if i == len(eas)-1 {
 | 
			
		||||
			last = true
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		err := writeEa(&buf, &eas[i], last)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return buf.Bytes(), nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										329
									
								
								vendor/github.com/Microsoft/go-winio/file.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										329
									
								
								vendor/github.com/Microsoft/go-winio/file.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,329 @@
 | 
			
		||||
//go:build windows
 | 
			
		||||
// +build windows
 | 
			
		||||
 | 
			
		||||
package winio
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"io"
 | 
			
		||||
	"runtime"
 | 
			
		||||
	"sync"
 | 
			
		||||
	"sync/atomic"
 | 
			
		||||
	"syscall"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
//sys cancelIoEx(file syscall.Handle, o *syscall.Overlapped) (err error) = CancelIoEx
 | 
			
		||||
//sys createIoCompletionPort(file syscall.Handle, port syscall.Handle, key uintptr, threadCount uint32) (newport syscall.Handle, err error) = CreateIoCompletionPort
 | 
			
		||||
//sys getQueuedCompletionStatus(port syscall.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) = GetQueuedCompletionStatus
 | 
			
		||||
//sys setFileCompletionNotificationModes(h syscall.Handle, flags uint8) (err error) = SetFileCompletionNotificationModes
 | 
			
		||||
//sys wsaGetOverlappedResult(h syscall.Handle, o *syscall.Overlapped, bytes *uint32, wait bool, flags *uint32) (err error) = ws2_32.WSAGetOverlappedResult
 | 
			
		||||
 | 
			
		||||
type atomicBool int32
 | 
			
		||||
 | 
			
		||||
func (b *atomicBool) isSet() bool { return atomic.LoadInt32((*int32)(b)) != 0 }
 | 
			
		||||
func (b *atomicBool) setFalse()   { atomic.StoreInt32((*int32)(b), 0) }
 | 
			
		||||
func (b *atomicBool) setTrue()    { atomic.StoreInt32((*int32)(b), 1) }
 | 
			
		||||
func (b *atomicBool) swap(new bool) bool {
 | 
			
		||||
	var newInt int32
 | 
			
		||||
	if new {
 | 
			
		||||
		newInt = 1
 | 
			
		||||
	}
 | 
			
		||||
	return atomic.SwapInt32((*int32)(b), newInt) == 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	cFILE_SKIP_COMPLETION_PORT_ON_SUCCESS = 1
 | 
			
		||||
	cFILE_SKIP_SET_EVENT_ON_HANDLE        = 2
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	ErrFileClosed = errors.New("file has already been closed")
 | 
			
		||||
	ErrTimeout    = &timeoutError{}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type timeoutError struct{}
 | 
			
		||||
 | 
			
		||||
func (e *timeoutError) Error() string   { return "i/o timeout" }
 | 
			
		||||
func (e *timeoutError) Timeout() bool   { return true }
 | 
			
		||||
func (e *timeoutError) Temporary() bool { return true }
 | 
			
		||||
 | 
			
		||||
type timeoutChan chan struct{}
 | 
			
		||||
 | 
			
		||||
var ioInitOnce sync.Once
 | 
			
		||||
var ioCompletionPort syscall.Handle
 | 
			
		||||
 | 
			
		||||
// ioResult contains the result of an asynchronous IO operation
 | 
			
		||||
type ioResult struct {
 | 
			
		||||
	bytes uint32
 | 
			
		||||
	err   error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ioOperation represents an outstanding asynchronous Win32 IO
 | 
			
		||||
type ioOperation struct {
 | 
			
		||||
	o  syscall.Overlapped
 | 
			
		||||
	ch chan ioResult
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func initIo() {
 | 
			
		||||
	h, err := createIoCompletionPort(syscall.InvalidHandle, 0, 0, 0xffffffff)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
	ioCompletionPort = h
 | 
			
		||||
	go ioCompletionProcessor(h)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// win32File implements Reader, Writer, and Closer on a Win32 handle without blocking in a syscall.
 | 
			
		||||
// It takes ownership of this handle and will close it if it is garbage collected.
 | 
			
		||||
type win32File struct {
 | 
			
		||||
	handle        syscall.Handle
 | 
			
		||||
	wg            sync.WaitGroup
 | 
			
		||||
	wgLock        sync.RWMutex
 | 
			
		||||
	closing       atomicBool
 | 
			
		||||
	socket        bool
 | 
			
		||||
	readDeadline  deadlineHandler
 | 
			
		||||
	writeDeadline deadlineHandler
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type deadlineHandler struct {
 | 
			
		||||
	setLock     sync.Mutex
 | 
			
		||||
	channel     timeoutChan
 | 
			
		||||
	channelLock sync.RWMutex
 | 
			
		||||
	timer       *time.Timer
 | 
			
		||||
	timedout    atomicBool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// makeWin32File makes a new win32File from an existing file handle
 | 
			
		||||
func makeWin32File(h syscall.Handle) (*win32File, error) {
 | 
			
		||||
	f := &win32File{handle: h}
 | 
			
		||||
	ioInitOnce.Do(initIo)
 | 
			
		||||
	_, err := createIoCompletionPort(h, ioCompletionPort, 0, 0xffffffff)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	err = setFileCompletionNotificationModes(h, cFILE_SKIP_COMPLETION_PORT_ON_SUCCESS|cFILE_SKIP_SET_EVENT_ON_HANDLE)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	f.readDeadline.channel = make(timeoutChan)
 | 
			
		||||
	f.writeDeadline.channel = make(timeoutChan)
 | 
			
		||||
	return f, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func MakeOpenFile(h syscall.Handle) (io.ReadWriteCloser, error) {
 | 
			
		||||
	// If we return the result of makeWin32File directly, it can result in an
 | 
			
		||||
	// interface-wrapped nil, rather than a nil interface value.
 | 
			
		||||
	f, err := makeWin32File(h)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return f, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// closeHandle closes the resources associated with a Win32 handle
 | 
			
		||||
func (f *win32File) closeHandle() {
 | 
			
		||||
	f.wgLock.Lock()
 | 
			
		||||
	// Atomically set that we are closing, releasing the resources only once.
 | 
			
		||||
	if !f.closing.swap(true) {
 | 
			
		||||
		f.wgLock.Unlock()
 | 
			
		||||
		// cancel all IO and wait for it to complete
 | 
			
		||||
		cancelIoEx(f.handle, nil)
 | 
			
		||||
		f.wg.Wait()
 | 
			
		||||
		// at this point, no new IO can start
 | 
			
		||||
		syscall.Close(f.handle)
 | 
			
		||||
		f.handle = 0
 | 
			
		||||
	} else {
 | 
			
		||||
		f.wgLock.Unlock()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Close closes a win32File.
 | 
			
		||||
func (f *win32File) Close() error {
 | 
			
		||||
	f.closeHandle()
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsClosed checks if the file has been closed
 | 
			
		||||
func (f *win32File) IsClosed() bool {
 | 
			
		||||
	return f.closing.isSet()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// prepareIo prepares for a new IO operation.
 | 
			
		||||
// The caller must call f.wg.Done() when the IO is finished, prior to Close() returning.
 | 
			
		||||
func (f *win32File) prepareIo() (*ioOperation, error) {
 | 
			
		||||
	f.wgLock.RLock()
 | 
			
		||||
	if f.closing.isSet() {
 | 
			
		||||
		f.wgLock.RUnlock()
 | 
			
		||||
		return nil, ErrFileClosed
 | 
			
		||||
	}
 | 
			
		||||
	f.wg.Add(1)
 | 
			
		||||
	f.wgLock.RUnlock()
 | 
			
		||||
	c := &ioOperation{}
 | 
			
		||||
	c.ch = make(chan ioResult)
 | 
			
		||||
	return c, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ioCompletionProcessor processes completed async IOs forever
 | 
			
		||||
func ioCompletionProcessor(h syscall.Handle) {
 | 
			
		||||
	for {
 | 
			
		||||
		var bytes uint32
 | 
			
		||||
		var key uintptr
 | 
			
		||||
		var op *ioOperation
 | 
			
		||||
		err := getQueuedCompletionStatus(h, &bytes, &key, &op, syscall.INFINITE)
 | 
			
		||||
		if op == nil {
 | 
			
		||||
			panic(err)
 | 
			
		||||
		}
 | 
			
		||||
		op.ch <- ioResult{bytes, err}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// asyncIo processes the return value from ReadFile or WriteFile, blocking until
 | 
			
		||||
// the operation has actually completed.
 | 
			
		||||
func (f *win32File) asyncIo(c *ioOperation, d *deadlineHandler, bytes uint32, err error) (int, error) {
 | 
			
		||||
	if err != syscall.ERROR_IO_PENDING {
 | 
			
		||||
		return int(bytes), err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if f.closing.isSet() {
 | 
			
		||||
		cancelIoEx(f.handle, &c.o)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var timeout timeoutChan
 | 
			
		||||
	if d != nil {
 | 
			
		||||
		d.channelLock.Lock()
 | 
			
		||||
		timeout = d.channel
 | 
			
		||||
		d.channelLock.Unlock()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var r ioResult
 | 
			
		||||
	select {
 | 
			
		||||
	case r = <-c.ch:
 | 
			
		||||
		err = r.err
 | 
			
		||||
		if err == syscall.ERROR_OPERATION_ABORTED {
 | 
			
		||||
			if f.closing.isSet() {
 | 
			
		||||
				err = ErrFileClosed
 | 
			
		||||
			}
 | 
			
		||||
		} else if err != nil && f.socket {
 | 
			
		||||
			// err is from Win32. Query the overlapped structure to get the winsock error.
 | 
			
		||||
			var bytes, flags uint32
 | 
			
		||||
			err = wsaGetOverlappedResult(f.handle, &c.o, &bytes, false, &flags)
 | 
			
		||||
		}
 | 
			
		||||
	case <-timeout:
 | 
			
		||||
		cancelIoEx(f.handle, &c.o)
 | 
			
		||||
		r = <-c.ch
 | 
			
		||||
		err = r.err
 | 
			
		||||
		if err == syscall.ERROR_OPERATION_ABORTED {
 | 
			
		||||
			err = ErrTimeout
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// runtime.KeepAlive is needed, as c is passed via native
 | 
			
		||||
	// code to ioCompletionProcessor, c must remain alive
 | 
			
		||||
	// until the channel read is complete.
 | 
			
		||||
	runtime.KeepAlive(c)
 | 
			
		||||
	return int(r.bytes), err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Read reads from a file handle.
 | 
			
		||||
func (f *win32File) Read(b []byte) (int, error) {
 | 
			
		||||
	c, err := f.prepareIo()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
	defer f.wg.Done()
 | 
			
		||||
 | 
			
		||||
	if f.readDeadline.timedout.isSet() {
 | 
			
		||||
		return 0, ErrTimeout
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var bytes uint32
 | 
			
		||||
	err = syscall.ReadFile(f.handle, b, &bytes, &c.o)
 | 
			
		||||
	n, err := f.asyncIo(c, &f.readDeadline, bytes, err)
 | 
			
		||||
	runtime.KeepAlive(b)
 | 
			
		||||
 | 
			
		||||
	// Handle EOF conditions.
 | 
			
		||||
	if err == nil && n == 0 && len(b) != 0 {
 | 
			
		||||
		return 0, io.EOF
 | 
			
		||||
	} else if err == syscall.ERROR_BROKEN_PIPE {
 | 
			
		||||
		return 0, io.EOF
 | 
			
		||||
	} else {
 | 
			
		||||
		return n, err
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Write writes to a file handle.
 | 
			
		||||
func (f *win32File) Write(b []byte) (int, error) {
 | 
			
		||||
	c, err := f.prepareIo()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
	defer f.wg.Done()
 | 
			
		||||
 | 
			
		||||
	if f.writeDeadline.timedout.isSet() {
 | 
			
		||||
		return 0, ErrTimeout
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var bytes uint32
 | 
			
		||||
	err = syscall.WriteFile(f.handle, b, &bytes, &c.o)
 | 
			
		||||
	n, err := f.asyncIo(c, &f.writeDeadline, bytes, err)
 | 
			
		||||
	runtime.KeepAlive(b)
 | 
			
		||||
	return n, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (f *win32File) SetReadDeadline(deadline time.Time) error {
 | 
			
		||||
	return f.readDeadline.set(deadline)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (f *win32File) SetWriteDeadline(deadline time.Time) error {
 | 
			
		||||
	return f.writeDeadline.set(deadline)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (f *win32File) Flush() error {
 | 
			
		||||
	return syscall.FlushFileBuffers(f.handle)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (f *win32File) Fd() uintptr {
 | 
			
		||||
	return uintptr(f.handle)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *deadlineHandler) set(deadline time.Time) error {
 | 
			
		||||
	d.setLock.Lock()
 | 
			
		||||
	defer d.setLock.Unlock()
 | 
			
		||||
 | 
			
		||||
	if d.timer != nil {
 | 
			
		||||
		if !d.timer.Stop() {
 | 
			
		||||
			<-d.channel
 | 
			
		||||
		}
 | 
			
		||||
		d.timer = nil
 | 
			
		||||
	}
 | 
			
		||||
	d.timedout.setFalse()
 | 
			
		||||
 | 
			
		||||
	select {
 | 
			
		||||
	case <-d.channel:
 | 
			
		||||
		d.channelLock.Lock()
 | 
			
		||||
		d.channel = make(chan struct{})
 | 
			
		||||
		d.channelLock.Unlock()
 | 
			
		||||
	default:
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if deadline.IsZero() {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	timeoutIO := func() {
 | 
			
		||||
		d.timedout.setTrue()
 | 
			
		||||
		close(d.channel)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	now := time.Now()
 | 
			
		||||
	duration := deadline.Sub(now)
 | 
			
		||||
	if deadline.After(now) {
 | 
			
		||||
		// Deadline is in the future, set a timer to wait
 | 
			
		||||
		d.timer = time.AfterFunc(duration, timeoutIO)
 | 
			
		||||
	} else {
 | 
			
		||||
		// Deadline is in the past. Cancel all pending IO now.
 | 
			
		||||
		timeoutIO()
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										73
									
								
								vendor/github.com/Microsoft/go-winio/fileinfo.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								vendor/github.com/Microsoft/go-winio/fileinfo.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,73 @@
 | 
			
		||||
// +build windows
 | 
			
		||||
 | 
			
		||||
package winio
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"os"
 | 
			
		||||
	"runtime"
 | 
			
		||||
	"unsafe"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/sys/windows"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// FileBasicInfo contains file access time and file attributes information.
 | 
			
		||||
type FileBasicInfo struct {
 | 
			
		||||
	CreationTime, LastAccessTime, LastWriteTime, ChangeTime windows.Filetime
 | 
			
		||||
	FileAttributes                                          uint32
 | 
			
		||||
	pad                                                     uint32 // padding
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetFileBasicInfo retrieves times and attributes for a file.
 | 
			
		||||
func GetFileBasicInfo(f *os.File) (*FileBasicInfo, error) {
 | 
			
		||||
	bi := &FileBasicInfo{}
 | 
			
		||||
	if err := windows.GetFileInformationByHandleEx(windows.Handle(f.Fd()), windows.FileBasicInfo, (*byte)(unsafe.Pointer(bi)), uint32(unsafe.Sizeof(*bi))); err != nil {
 | 
			
		||||
		return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err}
 | 
			
		||||
	}
 | 
			
		||||
	runtime.KeepAlive(f)
 | 
			
		||||
	return bi, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetFileBasicInfo sets times and attributes for a file.
 | 
			
		||||
func SetFileBasicInfo(f *os.File, bi *FileBasicInfo) error {
 | 
			
		||||
	if err := windows.SetFileInformationByHandle(windows.Handle(f.Fd()), windows.FileBasicInfo, (*byte)(unsafe.Pointer(bi)), uint32(unsafe.Sizeof(*bi))); err != nil {
 | 
			
		||||
		return &os.PathError{Op: "SetFileInformationByHandle", Path: f.Name(), Err: err}
 | 
			
		||||
	}
 | 
			
		||||
	runtime.KeepAlive(f)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FileStandardInfo contains extended information for the file.
 | 
			
		||||
// FILE_STANDARD_INFO in WinBase.h
 | 
			
		||||
// https://docs.microsoft.com/en-us/windows/win32/api/winbase/ns-winbase-file_standard_info
 | 
			
		||||
type FileStandardInfo struct {
 | 
			
		||||
	AllocationSize, EndOfFile int64
 | 
			
		||||
	NumberOfLinks             uint32
 | 
			
		||||
	DeletePending, Directory  bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetFileStandardInfo retrieves ended information for the file.
 | 
			
		||||
func GetFileStandardInfo(f *os.File) (*FileStandardInfo, error) {
 | 
			
		||||
	si := &FileStandardInfo{}
 | 
			
		||||
	if err := windows.GetFileInformationByHandleEx(windows.Handle(f.Fd()), windows.FileStandardInfo, (*byte)(unsafe.Pointer(si)), uint32(unsafe.Sizeof(*si))); err != nil {
 | 
			
		||||
		return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err}
 | 
			
		||||
	}
 | 
			
		||||
	runtime.KeepAlive(f)
 | 
			
		||||
	return si, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FileIDInfo contains the volume serial number and file ID for a file. This pair should be
 | 
			
		||||
// unique on a system.
 | 
			
		||||
type FileIDInfo struct {
 | 
			
		||||
	VolumeSerialNumber uint64
 | 
			
		||||
	FileID             [16]byte
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetFileID retrieves the unique (volume, file ID) pair for a file.
 | 
			
		||||
func GetFileID(f *os.File) (*FileIDInfo, error) {
 | 
			
		||||
	fileID := &FileIDInfo{}
 | 
			
		||||
	if err := windows.GetFileInformationByHandleEx(windows.Handle(f.Fd()), windows.FileIdInfo, (*byte)(unsafe.Pointer(fileID)), uint32(unsafe.Sizeof(*fileID))); err != nil {
 | 
			
		||||
		return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err}
 | 
			
		||||
	}
 | 
			
		||||
	runtime.KeepAlive(f)
 | 
			
		||||
	return fileID, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										316
									
								
								vendor/github.com/Microsoft/go-winio/hvsock.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										316
									
								
								vendor/github.com/Microsoft/go-winio/hvsock.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,316 @@
 | 
			
		||||
//go:build windows
 | 
			
		||||
// +build windows
 | 
			
		||||
 | 
			
		||||
package winio
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"net"
 | 
			
		||||
	"os"
 | 
			
		||||
	"syscall"
 | 
			
		||||
	"time"
 | 
			
		||||
	"unsafe"
 | 
			
		||||
 | 
			
		||||
	"github.com/Microsoft/go-winio/pkg/guid"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
//sys bind(s syscall.Handle, name unsafe.Pointer, namelen int32) (err error) [failretval==socketError] = ws2_32.bind
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	afHvSock = 34 // AF_HYPERV
 | 
			
		||||
 | 
			
		||||
	socketError = ^uintptr(0)
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// An HvsockAddr is an address for a AF_HYPERV socket.
 | 
			
		||||
type HvsockAddr struct {
 | 
			
		||||
	VMID      guid.GUID
 | 
			
		||||
	ServiceID guid.GUID
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type rawHvsockAddr struct {
 | 
			
		||||
	Family    uint16
 | 
			
		||||
	_         uint16
 | 
			
		||||
	VMID      guid.GUID
 | 
			
		||||
	ServiceID guid.GUID
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Network returns the address's network name, "hvsock".
 | 
			
		||||
func (addr *HvsockAddr) Network() string {
 | 
			
		||||
	return "hvsock"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (addr *HvsockAddr) String() string {
 | 
			
		||||
	return fmt.Sprintf("%s:%s", &addr.VMID, &addr.ServiceID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// VsockServiceID returns an hvsock service ID corresponding to the specified AF_VSOCK port.
 | 
			
		||||
func VsockServiceID(port uint32) guid.GUID {
 | 
			
		||||
	g, _ := guid.FromString("00000000-facb-11e6-bd58-64006a7986d3")
 | 
			
		||||
	g.Data1 = port
 | 
			
		||||
	return g
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (addr *HvsockAddr) raw() rawHvsockAddr {
 | 
			
		||||
	return rawHvsockAddr{
 | 
			
		||||
		Family:    afHvSock,
 | 
			
		||||
		VMID:      addr.VMID,
 | 
			
		||||
		ServiceID: addr.ServiceID,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (addr *HvsockAddr) fromRaw(raw *rawHvsockAddr) {
 | 
			
		||||
	addr.VMID = raw.VMID
 | 
			
		||||
	addr.ServiceID = raw.ServiceID
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// HvsockListener is a socket listener for the AF_HYPERV address family.
 | 
			
		||||
type HvsockListener struct {
 | 
			
		||||
	sock *win32File
 | 
			
		||||
	addr HvsockAddr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// HvsockConn is a connected socket of the AF_HYPERV address family.
 | 
			
		||||
type HvsockConn struct {
 | 
			
		||||
	sock          *win32File
 | 
			
		||||
	local, remote HvsockAddr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newHvSocket() (*win32File, error) {
 | 
			
		||||
	fd, err := syscall.Socket(afHvSock, syscall.SOCK_STREAM, 1)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, os.NewSyscallError("socket", err)
 | 
			
		||||
	}
 | 
			
		||||
	f, err := makeWin32File(fd)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		syscall.Close(fd)
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	f.socket = true
 | 
			
		||||
	return f, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ListenHvsock listens for connections on the specified hvsock address.
 | 
			
		||||
func ListenHvsock(addr *HvsockAddr) (_ *HvsockListener, err error) {
 | 
			
		||||
	l := &HvsockListener{addr: *addr}
 | 
			
		||||
	sock, err := newHvSocket()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, l.opErr("listen", err)
 | 
			
		||||
	}
 | 
			
		||||
	sa := addr.raw()
 | 
			
		||||
	err = bind(sock.handle, unsafe.Pointer(&sa), int32(unsafe.Sizeof(sa)))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, l.opErr("listen", os.NewSyscallError("socket", err))
 | 
			
		||||
	}
 | 
			
		||||
	err = syscall.Listen(sock.handle, 16)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, l.opErr("listen", os.NewSyscallError("listen", err))
 | 
			
		||||
	}
 | 
			
		||||
	return &HvsockListener{sock: sock, addr: *addr}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *HvsockListener) opErr(op string, err error) error {
 | 
			
		||||
	return &net.OpError{Op: op, Net: "hvsock", Addr: &l.addr, Err: err}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Addr returns the listener's network address.
 | 
			
		||||
func (l *HvsockListener) Addr() net.Addr {
 | 
			
		||||
	return &l.addr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Accept waits for the next connection and returns it.
 | 
			
		||||
func (l *HvsockListener) Accept() (_ net.Conn, err error) {
 | 
			
		||||
	sock, err := newHvSocket()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, l.opErr("accept", err)
 | 
			
		||||
	}
 | 
			
		||||
	defer func() {
 | 
			
		||||
		if sock != nil {
 | 
			
		||||
			sock.Close()
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
	c, err := l.sock.prepareIo()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, l.opErr("accept", err)
 | 
			
		||||
	}
 | 
			
		||||
	defer l.sock.wg.Done()
 | 
			
		||||
 | 
			
		||||
	// AcceptEx, per documentation, requires an extra 16 bytes per address.
 | 
			
		||||
	const addrlen = uint32(16 + unsafe.Sizeof(rawHvsockAddr{}))
 | 
			
		||||
	var addrbuf [addrlen * 2]byte
 | 
			
		||||
 | 
			
		||||
	var bytes uint32
 | 
			
		||||
	err = syscall.AcceptEx(l.sock.handle, sock.handle, &addrbuf[0], 0, addrlen, addrlen, &bytes, &c.o)
 | 
			
		||||
	_, err = l.sock.asyncIo(c, nil, bytes, err)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, l.opErr("accept", os.NewSyscallError("acceptex", err))
 | 
			
		||||
	}
 | 
			
		||||
	conn := &HvsockConn{
 | 
			
		||||
		sock: sock,
 | 
			
		||||
	}
 | 
			
		||||
	conn.local.fromRaw((*rawHvsockAddr)(unsafe.Pointer(&addrbuf[0])))
 | 
			
		||||
	conn.remote.fromRaw((*rawHvsockAddr)(unsafe.Pointer(&addrbuf[addrlen])))
 | 
			
		||||
	sock = nil
 | 
			
		||||
	return conn, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Close closes the listener, causing any pending Accept calls to fail.
 | 
			
		||||
func (l *HvsockListener) Close() error {
 | 
			
		||||
	return l.sock.Close()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Need to finish ConnectEx handling
 | 
			
		||||
func DialHvsock(ctx context.Context, addr *HvsockAddr) (*HvsockConn, error) {
 | 
			
		||||
	sock, err := newHvSocket()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	defer func() {
 | 
			
		||||
		if sock != nil {
 | 
			
		||||
			sock.Close()
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
	c, err := sock.prepareIo()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	defer sock.wg.Done()
 | 
			
		||||
	var bytes uint32
 | 
			
		||||
	err = windows.ConnectEx(windows.Handle(sock.handle), sa, nil, 0, &bytes, &c.o)
 | 
			
		||||
	_, err = sock.asyncIo(ctx, c, nil, bytes, err)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	conn := &HvsockConn{
 | 
			
		||||
		sock:   sock,
 | 
			
		||||
		remote: *addr,
 | 
			
		||||
	}
 | 
			
		||||
	sock = nil
 | 
			
		||||
	return conn, nil
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
func (conn *HvsockConn) opErr(op string, err error) error {
 | 
			
		||||
	return &net.OpError{Op: op, Net: "hvsock", Source: &conn.local, Addr: &conn.remote, Err: err}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (conn *HvsockConn) Read(b []byte) (int, error) {
 | 
			
		||||
	c, err := conn.sock.prepareIo()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, conn.opErr("read", err)
 | 
			
		||||
	}
 | 
			
		||||
	defer conn.sock.wg.Done()
 | 
			
		||||
	buf := syscall.WSABuf{Buf: &b[0], Len: uint32(len(b))}
 | 
			
		||||
	var flags, bytes uint32
 | 
			
		||||
	err = syscall.WSARecv(conn.sock.handle, &buf, 1, &bytes, &flags, &c.o, nil)
 | 
			
		||||
	n, err := conn.sock.asyncIo(c, &conn.sock.readDeadline, bytes, err)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if _, ok := err.(syscall.Errno); ok {
 | 
			
		||||
			err = os.NewSyscallError("wsarecv", err)
 | 
			
		||||
		}
 | 
			
		||||
		return 0, conn.opErr("read", err)
 | 
			
		||||
	} else if n == 0 {
 | 
			
		||||
		err = io.EOF
 | 
			
		||||
	}
 | 
			
		||||
	return n, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (conn *HvsockConn) Write(b []byte) (int, error) {
 | 
			
		||||
	t := 0
 | 
			
		||||
	for len(b) != 0 {
 | 
			
		||||
		n, err := conn.write(b)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return t + n, err
 | 
			
		||||
		}
 | 
			
		||||
		t += n
 | 
			
		||||
		b = b[n:]
 | 
			
		||||
	}
 | 
			
		||||
	return t, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (conn *HvsockConn) write(b []byte) (int, error) {
 | 
			
		||||
	c, err := conn.sock.prepareIo()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, conn.opErr("write", err)
 | 
			
		||||
	}
 | 
			
		||||
	defer conn.sock.wg.Done()
 | 
			
		||||
	buf := syscall.WSABuf{Buf: &b[0], Len: uint32(len(b))}
 | 
			
		||||
	var bytes uint32
 | 
			
		||||
	err = syscall.WSASend(conn.sock.handle, &buf, 1, &bytes, 0, &c.o, nil)
 | 
			
		||||
	n, err := conn.sock.asyncIo(c, &conn.sock.writeDeadline, bytes, err)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if _, ok := err.(syscall.Errno); ok {
 | 
			
		||||
			err = os.NewSyscallError("wsasend", err)
 | 
			
		||||
		}
 | 
			
		||||
		return 0, conn.opErr("write", err)
 | 
			
		||||
	}
 | 
			
		||||
	return n, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Close closes the socket connection, failing any pending read or write calls.
 | 
			
		||||
func (conn *HvsockConn) Close() error {
 | 
			
		||||
	return conn.sock.Close()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (conn *HvsockConn) IsClosed() bool {
 | 
			
		||||
	return conn.sock.IsClosed()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (conn *HvsockConn) shutdown(how int) error {
 | 
			
		||||
	if conn.IsClosed() {
 | 
			
		||||
		return ErrFileClosed
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err := syscall.Shutdown(conn.sock.handle, how)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return os.NewSyscallError("shutdown", err)
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CloseRead shuts down the read end of the socket, preventing future read operations.
 | 
			
		||||
func (conn *HvsockConn) CloseRead() error {
 | 
			
		||||
	err := conn.shutdown(syscall.SHUT_RD)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return conn.opErr("close", err)
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CloseWrite shuts down the write end of the socket, preventing future write operations and
 | 
			
		||||
// notifying the other endpoint that no more data will be written.
 | 
			
		||||
func (conn *HvsockConn) CloseWrite() error {
 | 
			
		||||
	err := conn.shutdown(syscall.SHUT_WR)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return conn.opErr("close", err)
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LocalAddr returns the local address of the connection.
 | 
			
		||||
func (conn *HvsockConn) LocalAddr() net.Addr {
 | 
			
		||||
	return &conn.local
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RemoteAddr returns the remote address of the connection.
 | 
			
		||||
func (conn *HvsockConn) RemoteAddr() net.Addr {
 | 
			
		||||
	return &conn.remote
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetDeadline implements the net.Conn SetDeadline method.
 | 
			
		||||
func (conn *HvsockConn) SetDeadline(t time.Time) error {
 | 
			
		||||
	conn.SetReadDeadline(t)
 | 
			
		||||
	conn.SetWriteDeadline(t)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetReadDeadline implements the net.Conn SetReadDeadline method.
 | 
			
		||||
func (conn *HvsockConn) SetReadDeadline(t time.Time) error {
 | 
			
		||||
	return conn.sock.SetReadDeadline(t)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetWriteDeadline implements the net.Conn SetWriteDeadline method.
 | 
			
		||||
func (conn *HvsockConn) SetWriteDeadline(t time.Time) error {
 | 
			
		||||
	return conn.sock.SetWriteDeadline(t)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										517
									
								
								vendor/github.com/Microsoft/go-winio/pipe.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										517
									
								
								vendor/github.com/Microsoft/go-winio/pipe.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,517 @@
 | 
			
		||||
// +build windows
 | 
			
		||||
 | 
			
		||||
package winio
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"net"
 | 
			
		||||
	"os"
 | 
			
		||||
	"runtime"
 | 
			
		||||
	"syscall"
 | 
			
		||||
	"time"
 | 
			
		||||
	"unsafe"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
//sys connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) = ConnectNamedPipe
 | 
			
		||||
//sys createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *syscall.SecurityAttributes) (handle syscall.Handle, err error)  [failretval==syscall.InvalidHandle] = CreateNamedPipeW
 | 
			
		||||
//sys createFile(name string, access uint32, mode uint32, sa *syscall.SecurityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) [failretval==syscall.InvalidHandle] = CreateFileW
 | 
			
		||||
//sys getNamedPipeInfo(pipe syscall.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) = GetNamedPipeInfo
 | 
			
		||||
//sys getNamedPipeHandleState(pipe syscall.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) = GetNamedPipeHandleStateW
 | 
			
		||||
//sys localAlloc(uFlags uint32, length uint32) (ptr uintptr) = LocalAlloc
 | 
			
		||||
//sys ntCreateNamedPipeFile(pipe *syscall.Handle, access uint32, oa *objectAttributes, iosb *ioStatusBlock, share uint32, disposition uint32, options uint32, typ uint32, readMode uint32, completionMode uint32, maxInstances uint32, inboundQuota uint32, outputQuota uint32, timeout *int64) (status ntstatus) = ntdll.NtCreateNamedPipeFile
 | 
			
		||||
//sys rtlNtStatusToDosError(status ntstatus) (winerr error) = ntdll.RtlNtStatusToDosErrorNoTeb
 | 
			
		||||
//sys rtlDosPathNameToNtPathName(name *uint16, ntName *unicodeString, filePart uintptr, reserved uintptr) (status ntstatus) = ntdll.RtlDosPathNameToNtPathName_U
 | 
			
		||||
//sys rtlDefaultNpAcl(dacl *uintptr) (status ntstatus) = ntdll.RtlDefaultNpAcl
 | 
			
		||||
 | 
			
		||||
type ioStatusBlock struct {
 | 
			
		||||
	Status, Information uintptr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type objectAttributes struct {
 | 
			
		||||
	Length             uintptr
 | 
			
		||||
	RootDirectory      uintptr
 | 
			
		||||
	ObjectName         *unicodeString
 | 
			
		||||
	Attributes         uintptr
 | 
			
		||||
	SecurityDescriptor *securityDescriptor
 | 
			
		||||
	SecurityQoS        uintptr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type unicodeString struct {
 | 
			
		||||
	Length        uint16
 | 
			
		||||
	MaximumLength uint16
 | 
			
		||||
	Buffer        uintptr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type securityDescriptor struct {
 | 
			
		||||
	Revision byte
 | 
			
		||||
	Sbz1     byte
 | 
			
		||||
	Control  uint16
 | 
			
		||||
	Owner    uintptr
 | 
			
		||||
	Group    uintptr
 | 
			
		||||
	Sacl     uintptr
 | 
			
		||||
	Dacl     uintptr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ntstatus int32
 | 
			
		||||
 | 
			
		||||
func (status ntstatus) Err() error {
 | 
			
		||||
	if status >= 0 {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	return rtlNtStatusToDosError(status)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	cERROR_PIPE_BUSY      = syscall.Errno(231)
 | 
			
		||||
	cERROR_NO_DATA        = syscall.Errno(232)
 | 
			
		||||
	cERROR_PIPE_CONNECTED = syscall.Errno(535)
 | 
			
		||||
	cERROR_SEM_TIMEOUT    = syscall.Errno(121)
 | 
			
		||||
 | 
			
		||||
	cSECURITY_SQOS_PRESENT = 0x100000
 | 
			
		||||
	cSECURITY_ANONYMOUS    = 0
 | 
			
		||||
 | 
			
		||||
	cPIPE_TYPE_MESSAGE = 4
 | 
			
		||||
 | 
			
		||||
	cPIPE_READMODE_MESSAGE = 2
 | 
			
		||||
 | 
			
		||||
	cFILE_OPEN   = 1
 | 
			
		||||
	cFILE_CREATE = 2
 | 
			
		||||
 | 
			
		||||
	cFILE_PIPE_MESSAGE_TYPE          = 1
 | 
			
		||||
	cFILE_PIPE_REJECT_REMOTE_CLIENTS = 2
 | 
			
		||||
 | 
			
		||||
	cSE_DACL_PRESENT = 4
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	// ErrPipeListenerClosed is returned for pipe operations on listeners that have been closed.
 | 
			
		||||
	// This error should match net.errClosing since docker takes a dependency on its text.
 | 
			
		||||
	ErrPipeListenerClosed = errors.New("use of closed network connection")
 | 
			
		||||
 | 
			
		||||
	errPipeWriteClosed = errors.New("pipe has been closed for write")
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type win32Pipe struct {
 | 
			
		||||
	*win32File
 | 
			
		||||
	path string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type win32MessageBytePipe struct {
 | 
			
		||||
	win32Pipe
 | 
			
		||||
	writeClosed bool
 | 
			
		||||
	readEOF     bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type pipeAddress string
 | 
			
		||||
 | 
			
		||||
func (f *win32Pipe) LocalAddr() net.Addr {
 | 
			
		||||
	return pipeAddress(f.path)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (f *win32Pipe) RemoteAddr() net.Addr {
 | 
			
		||||
	return pipeAddress(f.path)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (f *win32Pipe) SetDeadline(t time.Time) error {
 | 
			
		||||
	f.SetReadDeadline(t)
 | 
			
		||||
	f.SetWriteDeadline(t)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CloseWrite closes the write side of a message pipe in byte mode.
 | 
			
		||||
func (f *win32MessageBytePipe) CloseWrite() error {
 | 
			
		||||
	if f.writeClosed {
 | 
			
		||||
		return errPipeWriteClosed
 | 
			
		||||
	}
 | 
			
		||||
	err := f.win32File.Flush()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	_, err = f.win32File.Write(nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	f.writeClosed = true
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Write writes bytes to a message pipe in byte mode. Zero-byte writes are ignored, since
 | 
			
		||||
// they are used to implement CloseWrite().
 | 
			
		||||
func (f *win32MessageBytePipe) Write(b []byte) (int, error) {
 | 
			
		||||
	if f.writeClosed {
 | 
			
		||||
		return 0, errPipeWriteClosed
 | 
			
		||||
	}
 | 
			
		||||
	if len(b) == 0 {
 | 
			
		||||
		return 0, nil
 | 
			
		||||
	}
 | 
			
		||||
	return f.win32File.Write(b)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Read reads bytes from a message pipe in byte mode. A read of a zero-byte message on a message
 | 
			
		||||
// mode pipe will return io.EOF, as will all subsequent reads.
 | 
			
		||||
func (f *win32MessageBytePipe) Read(b []byte) (int, error) {
 | 
			
		||||
	if f.readEOF {
 | 
			
		||||
		return 0, io.EOF
 | 
			
		||||
	}
 | 
			
		||||
	n, err := f.win32File.Read(b)
 | 
			
		||||
	if err == io.EOF {
 | 
			
		||||
		// If this was the result of a zero-byte read, then
 | 
			
		||||
		// it is possible that the read was due to a zero-size
 | 
			
		||||
		// message. Since we are simulating CloseWrite with a
 | 
			
		||||
		// zero-byte message, ensure that all future Read() calls
 | 
			
		||||
		// also return EOF.
 | 
			
		||||
		f.readEOF = true
 | 
			
		||||
	} else if err == syscall.ERROR_MORE_DATA {
 | 
			
		||||
		// ERROR_MORE_DATA indicates that the pipe's read mode is message mode
 | 
			
		||||
		// and the message still has more bytes. Treat this as a success, since
 | 
			
		||||
		// this package presents all named pipes as byte streams.
 | 
			
		||||
		err = nil
 | 
			
		||||
	}
 | 
			
		||||
	return n, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s pipeAddress) Network() string {
 | 
			
		||||
	return "pipe"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s pipeAddress) String() string {
 | 
			
		||||
	return string(s)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// tryDialPipe attempts to dial the pipe at `path` until `ctx` cancellation or timeout.
 | 
			
		||||
func tryDialPipe(ctx context.Context, path *string, access uint32) (syscall.Handle, error) {
 | 
			
		||||
	for {
 | 
			
		||||
 | 
			
		||||
		select {
 | 
			
		||||
		case <-ctx.Done():
 | 
			
		||||
			return syscall.Handle(0), ctx.Err()
 | 
			
		||||
		default:
 | 
			
		||||
			h, err := createFile(*path, access, 0, nil, syscall.OPEN_EXISTING, syscall.FILE_FLAG_OVERLAPPED|cSECURITY_SQOS_PRESENT|cSECURITY_ANONYMOUS, 0)
 | 
			
		||||
			if err == nil {
 | 
			
		||||
				return h, nil
 | 
			
		||||
			}
 | 
			
		||||
			if err != cERROR_PIPE_BUSY {
 | 
			
		||||
				return h, &os.PathError{Err: err, Op: "open", Path: *path}
 | 
			
		||||
			}
 | 
			
		||||
			// Wait 10 msec and try again. This is a rather simplistic
 | 
			
		||||
			// view, as we always try each 10 milliseconds.
 | 
			
		||||
			time.Sleep(10 * time.Millisecond)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DialPipe connects to a named pipe by path, timing out if the connection
 | 
			
		||||
// takes longer than the specified duration. If timeout is nil, then we use
 | 
			
		||||
// a default timeout of 2 seconds.  (We do not use WaitNamedPipe.)
 | 
			
		||||
func DialPipe(path string, timeout *time.Duration) (net.Conn, error) {
 | 
			
		||||
	var absTimeout time.Time
 | 
			
		||||
	if timeout != nil {
 | 
			
		||||
		absTimeout = time.Now().Add(*timeout)
 | 
			
		||||
	} else {
 | 
			
		||||
		absTimeout = time.Now().Add(2 * time.Second)
 | 
			
		||||
	}
 | 
			
		||||
	ctx, _ := context.WithDeadline(context.Background(), absTimeout)
 | 
			
		||||
	conn, err := DialPipeContext(ctx, path)
 | 
			
		||||
	if err == context.DeadlineExceeded {
 | 
			
		||||
		return nil, ErrTimeout
 | 
			
		||||
	}
 | 
			
		||||
	return conn, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DialPipeContext attempts to connect to a named pipe by `path` until `ctx`
 | 
			
		||||
// cancellation or timeout.
 | 
			
		||||
func DialPipeContext(ctx context.Context, path string) (net.Conn, error) {
 | 
			
		||||
	return DialPipeAccess(ctx, path, syscall.GENERIC_READ|syscall.GENERIC_WRITE)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DialPipeAccess attempts to connect to a named pipe by `path` with `access` until `ctx`
 | 
			
		||||
// cancellation or timeout.
 | 
			
		||||
func DialPipeAccess(ctx context.Context, path string, access uint32) (net.Conn, error) {
 | 
			
		||||
	var err error
 | 
			
		||||
	var h syscall.Handle
 | 
			
		||||
	h, err = tryDialPipe(ctx, &path, access)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var flags uint32
 | 
			
		||||
	err = getNamedPipeInfo(h, &flags, nil, nil, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	f, err := makeWin32File(h)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		syscall.Close(h)
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// If the pipe is in message mode, return a message byte pipe, which
 | 
			
		||||
	// supports CloseWrite().
 | 
			
		||||
	if flags&cPIPE_TYPE_MESSAGE != 0 {
 | 
			
		||||
		return &win32MessageBytePipe{
 | 
			
		||||
			win32Pipe: win32Pipe{win32File: f, path: path},
 | 
			
		||||
		}, nil
 | 
			
		||||
	}
 | 
			
		||||
	return &win32Pipe{win32File: f, path: path}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type acceptResponse struct {
 | 
			
		||||
	f   *win32File
 | 
			
		||||
	err error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type win32PipeListener struct {
 | 
			
		||||
	firstHandle syscall.Handle
 | 
			
		||||
	path        string
 | 
			
		||||
	config      PipeConfig
 | 
			
		||||
	acceptCh    chan (chan acceptResponse)
 | 
			
		||||
	closeCh     chan int
 | 
			
		||||
	doneCh      chan int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func makeServerPipeHandle(path string, sd []byte, c *PipeConfig, first bool) (syscall.Handle, error) {
 | 
			
		||||
	path16, err := syscall.UTF16FromString(path)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, &os.PathError{Op: "open", Path: path, Err: err}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var oa objectAttributes
 | 
			
		||||
	oa.Length = unsafe.Sizeof(oa)
 | 
			
		||||
 | 
			
		||||
	var ntPath unicodeString
 | 
			
		||||
	if err := rtlDosPathNameToNtPathName(&path16[0], &ntPath, 0, 0).Err(); err != nil {
 | 
			
		||||
		return 0, &os.PathError{Op: "open", Path: path, Err: err}
 | 
			
		||||
	}
 | 
			
		||||
	defer localFree(ntPath.Buffer)
 | 
			
		||||
	oa.ObjectName = &ntPath
 | 
			
		||||
 | 
			
		||||
	// The security descriptor is only needed for the first pipe.
 | 
			
		||||
	if first {
 | 
			
		||||
		if sd != nil {
 | 
			
		||||
			len := uint32(len(sd))
 | 
			
		||||
			sdb := localAlloc(0, len)
 | 
			
		||||
			defer localFree(sdb)
 | 
			
		||||
			copy((*[0xffff]byte)(unsafe.Pointer(sdb))[:], sd)
 | 
			
		||||
			oa.SecurityDescriptor = (*securityDescriptor)(unsafe.Pointer(sdb))
 | 
			
		||||
		} else {
 | 
			
		||||
			// Construct the default named pipe security descriptor.
 | 
			
		||||
			var dacl uintptr
 | 
			
		||||
			if err := rtlDefaultNpAcl(&dacl).Err(); err != nil {
 | 
			
		||||
				return 0, fmt.Errorf("getting default named pipe ACL: %s", err)
 | 
			
		||||
			}
 | 
			
		||||
			defer localFree(dacl)
 | 
			
		||||
 | 
			
		||||
			sdb := &securityDescriptor{
 | 
			
		||||
				Revision: 1,
 | 
			
		||||
				Control:  cSE_DACL_PRESENT,
 | 
			
		||||
				Dacl:     dacl,
 | 
			
		||||
			}
 | 
			
		||||
			oa.SecurityDescriptor = sdb
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	typ := uint32(cFILE_PIPE_REJECT_REMOTE_CLIENTS)
 | 
			
		||||
	if c.MessageMode {
 | 
			
		||||
		typ |= cFILE_PIPE_MESSAGE_TYPE
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	disposition := uint32(cFILE_OPEN)
 | 
			
		||||
	access := uint32(syscall.GENERIC_READ | syscall.GENERIC_WRITE | syscall.SYNCHRONIZE)
 | 
			
		||||
	if first {
 | 
			
		||||
		disposition = cFILE_CREATE
 | 
			
		||||
		// By not asking for read or write access, the named pipe file system
 | 
			
		||||
		// will put this pipe into an initially disconnected state, blocking
 | 
			
		||||
		// client connections until the next call with first == false.
 | 
			
		||||
		access = syscall.SYNCHRONIZE
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	timeout := int64(-50 * 10000) // 50ms
 | 
			
		||||
 | 
			
		||||
	var (
 | 
			
		||||
		h    syscall.Handle
 | 
			
		||||
		iosb ioStatusBlock
 | 
			
		||||
	)
 | 
			
		||||
	err = ntCreateNamedPipeFile(&h, access, &oa, &iosb, syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE, disposition, 0, typ, 0, 0, 0xffffffff, uint32(c.InputBufferSize), uint32(c.OutputBufferSize), &timeout).Err()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, &os.PathError{Op: "open", Path: path, Err: err}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	runtime.KeepAlive(ntPath)
 | 
			
		||||
	return h, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *win32PipeListener) makeServerPipe() (*win32File, error) {
 | 
			
		||||
	h, err := makeServerPipeHandle(l.path, nil, &l.config, false)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	f, err := makeWin32File(h)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		syscall.Close(h)
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return f, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *win32PipeListener) makeConnectedServerPipe() (*win32File, error) {
 | 
			
		||||
	p, err := l.makeServerPipe()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Wait for the client to connect.
 | 
			
		||||
	ch := make(chan error)
 | 
			
		||||
	go func(p *win32File) {
 | 
			
		||||
		ch <- connectPipe(p)
 | 
			
		||||
	}(p)
 | 
			
		||||
 | 
			
		||||
	select {
 | 
			
		||||
	case err = <-ch:
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			p.Close()
 | 
			
		||||
			p = nil
 | 
			
		||||
		}
 | 
			
		||||
	case <-l.closeCh:
 | 
			
		||||
		// Abort the connect request by closing the handle.
 | 
			
		||||
		p.Close()
 | 
			
		||||
		p = nil
 | 
			
		||||
		err = <-ch
 | 
			
		||||
		if err == nil || err == ErrFileClosed {
 | 
			
		||||
			err = ErrPipeListenerClosed
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return p, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *win32PipeListener) listenerRoutine() {
 | 
			
		||||
	closed := false
 | 
			
		||||
	for !closed {
 | 
			
		||||
		select {
 | 
			
		||||
		case <-l.closeCh:
 | 
			
		||||
			closed = true
 | 
			
		||||
		case responseCh := <-l.acceptCh:
 | 
			
		||||
			var (
 | 
			
		||||
				p   *win32File
 | 
			
		||||
				err error
 | 
			
		||||
			)
 | 
			
		||||
			for {
 | 
			
		||||
				p, err = l.makeConnectedServerPipe()
 | 
			
		||||
				// If the connection was immediately closed by the client, try
 | 
			
		||||
				// again.
 | 
			
		||||
				if err != cERROR_NO_DATA {
 | 
			
		||||
					break
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			responseCh <- acceptResponse{p, err}
 | 
			
		||||
			closed = err == ErrPipeListenerClosed
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	syscall.Close(l.firstHandle)
 | 
			
		||||
	l.firstHandle = 0
 | 
			
		||||
	// Notify Close() and Accept() callers that the handle has been closed.
 | 
			
		||||
	close(l.doneCh)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PipeConfig contain configuration for the pipe listener.
 | 
			
		||||
type PipeConfig struct {
 | 
			
		||||
	// SecurityDescriptor contains a Windows security descriptor in SDDL format.
 | 
			
		||||
	SecurityDescriptor string
 | 
			
		||||
 | 
			
		||||
	// MessageMode determines whether the pipe is in byte or message mode. In either
 | 
			
		||||
	// case the pipe is read in byte mode by default. The only practical difference in
 | 
			
		||||
	// this implementation is that CloseWrite() is only supported for message mode pipes;
 | 
			
		||||
	// CloseWrite() is implemented as a zero-byte write, but zero-byte writes are only
 | 
			
		||||
	// transferred to the reader (and returned as io.EOF in this implementation)
 | 
			
		||||
	// when the pipe is in message mode.
 | 
			
		||||
	MessageMode bool
 | 
			
		||||
 | 
			
		||||
	// InputBufferSize specifies the size of the input buffer, in bytes.
 | 
			
		||||
	InputBufferSize int32
 | 
			
		||||
 | 
			
		||||
	// OutputBufferSize specifies the size of the output buffer, in bytes.
 | 
			
		||||
	OutputBufferSize int32
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ListenPipe creates a listener on a Windows named pipe path, e.g. \\.\pipe\mypipe.
 | 
			
		||||
// The pipe must not already exist.
 | 
			
		||||
func ListenPipe(path string, c *PipeConfig) (net.Listener, error) {
 | 
			
		||||
	var (
 | 
			
		||||
		sd  []byte
 | 
			
		||||
		err error
 | 
			
		||||
	)
 | 
			
		||||
	if c == nil {
 | 
			
		||||
		c = &PipeConfig{}
 | 
			
		||||
	}
 | 
			
		||||
	if c.SecurityDescriptor != "" {
 | 
			
		||||
		sd, err = SddlToSecurityDescriptor(c.SecurityDescriptor)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	h, err := makeServerPipeHandle(path, sd, c, true)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	l := &win32PipeListener{
 | 
			
		||||
		firstHandle: h,
 | 
			
		||||
		path:        path,
 | 
			
		||||
		config:      *c,
 | 
			
		||||
		acceptCh:    make(chan (chan acceptResponse)),
 | 
			
		||||
		closeCh:     make(chan int),
 | 
			
		||||
		doneCh:      make(chan int),
 | 
			
		||||
	}
 | 
			
		||||
	go l.listenerRoutine()
 | 
			
		||||
	return l, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func connectPipe(p *win32File) error {
 | 
			
		||||
	c, err := p.prepareIo()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	defer p.wg.Done()
 | 
			
		||||
 | 
			
		||||
	err = connectNamedPipe(p.handle, &c.o)
 | 
			
		||||
	_, err = p.asyncIo(c, nil, 0, err)
 | 
			
		||||
	if err != nil && err != cERROR_PIPE_CONNECTED {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *win32PipeListener) Accept() (net.Conn, error) {
 | 
			
		||||
	ch := make(chan acceptResponse)
 | 
			
		||||
	select {
 | 
			
		||||
	case l.acceptCh <- ch:
 | 
			
		||||
		response := <-ch
 | 
			
		||||
		err := response.err
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		if l.config.MessageMode {
 | 
			
		||||
			return &win32MessageBytePipe{
 | 
			
		||||
				win32Pipe: win32Pipe{win32File: response.f, path: l.path},
 | 
			
		||||
			}, nil
 | 
			
		||||
		}
 | 
			
		||||
		return &win32Pipe{win32File: response.f, path: l.path}, nil
 | 
			
		||||
	case <-l.doneCh:
 | 
			
		||||
		return nil, ErrPipeListenerClosed
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *win32PipeListener) Close() error {
 | 
			
		||||
	select {
 | 
			
		||||
	case l.closeCh <- 1:
 | 
			
		||||
		<-l.doneCh
 | 
			
		||||
	case <-l.doneCh:
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *win32PipeListener) Addr() net.Addr {
 | 
			
		||||
	return pipeAddress(l.path)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										228
									
								
								vendor/github.com/Microsoft/go-winio/pkg/guid/guid.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										228
									
								
								vendor/github.com/Microsoft/go-winio/pkg/guid/guid.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,228 @@
 | 
			
		||||
// +build windows
 | 
			
		||||
 | 
			
		||||
// Package guid provides a GUID type. The backing structure for a GUID is
 | 
			
		||||
// identical to that used by the golang.org/x/sys/windows GUID type.
 | 
			
		||||
// There are two main binary encodings used for a GUID, the big-endian encoding,
 | 
			
		||||
// and the Windows (mixed-endian) encoding. See here for details:
 | 
			
		||||
// https://en.wikipedia.org/wiki/Universally_unique_identifier#Encoding
 | 
			
		||||
package guid
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/rand"
 | 
			
		||||
	"crypto/sha1"
 | 
			
		||||
	"encoding"
 | 
			
		||||
	"encoding/binary"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strconv"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Variant specifies which GUID variant (or "type") of the GUID. It determines
 | 
			
		||||
// how the entirety of the rest of the GUID is interpreted.
 | 
			
		||||
type Variant uint8
 | 
			
		||||
 | 
			
		||||
// The variants specified by RFC 4122.
 | 
			
		||||
const (
 | 
			
		||||
	// VariantUnknown specifies a GUID variant which does not conform to one of
 | 
			
		||||
	// the variant encodings specified in RFC 4122.
 | 
			
		||||
	VariantUnknown Variant = iota
 | 
			
		||||
	VariantNCS
 | 
			
		||||
	VariantRFC4122
 | 
			
		||||
	VariantMicrosoft
 | 
			
		||||
	VariantFuture
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Version specifies how the bits in the GUID were generated. For instance, a
 | 
			
		||||
// version 4 GUID is randomly generated, and a version 5 is generated from the
 | 
			
		||||
// hash of an input string.
 | 
			
		||||
type Version uint8
 | 
			
		||||
 | 
			
		||||
var _ = (encoding.TextMarshaler)(GUID{})
 | 
			
		||||
var _ = (encoding.TextUnmarshaler)(&GUID{})
 | 
			
		||||
 | 
			
		||||
// NewV4 returns a new version 4 (pseudorandom) GUID, as defined by RFC 4122.
 | 
			
		||||
func NewV4() (GUID, error) {
 | 
			
		||||
	var b [16]byte
 | 
			
		||||
	if _, err := rand.Read(b[:]); err != nil {
 | 
			
		||||
		return GUID{}, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	g := FromArray(b)
 | 
			
		||||
	g.setVersion(4) // Version 4 means randomly generated.
 | 
			
		||||
	g.setVariant(VariantRFC4122)
 | 
			
		||||
 | 
			
		||||
	return g, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewV5 returns a new version 5 (generated from a string via SHA-1 hashing)
 | 
			
		||||
// GUID, as defined by RFC 4122. The RFC is unclear on the encoding of the name,
 | 
			
		||||
// and the sample code treats it as a series of bytes, so we do the same here.
 | 
			
		||||
//
 | 
			
		||||
// Some implementations, such as those found on Windows, treat the name as a
 | 
			
		||||
// big-endian UTF16 stream of bytes. If that is desired, the string can be
 | 
			
		||||
// encoded as such before being passed to this function.
 | 
			
		||||
func NewV5(namespace GUID, name []byte) (GUID, error) {
 | 
			
		||||
	b := sha1.New()
 | 
			
		||||
	namespaceBytes := namespace.ToArray()
 | 
			
		||||
	b.Write(namespaceBytes[:])
 | 
			
		||||
	b.Write(name)
 | 
			
		||||
 | 
			
		||||
	a := [16]byte{}
 | 
			
		||||
	copy(a[:], b.Sum(nil))
 | 
			
		||||
 | 
			
		||||
	g := FromArray(a)
 | 
			
		||||
	g.setVersion(5) // Version 5 means generated from a string.
 | 
			
		||||
	g.setVariant(VariantRFC4122)
 | 
			
		||||
 | 
			
		||||
	return g, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func fromArray(b [16]byte, order binary.ByteOrder) GUID {
 | 
			
		||||
	var g GUID
 | 
			
		||||
	g.Data1 = order.Uint32(b[0:4])
 | 
			
		||||
	g.Data2 = order.Uint16(b[4:6])
 | 
			
		||||
	g.Data3 = order.Uint16(b[6:8])
 | 
			
		||||
	copy(g.Data4[:], b[8:16])
 | 
			
		||||
	return g
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (g GUID) toArray(order binary.ByteOrder) [16]byte {
 | 
			
		||||
	b := [16]byte{}
 | 
			
		||||
	order.PutUint32(b[0:4], g.Data1)
 | 
			
		||||
	order.PutUint16(b[4:6], g.Data2)
 | 
			
		||||
	order.PutUint16(b[6:8], g.Data3)
 | 
			
		||||
	copy(b[8:16], g.Data4[:])
 | 
			
		||||
	return b
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FromArray constructs a GUID from a big-endian encoding array of 16 bytes.
 | 
			
		||||
func FromArray(b [16]byte) GUID {
 | 
			
		||||
	return fromArray(b, binary.BigEndian)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ToArray returns an array of 16 bytes representing the GUID in big-endian
 | 
			
		||||
// encoding.
 | 
			
		||||
func (g GUID) ToArray() [16]byte {
 | 
			
		||||
	return g.toArray(binary.BigEndian)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FromWindowsArray constructs a GUID from a Windows encoding array of bytes.
 | 
			
		||||
func FromWindowsArray(b [16]byte) GUID {
 | 
			
		||||
	return fromArray(b, binary.LittleEndian)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ToWindowsArray returns an array of 16 bytes representing the GUID in Windows
 | 
			
		||||
// encoding.
 | 
			
		||||
func (g GUID) ToWindowsArray() [16]byte {
 | 
			
		||||
	return g.toArray(binary.LittleEndian)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (g GUID) String() string {
 | 
			
		||||
	return fmt.Sprintf(
 | 
			
		||||
		"%08x-%04x-%04x-%04x-%012x",
 | 
			
		||||
		g.Data1,
 | 
			
		||||
		g.Data2,
 | 
			
		||||
		g.Data3,
 | 
			
		||||
		g.Data4[:2],
 | 
			
		||||
		g.Data4[2:])
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FromString parses a string containing a GUID and returns the GUID. The only
 | 
			
		||||
// format currently supported is the `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`
 | 
			
		||||
// format.
 | 
			
		||||
func FromString(s string) (GUID, error) {
 | 
			
		||||
	if len(s) != 36 {
 | 
			
		||||
		return GUID{}, fmt.Errorf("invalid GUID %q", s)
 | 
			
		||||
	}
 | 
			
		||||
	if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' {
 | 
			
		||||
		return GUID{}, fmt.Errorf("invalid GUID %q", s)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var g GUID
 | 
			
		||||
 | 
			
		||||
	data1, err := strconv.ParseUint(s[0:8], 16, 32)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return GUID{}, fmt.Errorf("invalid GUID %q", s)
 | 
			
		||||
	}
 | 
			
		||||
	g.Data1 = uint32(data1)
 | 
			
		||||
 | 
			
		||||
	data2, err := strconv.ParseUint(s[9:13], 16, 16)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return GUID{}, fmt.Errorf("invalid GUID %q", s)
 | 
			
		||||
	}
 | 
			
		||||
	g.Data2 = uint16(data2)
 | 
			
		||||
 | 
			
		||||
	data3, err := strconv.ParseUint(s[14:18], 16, 16)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return GUID{}, fmt.Errorf("invalid GUID %q", s)
 | 
			
		||||
	}
 | 
			
		||||
	g.Data3 = uint16(data3)
 | 
			
		||||
 | 
			
		||||
	for i, x := range []int{19, 21, 24, 26, 28, 30, 32, 34} {
 | 
			
		||||
		v, err := strconv.ParseUint(s[x:x+2], 16, 8)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return GUID{}, fmt.Errorf("invalid GUID %q", s)
 | 
			
		||||
		}
 | 
			
		||||
		g.Data4[i] = uint8(v)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return g, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (g *GUID) setVariant(v Variant) {
 | 
			
		||||
	d := g.Data4[0]
 | 
			
		||||
	switch v {
 | 
			
		||||
	case VariantNCS:
 | 
			
		||||
		d = (d & 0x7f)
 | 
			
		||||
	case VariantRFC4122:
 | 
			
		||||
		d = (d & 0x3f) | 0x80
 | 
			
		||||
	case VariantMicrosoft:
 | 
			
		||||
		d = (d & 0x1f) | 0xc0
 | 
			
		||||
	case VariantFuture:
 | 
			
		||||
		d = (d & 0x0f) | 0xe0
 | 
			
		||||
	case VariantUnknown:
 | 
			
		||||
		fallthrough
 | 
			
		||||
	default:
 | 
			
		||||
		panic(fmt.Sprintf("invalid variant: %d", v))
 | 
			
		||||
	}
 | 
			
		||||
	g.Data4[0] = d
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Variant returns the GUID variant, as defined in RFC 4122.
 | 
			
		||||
func (g GUID) Variant() Variant {
 | 
			
		||||
	b := g.Data4[0]
 | 
			
		||||
	if b&0x80 == 0 {
 | 
			
		||||
		return VariantNCS
 | 
			
		||||
	} else if b&0xc0 == 0x80 {
 | 
			
		||||
		return VariantRFC4122
 | 
			
		||||
	} else if b&0xe0 == 0xc0 {
 | 
			
		||||
		return VariantMicrosoft
 | 
			
		||||
	} else if b&0xe0 == 0xe0 {
 | 
			
		||||
		return VariantFuture
 | 
			
		||||
	}
 | 
			
		||||
	return VariantUnknown
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (g *GUID) setVersion(v Version) {
 | 
			
		||||
	g.Data3 = (g.Data3 & 0x0fff) | (uint16(v) << 12)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Version returns the GUID version, as defined in RFC 4122.
 | 
			
		||||
func (g GUID) Version() Version {
 | 
			
		||||
	return Version((g.Data3 & 0xF000) >> 12)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MarshalText returns the textual representation of the GUID.
 | 
			
		||||
func (g GUID) MarshalText() ([]byte, error) {
 | 
			
		||||
	return []byte(g.String()), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UnmarshalText takes the textual representation of a GUID, and unmarhals it
 | 
			
		||||
// into this GUID.
 | 
			
		||||
func (g *GUID) UnmarshalText(text []byte) error {
 | 
			
		||||
	g2, err := FromString(string(text))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	*g = g2
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										15
									
								
								vendor/github.com/Microsoft/go-winio/pkg/guid/guid_nonwindows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								vendor/github.com/Microsoft/go-winio/pkg/guid/guid_nonwindows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
			
		||||
// +build !windows
 | 
			
		||||
 | 
			
		||||
package guid
 | 
			
		||||
 | 
			
		||||
// GUID represents a GUID/UUID. It has the same structure as
 | 
			
		||||
// golang.org/x/sys/windows.GUID so that it can be used with functions expecting
 | 
			
		||||
// that type. It is defined as its own type as that is only available to builds
 | 
			
		||||
// targeted at `windows`. The representation matches that used by native Windows
 | 
			
		||||
// code.
 | 
			
		||||
type GUID struct {
 | 
			
		||||
	Data1 uint32
 | 
			
		||||
	Data2 uint16
 | 
			
		||||
	Data3 uint16
 | 
			
		||||
	Data4 [8]byte
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										10
									
								
								vendor/github.com/Microsoft/go-winio/pkg/guid/guid_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								vendor/github.com/Microsoft/go-winio/pkg/guid/guid_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
package guid
 | 
			
		||||
 | 
			
		||||
import "golang.org/x/sys/windows"
 | 
			
		||||
 | 
			
		||||
// GUID represents a GUID/UUID. It has the same structure as
 | 
			
		||||
// golang.org/x/sys/windows.GUID so that it can be used with functions expecting
 | 
			
		||||
// that type. It is defined as its own type so that stringification and
 | 
			
		||||
// marshaling can be supported. The representation matches that used by native
 | 
			
		||||
// Windows code.
 | 
			
		||||
type GUID windows.GUID
 | 
			
		||||
							
								
								
									
										203
									
								
								vendor/github.com/Microsoft/go-winio/privilege.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										203
									
								
								vendor/github.com/Microsoft/go-winio/privilege.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,203 @@
 | 
			
		||||
// +build windows
 | 
			
		||||
 | 
			
		||||
package winio
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"encoding/binary"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"runtime"
 | 
			
		||||
	"sync"
 | 
			
		||||
	"syscall"
 | 
			
		||||
	"unicode/utf16"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/sys/windows"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
//sys adjustTokenPrivileges(token windows.Token, releaseAll bool, input *byte, outputSize uint32, output *byte, requiredSize *uint32) (success bool, err error) [true] = advapi32.AdjustTokenPrivileges
 | 
			
		||||
//sys impersonateSelf(level uint32) (err error) = advapi32.ImpersonateSelf
 | 
			
		||||
//sys revertToSelf() (err error) = advapi32.RevertToSelf
 | 
			
		||||
//sys openThreadToken(thread syscall.Handle, accessMask uint32, openAsSelf bool, token *windows.Token) (err error) = advapi32.OpenThreadToken
 | 
			
		||||
//sys getCurrentThread() (h syscall.Handle) = GetCurrentThread
 | 
			
		||||
//sys lookupPrivilegeValue(systemName string, name string, luid *uint64) (err error) = advapi32.LookupPrivilegeValueW
 | 
			
		||||
//sys lookupPrivilegeName(systemName string, luid *uint64, buffer *uint16, size *uint32) (err error) = advapi32.LookupPrivilegeNameW
 | 
			
		||||
//sys lookupPrivilegeDisplayName(systemName string, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) = advapi32.LookupPrivilegeDisplayNameW
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	SE_PRIVILEGE_ENABLED = 2
 | 
			
		||||
 | 
			
		||||
	ERROR_NOT_ALL_ASSIGNED syscall.Errno = 1300
 | 
			
		||||
 | 
			
		||||
	SeBackupPrivilege   = "SeBackupPrivilege"
 | 
			
		||||
	SeRestorePrivilege  = "SeRestorePrivilege"
 | 
			
		||||
	SeSecurityPrivilege = "SeSecurityPrivilege"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	securityAnonymous = iota
 | 
			
		||||
	securityIdentification
 | 
			
		||||
	securityImpersonation
 | 
			
		||||
	securityDelegation
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	privNames     = make(map[string]uint64)
 | 
			
		||||
	privNameMutex sync.Mutex
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// PrivilegeError represents an error enabling privileges.
 | 
			
		||||
type PrivilegeError struct {
 | 
			
		||||
	privileges []uint64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e *PrivilegeError) Error() string {
 | 
			
		||||
	s := ""
 | 
			
		||||
	if len(e.privileges) > 1 {
 | 
			
		||||
		s = "Could not enable privileges "
 | 
			
		||||
	} else {
 | 
			
		||||
		s = "Could not enable privilege "
 | 
			
		||||
	}
 | 
			
		||||
	for i, p := range e.privileges {
 | 
			
		||||
		if i != 0 {
 | 
			
		||||
			s += ", "
 | 
			
		||||
		}
 | 
			
		||||
		s += `"`
 | 
			
		||||
		s += getPrivilegeName(p)
 | 
			
		||||
		s += `"`
 | 
			
		||||
	}
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RunWithPrivilege enables a single privilege for a function call.
 | 
			
		||||
func RunWithPrivilege(name string, fn func() error) error {
 | 
			
		||||
	return RunWithPrivileges([]string{name}, fn)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RunWithPrivileges enables privileges for a function call.
 | 
			
		||||
func RunWithPrivileges(names []string, fn func() error) error {
 | 
			
		||||
	privileges, err := mapPrivileges(names)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	runtime.LockOSThread()
 | 
			
		||||
	defer runtime.UnlockOSThread()
 | 
			
		||||
	token, err := newThreadToken()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	defer releaseThreadToken(token)
 | 
			
		||||
	err = adjustPrivileges(token, privileges, SE_PRIVILEGE_ENABLED)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	return fn()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func mapPrivileges(names []string) ([]uint64, error) {
 | 
			
		||||
	var privileges []uint64
 | 
			
		||||
	privNameMutex.Lock()
 | 
			
		||||
	defer privNameMutex.Unlock()
 | 
			
		||||
	for _, name := range names {
 | 
			
		||||
		p, ok := privNames[name]
 | 
			
		||||
		if !ok {
 | 
			
		||||
			err := lookupPrivilegeValue("", name, &p)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
			privNames[name] = p
 | 
			
		||||
		}
 | 
			
		||||
		privileges = append(privileges, p)
 | 
			
		||||
	}
 | 
			
		||||
	return privileges, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// EnableProcessPrivileges enables privileges globally for the process.
 | 
			
		||||
func EnableProcessPrivileges(names []string) error {
 | 
			
		||||
	return enableDisableProcessPrivilege(names, SE_PRIVILEGE_ENABLED)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DisableProcessPrivileges disables privileges globally for the process.
 | 
			
		||||
func DisableProcessPrivileges(names []string) error {
 | 
			
		||||
	return enableDisableProcessPrivilege(names, 0)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func enableDisableProcessPrivilege(names []string, action uint32) error {
 | 
			
		||||
	privileges, err := mapPrivileges(names)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	p, _ := windows.GetCurrentProcess()
 | 
			
		||||
	var token windows.Token
 | 
			
		||||
	err = windows.OpenProcessToken(p, windows.TOKEN_ADJUST_PRIVILEGES|windows.TOKEN_QUERY, &token)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	defer token.Close()
 | 
			
		||||
	return adjustPrivileges(token, privileges, action)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func adjustPrivileges(token windows.Token, privileges []uint64, action uint32) error {
 | 
			
		||||
	var b bytes.Buffer
 | 
			
		||||
	binary.Write(&b, binary.LittleEndian, uint32(len(privileges)))
 | 
			
		||||
	for _, p := range privileges {
 | 
			
		||||
		binary.Write(&b, binary.LittleEndian, p)
 | 
			
		||||
		binary.Write(&b, binary.LittleEndian, action)
 | 
			
		||||
	}
 | 
			
		||||
	prevState := make([]byte, b.Len())
 | 
			
		||||
	reqSize := uint32(0)
 | 
			
		||||
	success, err := adjustTokenPrivileges(token, false, &b.Bytes()[0], uint32(len(prevState)), &prevState[0], &reqSize)
 | 
			
		||||
	if !success {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if err == ERROR_NOT_ALL_ASSIGNED {
 | 
			
		||||
		return &PrivilegeError{privileges}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getPrivilegeName(luid uint64) string {
 | 
			
		||||
	var nameBuffer [256]uint16
 | 
			
		||||
	bufSize := uint32(len(nameBuffer))
 | 
			
		||||
	err := lookupPrivilegeName("", &luid, &nameBuffer[0], &bufSize)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Sprintf("<unknown privilege %d>", luid)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var displayNameBuffer [256]uint16
 | 
			
		||||
	displayBufSize := uint32(len(displayNameBuffer))
 | 
			
		||||
	var langID uint32
 | 
			
		||||
	err = lookupPrivilegeDisplayName("", &nameBuffer[0], &displayNameBuffer[0], &displayBufSize, &langID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Sprintf("<unknown privilege %s>", string(utf16.Decode(nameBuffer[:bufSize])))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return string(utf16.Decode(displayNameBuffer[:displayBufSize]))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newThreadToken() (windows.Token, error) {
 | 
			
		||||
	err := impersonateSelf(securityImpersonation)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var token windows.Token
 | 
			
		||||
	err = openThreadToken(getCurrentThread(), syscall.TOKEN_ADJUST_PRIVILEGES|syscall.TOKEN_QUERY, false, &token)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		rerr := revertToSelf()
 | 
			
		||||
		if rerr != nil {
 | 
			
		||||
			panic(rerr)
 | 
			
		||||
		}
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
	return token, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func releaseThreadToken(h windows.Token) {
 | 
			
		||||
	err := revertToSelf()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
	h.Close()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										128
									
								
								vendor/github.com/Microsoft/go-winio/reparse.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								vendor/github.com/Microsoft/go-winio/reparse.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,128 @@
 | 
			
		||||
package winio
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"encoding/binary"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"unicode/utf16"
 | 
			
		||||
	"unsafe"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	reparseTagMountPoint = 0xA0000003
 | 
			
		||||
	reparseTagSymlink    = 0xA000000C
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type reparseDataBuffer struct {
 | 
			
		||||
	ReparseTag           uint32
 | 
			
		||||
	ReparseDataLength    uint16
 | 
			
		||||
	Reserved             uint16
 | 
			
		||||
	SubstituteNameOffset uint16
 | 
			
		||||
	SubstituteNameLength uint16
 | 
			
		||||
	PrintNameOffset      uint16
 | 
			
		||||
	PrintNameLength      uint16
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ReparsePoint describes a Win32 symlink or mount point.
 | 
			
		||||
type ReparsePoint struct {
 | 
			
		||||
	Target       string
 | 
			
		||||
	IsMountPoint bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UnsupportedReparsePointError is returned when trying to decode a non-symlink or
 | 
			
		||||
// mount point reparse point.
 | 
			
		||||
type UnsupportedReparsePointError struct {
 | 
			
		||||
	Tag uint32
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e *UnsupportedReparsePointError) Error() string {
 | 
			
		||||
	return fmt.Sprintf("unsupported reparse point %x", e.Tag)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DecodeReparsePoint decodes a Win32 REPARSE_DATA_BUFFER structure containing either a symlink
 | 
			
		||||
// or a mount point.
 | 
			
		||||
func DecodeReparsePoint(b []byte) (*ReparsePoint, error) {
 | 
			
		||||
	tag := binary.LittleEndian.Uint32(b[0:4])
 | 
			
		||||
	return DecodeReparsePointData(tag, b[8:])
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func DecodeReparsePointData(tag uint32, b []byte) (*ReparsePoint, error) {
 | 
			
		||||
	isMountPoint := false
 | 
			
		||||
	switch tag {
 | 
			
		||||
	case reparseTagMountPoint:
 | 
			
		||||
		isMountPoint = true
 | 
			
		||||
	case reparseTagSymlink:
 | 
			
		||||
	default:
 | 
			
		||||
		return nil, &UnsupportedReparsePointError{tag}
 | 
			
		||||
	}
 | 
			
		||||
	nameOffset := 8 + binary.LittleEndian.Uint16(b[4:6])
 | 
			
		||||
	if !isMountPoint {
 | 
			
		||||
		nameOffset += 4
 | 
			
		||||
	}
 | 
			
		||||
	nameLength := binary.LittleEndian.Uint16(b[6:8])
 | 
			
		||||
	name := make([]uint16, nameLength/2)
 | 
			
		||||
	err := binary.Read(bytes.NewReader(b[nameOffset:nameOffset+nameLength]), binary.LittleEndian, &name)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return &ReparsePoint{string(utf16.Decode(name)), isMountPoint}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func isDriveLetter(c byte) bool {
 | 
			
		||||
	return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// EncodeReparsePoint encodes a Win32 REPARSE_DATA_BUFFER structure describing a symlink or
 | 
			
		||||
// mount point.
 | 
			
		||||
func EncodeReparsePoint(rp *ReparsePoint) []byte {
 | 
			
		||||
	// Generate an NT path and determine if this is a relative path.
 | 
			
		||||
	var ntTarget string
 | 
			
		||||
	relative := false
 | 
			
		||||
	if strings.HasPrefix(rp.Target, `\\?\`) {
 | 
			
		||||
		ntTarget = `\??\` + rp.Target[4:]
 | 
			
		||||
	} else if strings.HasPrefix(rp.Target, `\\`) {
 | 
			
		||||
		ntTarget = `\??\UNC\` + rp.Target[2:]
 | 
			
		||||
	} else if len(rp.Target) >= 2 && isDriveLetter(rp.Target[0]) && rp.Target[1] == ':' {
 | 
			
		||||
		ntTarget = `\??\` + rp.Target
 | 
			
		||||
	} else {
 | 
			
		||||
		ntTarget = rp.Target
 | 
			
		||||
		relative = true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// The paths must be NUL-terminated even though they are counted strings.
 | 
			
		||||
	target16 := utf16.Encode([]rune(rp.Target + "\x00"))
 | 
			
		||||
	ntTarget16 := utf16.Encode([]rune(ntTarget + "\x00"))
 | 
			
		||||
 | 
			
		||||
	size := int(unsafe.Sizeof(reparseDataBuffer{})) - 8
 | 
			
		||||
	size += len(ntTarget16)*2 + len(target16)*2
 | 
			
		||||
 | 
			
		||||
	tag := uint32(reparseTagMountPoint)
 | 
			
		||||
	if !rp.IsMountPoint {
 | 
			
		||||
		tag = reparseTagSymlink
 | 
			
		||||
		size += 4 // Add room for symlink flags
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	data := reparseDataBuffer{
 | 
			
		||||
		ReparseTag:           tag,
 | 
			
		||||
		ReparseDataLength:    uint16(size),
 | 
			
		||||
		SubstituteNameOffset: 0,
 | 
			
		||||
		SubstituteNameLength: uint16((len(ntTarget16) - 1) * 2),
 | 
			
		||||
		PrintNameOffset:      uint16(len(ntTarget16) * 2),
 | 
			
		||||
		PrintNameLength:      uint16((len(target16) - 1) * 2),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var b bytes.Buffer
 | 
			
		||||
	binary.Write(&b, binary.LittleEndian, &data)
 | 
			
		||||
	if !rp.IsMountPoint {
 | 
			
		||||
		flags := uint32(0)
 | 
			
		||||
		if relative {
 | 
			
		||||
			flags |= 1
 | 
			
		||||
		}
 | 
			
		||||
		binary.Write(&b, binary.LittleEndian, flags)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	binary.Write(&b, binary.LittleEndian, ntTarget16)
 | 
			
		||||
	binary.Write(&b, binary.LittleEndian, target16)
 | 
			
		||||
	return b.Bytes()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										98
									
								
								vendor/github.com/Microsoft/go-winio/sd.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								vendor/github.com/Microsoft/go-winio/sd.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,98 @@
 | 
			
		||||
// +build windows
 | 
			
		||||
 | 
			
		||||
package winio
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"syscall"
 | 
			
		||||
	"unsafe"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
//sys lookupAccountName(systemName *uint16, accountName string, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) = advapi32.LookupAccountNameW
 | 
			
		||||
//sys convertSidToStringSid(sid *byte, str **uint16) (err error) = advapi32.ConvertSidToStringSidW
 | 
			
		||||
//sys convertStringSecurityDescriptorToSecurityDescriptor(str string, revision uint32, sd *uintptr, size *uint32) (err error) = advapi32.ConvertStringSecurityDescriptorToSecurityDescriptorW
 | 
			
		||||
//sys convertSecurityDescriptorToStringSecurityDescriptor(sd *byte, revision uint32, secInfo uint32, sddl **uint16, sddlSize *uint32) (err error) = advapi32.ConvertSecurityDescriptorToStringSecurityDescriptorW
 | 
			
		||||
//sys localFree(mem uintptr) = LocalFree
 | 
			
		||||
//sys getSecurityDescriptorLength(sd uintptr) (len uint32) = advapi32.GetSecurityDescriptorLength
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	cERROR_NONE_MAPPED = syscall.Errno(1332)
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type AccountLookupError struct {
 | 
			
		||||
	Name string
 | 
			
		||||
	Err  error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e *AccountLookupError) Error() string {
 | 
			
		||||
	if e.Name == "" {
 | 
			
		||||
		return "lookup account: empty account name specified"
 | 
			
		||||
	}
 | 
			
		||||
	var s string
 | 
			
		||||
	switch e.Err {
 | 
			
		||||
	case cERROR_NONE_MAPPED:
 | 
			
		||||
		s = "not found"
 | 
			
		||||
	default:
 | 
			
		||||
		s = e.Err.Error()
 | 
			
		||||
	}
 | 
			
		||||
	return "lookup account " + e.Name + ": " + s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type SddlConversionError struct {
 | 
			
		||||
	Sddl string
 | 
			
		||||
	Err  error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e *SddlConversionError) Error() string {
 | 
			
		||||
	return "convert " + e.Sddl + ": " + e.Err.Error()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LookupSidByName looks up the SID of an account by name
 | 
			
		||||
func LookupSidByName(name string) (sid string, err error) {
 | 
			
		||||
	if name == "" {
 | 
			
		||||
		return "", &AccountLookupError{name, cERROR_NONE_MAPPED}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var sidSize, sidNameUse, refDomainSize uint32
 | 
			
		||||
	err = lookupAccountName(nil, name, nil, &sidSize, nil, &refDomainSize, &sidNameUse)
 | 
			
		||||
	if err != nil && err != syscall.ERROR_INSUFFICIENT_BUFFER {
 | 
			
		||||
		return "", &AccountLookupError{name, err}
 | 
			
		||||
	}
 | 
			
		||||
	sidBuffer := make([]byte, sidSize)
 | 
			
		||||
	refDomainBuffer := make([]uint16, refDomainSize)
 | 
			
		||||
	err = lookupAccountName(nil, name, &sidBuffer[0], &sidSize, &refDomainBuffer[0], &refDomainSize, &sidNameUse)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", &AccountLookupError{name, err}
 | 
			
		||||
	}
 | 
			
		||||
	var strBuffer *uint16
 | 
			
		||||
	err = convertSidToStringSid(&sidBuffer[0], &strBuffer)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", &AccountLookupError{name, err}
 | 
			
		||||
	}
 | 
			
		||||
	sid = syscall.UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(strBuffer))[:])
 | 
			
		||||
	localFree(uintptr(unsafe.Pointer(strBuffer)))
 | 
			
		||||
	return sid, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func SddlToSecurityDescriptor(sddl string) ([]byte, error) {
 | 
			
		||||
	var sdBuffer uintptr
 | 
			
		||||
	err := convertStringSecurityDescriptorToSecurityDescriptor(sddl, 1, &sdBuffer, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, &SddlConversionError{sddl, err}
 | 
			
		||||
	}
 | 
			
		||||
	defer localFree(sdBuffer)
 | 
			
		||||
	sd := make([]byte, getSecurityDescriptorLength(sdBuffer))
 | 
			
		||||
	copy(sd, (*[0xffff]byte)(unsafe.Pointer(sdBuffer))[:len(sd)])
 | 
			
		||||
	return sd, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func SecurityDescriptorToSddl(sd []byte) (string, error) {
 | 
			
		||||
	var sddl *uint16
 | 
			
		||||
	// The returned string length seems to including an aribtrary number of terminating NULs.
 | 
			
		||||
	// Don't use it.
 | 
			
		||||
	err := convertSecurityDescriptorToStringSecurityDescriptor(&sd[0], 1, 0xff, &sddl, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
	defer localFree(uintptr(unsafe.Pointer(sddl)))
 | 
			
		||||
	return syscall.UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(sddl))[:]), nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										3
									
								
								vendor/github.com/Microsoft/go-winio/syscall.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								vendor/github.com/Microsoft/go-winio/syscall.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
			
		||||
package winio
 | 
			
		||||
 | 
			
		||||
//go:generate go run golang.org/x/sys/windows/mkwinsyscall -output zsyscall_windows.go file.go pipe.go sd.go fileinfo.go privilege.go backup.go hvsock.go
 | 
			
		||||
							
								
								
									
										427
									
								
								vendor/github.com/Microsoft/go-winio/zsyscall_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										427
									
								
								vendor/github.com/Microsoft/go-winio/zsyscall_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,427 @@
 | 
			
		||||
// Code generated by 'go generate'; DO NOT EDIT.
 | 
			
		||||
 | 
			
		||||
package winio
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"syscall"
 | 
			
		||||
	"unsafe"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/sys/windows"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var _ unsafe.Pointer
 | 
			
		||||
 | 
			
		||||
// Do the interface allocations only once for common
 | 
			
		||||
// Errno values.
 | 
			
		||||
const (
 | 
			
		||||
	errnoERROR_IO_PENDING = 997
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
 | 
			
		||||
	errERROR_EINVAL     error = syscall.EINVAL
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// errnoErr returns common boxed Errno values, to prevent
 | 
			
		||||
// allocations at runtime.
 | 
			
		||||
func errnoErr(e syscall.Errno) error {
 | 
			
		||||
	switch e {
 | 
			
		||||
	case 0:
 | 
			
		||||
		return errERROR_EINVAL
 | 
			
		||||
	case errnoERROR_IO_PENDING:
 | 
			
		||||
		return errERROR_IO_PENDING
 | 
			
		||||
	}
 | 
			
		||||
	// TODO: add more here, after collecting data on the common
 | 
			
		||||
	// error values see on Windows. (perhaps when running
 | 
			
		||||
	// all.bat?)
 | 
			
		||||
	return e
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	modadvapi32 = windows.NewLazySystemDLL("advapi32.dll")
 | 
			
		||||
	modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
 | 
			
		||||
	modntdll    = windows.NewLazySystemDLL("ntdll.dll")
 | 
			
		||||
	modws2_32   = windows.NewLazySystemDLL("ws2_32.dll")
 | 
			
		||||
 | 
			
		||||
	procAdjustTokenPrivileges                                = modadvapi32.NewProc("AdjustTokenPrivileges")
 | 
			
		||||
	procConvertSecurityDescriptorToStringSecurityDescriptorW = modadvapi32.NewProc("ConvertSecurityDescriptorToStringSecurityDescriptorW")
 | 
			
		||||
	procConvertSidToStringSidW                               = modadvapi32.NewProc("ConvertSidToStringSidW")
 | 
			
		||||
	procConvertStringSecurityDescriptorToSecurityDescriptorW = modadvapi32.NewProc("ConvertStringSecurityDescriptorToSecurityDescriptorW")
 | 
			
		||||
	procGetSecurityDescriptorLength                          = modadvapi32.NewProc("GetSecurityDescriptorLength")
 | 
			
		||||
	procImpersonateSelf                                      = modadvapi32.NewProc("ImpersonateSelf")
 | 
			
		||||
	procLookupAccountNameW                                   = modadvapi32.NewProc("LookupAccountNameW")
 | 
			
		||||
	procLookupPrivilegeDisplayNameW                          = modadvapi32.NewProc("LookupPrivilegeDisplayNameW")
 | 
			
		||||
	procLookupPrivilegeNameW                                 = modadvapi32.NewProc("LookupPrivilegeNameW")
 | 
			
		||||
	procLookupPrivilegeValueW                                = modadvapi32.NewProc("LookupPrivilegeValueW")
 | 
			
		||||
	procOpenThreadToken                                      = modadvapi32.NewProc("OpenThreadToken")
 | 
			
		||||
	procRevertToSelf                                         = modadvapi32.NewProc("RevertToSelf")
 | 
			
		||||
	procBackupRead                                           = modkernel32.NewProc("BackupRead")
 | 
			
		||||
	procBackupWrite                                          = modkernel32.NewProc("BackupWrite")
 | 
			
		||||
	procCancelIoEx                                           = modkernel32.NewProc("CancelIoEx")
 | 
			
		||||
	procConnectNamedPipe                                     = modkernel32.NewProc("ConnectNamedPipe")
 | 
			
		||||
	procCreateFileW                                          = modkernel32.NewProc("CreateFileW")
 | 
			
		||||
	procCreateIoCompletionPort                               = modkernel32.NewProc("CreateIoCompletionPort")
 | 
			
		||||
	procCreateNamedPipeW                                     = modkernel32.NewProc("CreateNamedPipeW")
 | 
			
		||||
	procGetCurrentThread                                     = modkernel32.NewProc("GetCurrentThread")
 | 
			
		||||
	procGetNamedPipeHandleStateW                             = modkernel32.NewProc("GetNamedPipeHandleStateW")
 | 
			
		||||
	procGetNamedPipeInfo                                     = modkernel32.NewProc("GetNamedPipeInfo")
 | 
			
		||||
	procGetQueuedCompletionStatus                            = modkernel32.NewProc("GetQueuedCompletionStatus")
 | 
			
		||||
	procLocalAlloc                                           = modkernel32.NewProc("LocalAlloc")
 | 
			
		||||
	procLocalFree                                            = modkernel32.NewProc("LocalFree")
 | 
			
		||||
	procSetFileCompletionNotificationModes                   = modkernel32.NewProc("SetFileCompletionNotificationModes")
 | 
			
		||||
	procNtCreateNamedPipeFile                                = modntdll.NewProc("NtCreateNamedPipeFile")
 | 
			
		||||
	procRtlDefaultNpAcl                                      = modntdll.NewProc("RtlDefaultNpAcl")
 | 
			
		||||
	procRtlDosPathNameToNtPathName_U                         = modntdll.NewProc("RtlDosPathNameToNtPathName_U")
 | 
			
		||||
	procRtlNtStatusToDosErrorNoTeb                           = modntdll.NewProc("RtlNtStatusToDosErrorNoTeb")
 | 
			
		||||
	procWSAGetOverlappedResult                               = modws2_32.NewProc("WSAGetOverlappedResult")
 | 
			
		||||
	procbind                                                 = modws2_32.NewProc("bind")
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func adjustTokenPrivileges(token windows.Token, releaseAll bool, input *byte, outputSize uint32, output *byte, requiredSize *uint32) (success bool, err error) {
 | 
			
		||||
	var _p0 uint32
 | 
			
		||||
	if releaseAll {
 | 
			
		||||
		_p0 = 1
 | 
			
		||||
	}
 | 
			
		||||
	r0, _, e1 := syscall.Syscall6(procAdjustTokenPrivileges.Addr(), 6, uintptr(token), uintptr(_p0), uintptr(unsafe.Pointer(input)), uintptr(outputSize), uintptr(unsafe.Pointer(output)), uintptr(unsafe.Pointer(requiredSize)))
 | 
			
		||||
	success = r0 != 0
 | 
			
		||||
	if true {
 | 
			
		||||
		err = errnoErr(e1)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func convertSecurityDescriptorToStringSecurityDescriptor(sd *byte, revision uint32, secInfo uint32, sddl **uint16, sddlSize *uint32) (err error) {
 | 
			
		||||
	r1, _, e1 := syscall.Syscall6(procConvertSecurityDescriptorToStringSecurityDescriptorW.Addr(), 5, uintptr(unsafe.Pointer(sd)), uintptr(revision), uintptr(secInfo), uintptr(unsafe.Pointer(sddl)), uintptr(unsafe.Pointer(sddlSize)), 0)
 | 
			
		||||
	if r1 == 0 {
 | 
			
		||||
		err = errnoErr(e1)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func convertSidToStringSid(sid *byte, str **uint16) (err error) {
 | 
			
		||||
	r1, _, e1 := syscall.Syscall(procConvertSidToStringSidW.Addr(), 2, uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(str)), 0)
 | 
			
		||||
	if r1 == 0 {
 | 
			
		||||
		err = errnoErr(e1)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func convertStringSecurityDescriptorToSecurityDescriptor(str string, revision uint32, sd *uintptr, size *uint32) (err error) {
 | 
			
		||||
	var _p0 *uint16
 | 
			
		||||
	_p0, err = syscall.UTF16PtrFromString(str)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	return _convertStringSecurityDescriptorToSecurityDescriptor(_p0, revision, sd, size)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func _convertStringSecurityDescriptorToSecurityDescriptor(str *uint16, revision uint32, sd *uintptr, size *uint32) (err error) {
 | 
			
		||||
	r1, _, e1 := syscall.Syscall6(procConvertStringSecurityDescriptorToSecurityDescriptorW.Addr(), 4, uintptr(unsafe.Pointer(str)), uintptr(revision), uintptr(unsafe.Pointer(sd)), uintptr(unsafe.Pointer(size)), 0, 0)
 | 
			
		||||
	if r1 == 0 {
 | 
			
		||||
		err = errnoErr(e1)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getSecurityDescriptorLength(sd uintptr) (len uint32) {
 | 
			
		||||
	r0, _, _ := syscall.Syscall(procGetSecurityDescriptorLength.Addr(), 1, uintptr(sd), 0, 0)
 | 
			
		||||
	len = uint32(r0)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func impersonateSelf(level uint32) (err error) {
 | 
			
		||||
	r1, _, e1 := syscall.Syscall(procImpersonateSelf.Addr(), 1, uintptr(level), 0, 0)
 | 
			
		||||
	if r1 == 0 {
 | 
			
		||||
		err = errnoErr(e1)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func lookupAccountName(systemName *uint16, accountName string, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) {
 | 
			
		||||
	var _p0 *uint16
 | 
			
		||||
	_p0, err = syscall.UTF16PtrFromString(accountName)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	return _lookupAccountName(systemName, _p0, sid, sidSize, refDomain, refDomainSize, sidNameUse)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func _lookupAccountName(systemName *uint16, accountName *uint16, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) {
 | 
			
		||||
	r1, _, e1 := syscall.Syscall9(procLookupAccountNameW.Addr(), 7, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(accountName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(sidSize)), uintptr(unsafe.Pointer(refDomain)), uintptr(unsafe.Pointer(refDomainSize)), uintptr(unsafe.Pointer(sidNameUse)), 0, 0)
 | 
			
		||||
	if r1 == 0 {
 | 
			
		||||
		err = errnoErr(e1)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func lookupPrivilegeDisplayName(systemName string, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) {
 | 
			
		||||
	var _p0 *uint16
 | 
			
		||||
	_p0, err = syscall.UTF16PtrFromString(systemName)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	return _lookupPrivilegeDisplayName(_p0, name, buffer, size, languageId)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func _lookupPrivilegeDisplayName(systemName *uint16, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) {
 | 
			
		||||
	r1, _, e1 := syscall.Syscall6(procLookupPrivilegeDisplayNameW.Addr(), 5, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(buffer)), uintptr(unsafe.Pointer(size)), uintptr(unsafe.Pointer(languageId)), 0)
 | 
			
		||||
	if r1 == 0 {
 | 
			
		||||
		err = errnoErr(e1)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func lookupPrivilegeName(systemName string, luid *uint64, buffer *uint16, size *uint32) (err error) {
 | 
			
		||||
	var _p0 *uint16
 | 
			
		||||
	_p0, err = syscall.UTF16PtrFromString(systemName)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	return _lookupPrivilegeName(_p0, luid, buffer, size)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func _lookupPrivilegeName(systemName *uint16, luid *uint64, buffer *uint16, size *uint32) (err error) {
 | 
			
		||||
	r1, _, e1 := syscall.Syscall6(procLookupPrivilegeNameW.Addr(), 4, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(luid)), uintptr(unsafe.Pointer(buffer)), uintptr(unsafe.Pointer(size)), 0, 0)
 | 
			
		||||
	if r1 == 0 {
 | 
			
		||||
		err = errnoErr(e1)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func lookupPrivilegeValue(systemName string, name string, luid *uint64) (err error) {
 | 
			
		||||
	var _p0 *uint16
 | 
			
		||||
	_p0, err = syscall.UTF16PtrFromString(systemName)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	var _p1 *uint16
 | 
			
		||||
	_p1, err = syscall.UTF16PtrFromString(name)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	return _lookupPrivilegeValue(_p0, _p1, luid)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func _lookupPrivilegeValue(systemName *uint16, name *uint16, luid *uint64) (err error) {
 | 
			
		||||
	r1, _, e1 := syscall.Syscall(procLookupPrivilegeValueW.Addr(), 3, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(luid)))
 | 
			
		||||
	if r1 == 0 {
 | 
			
		||||
		err = errnoErr(e1)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func openThreadToken(thread syscall.Handle, accessMask uint32, openAsSelf bool, token *windows.Token) (err error) {
 | 
			
		||||
	var _p0 uint32
 | 
			
		||||
	if openAsSelf {
 | 
			
		||||
		_p0 = 1
 | 
			
		||||
	}
 | 
			
		||||
	r1, _, e1 := syscall.Syscall6(procOpenThreadToken.Addr(), 4, uintptr(thread), uintptr(accessMask), uintptr(_p0), uintptr(unsafe.Pointer(token)), 0, 0)
 | 
			
		||||
	if r1 == 0 {
 | 
			
		||||
		err = errnoErr(e1)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func revertToSelf() (err error) {
 | 
			
		||||
	r1, _, e1 := syscall.Syscall(procRevertToSelf.Addr(), 0, 0, 0, 0)
 | 
			
		||||
	if r1 == 0 {
 | 
			
		||||
		err = errnoErr(e1)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func backupRead(h syscall.Handle, b []byte, bytesRead *uint32, abort bool, processSecurity bool, context *uintptr) (err error) {
 | 
			
		||||
	var _p0 *byte
 | 
			
		||||
	if len(b) > 0 {
 | 
			
		||||
		_p0 = &b[0]
 | 
			
		||||
	}
 | 
			
		||||
	var _p1 uint32
 | 
			
		||||
	if abort {
 | 
			
		||||
		_p1 = 1
 | 
			
		||||
	}
 | 
			
		||||
	var _p2 uint32
 | 
			
		||||
	if processSecurity {
 | 
			
		||||
		_p2 = 1
 | 
			
		||||
	}
 | 
			
		||||
	r1, _, e1 := syscall.Syscall9(procBackupRead.Addr(), 7, uintptr(h), uintptr(unsafe.Pointer(_p0)), uintptr(len(b)), uintptr(unsafe.Pointer(bytesRead)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(context)), 0, 0)
 | 
			
		||||
	if r1 == 0 {
 | 
			
		||||
		err = errnoErr(e1)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func backupWrite(h syscall.Handle, b []byte, bytesWritten *uint32, abort bool, processSecurity bool, context *uintptr) (err error) {
 | 
			
		||||
	var _p0 *byte
 | 
			
		||||
	if len(b) > 0 {
 | 
			
		||||
		_p0 = &b[0]
 | 
			
		||||
	}
 | 
			
		||||
	var _p1 uint32
 | 
			
		||||
	if abort {
 | 
			
		||||
		_p1 = 1
 | 
			
		||||
	}
 | 
			
		||||
	var _p2 uint32
 | 
			
		||||
	if processSecurity {
 | 
			
		||||
		_p2 = 1
 | 
			
		||||
	}
 | 
			
		||||
	r1, _, e1 := syscall.Syscall9(procBackupWrite.Addr(), 7, uintptr(h), uintptr(unsafe.Pointer(_p0)), uintptr(len(b)), uintptr(unsafe.Pointer(bytesWritten)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(context)), 0, 0)
 | 
			
		||||
	if r1 == 0 {
 | 
			
		||||
		err = errnoErr(e1)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func cancelIoEx(file syscall.Handle, o *syscall.Overlapped) (err error) {
 | 
			
		||||
	r1, _, e1 := syscall.Syscall(procCancelIoEx.Addr(), 2, uintptr(file), uintptr(unsafe.Pointer(o)), 0)
 | 
			
		||||
	if r1 == 0 {
 | 
			
		||||
		err = errnoErr(e1)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) {
 | 
			
		||||
	r1, _, e1 := syscall.Syscall(procConnectNamedPipe.Addr(), 2, uintptr(pipe), uintptr(unsafe.Pointer(o)), 0)
 | 
			
		||||
	if r1 == 0 {
 | 
			
		||||
		err = errnoErr(e1)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func createFile(name string, access uint32, mode uint32, sa *syscall.SecurityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) {
 | 
			
		||||
	var _p0 *uint16
 | 
			
		||||
	_p0, err = syscall.UTF16PtrFromString(name)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	return _createFile(_p0, access, mode, sa, createmode, attrs, templatefile)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func _createFile(name *uint16, access uint32, mode uint32, sa *syscall.SecurityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) {
 | 
			
		||||
	r0, _, e1 := syscall.Syscall9(procCreateFileW.Addr(), 7, uintptr(unsafe.Pointer(name)), uintptr(access), uintptr(mode), uintptr(unsafe.Pointer(sa)), uintptr(createmode), uintptr(attrs), uintptr(templatefile), 0, 0)
 | 
			
		||||
	handle = syscall.Handle(r0)
 | 
			
		||||
	if handle == syscall.InvalidHandle {
 | 
			
		||||
		err = errnoErr(e1)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func createIoCompletionPort(file syscall.Handle, port syscall.Handle, key uintptr, threadCount uint32) (newport syscall.Handle, err error) {
 | 
			
		||||
	r0, _, e1 := syscall.Syscall6(procCreateIoCompletionPort.Addr(), 4, uintptr(file), uintptr(port), uintptr(key), uintptr(threadCount), 0, 0)
 | 
			
		||||
	newport = syscall.Handle(r0)
 | 
			
		||||
	if newport == 0 {
 | 
			
		||||
		err = errnoErr(e1)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *syscall.SecurityAttributes) (handle syscall.Handle, err error) {
 | 
			
		||||
	var _p0 *uint16
 | 
			
		||||
	_p0, err = syscall.UTF16PtrFromString(name)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	return _createNamedPipe(_p0, flags, pipeMode, maxInstances, outSize, inSize, defaultTimeout, sa)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func _createNamedPipe(name *uint16, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *syscall.SecurityAttributes) (handle syscall.Handle, err error) {
 | 
			
		||||
	r0, _, e1 := syscall.Syscall9(procCreateNamedPipeW.Addr(), 8, uintptr(unsafe.Pointer(name)), uintptr(flags), uintptr(pipeMode), uintptr(maxInstances), uintptr(outSize), uintptr(inSize), uintptr(defaultTimeout), uintptr(unsafe.Pointer(sa)), 0)
 | 
			
		||||
	handle = syscall.Handle(r0)
 | 
			
		||||
	if handle == syscall.InvalidHandle {
 | 
			
		||||
		err = errnoErr(e1)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getCurrentThread() (h syscall.Handle) {
 | 
			
		||||
	r0, _, _ := syscall.Syscall(procGetCurrentThread.Addr(), 0, 0, 0, 0)
 | 
			
		||||
	h = syscall.Handle(r0)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getNamedPipeHandleState(pipe syscall.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) {
 | 
			
		||||
	r1, _, e1 := syscall.Syscall9(procGetNamedPipeHandleStateW.Addr(), 7, uintptr(pipe), uintptr(unsafe.Pointer(state)), uintptr(unsafe.Pointer(curInstances)), uintptr(unsafe.Pointer(maxCollectionCount)), uintptr(unsafe.Pointer(collectDataTimeout)), uintptr(unsafe.Pointer(userName)), uintptr(maxUserNameSize), 0, 0)
 | 
			
		||||
	if r1 == 0 {
 | 
			
		||||
		err = errnoErr(e1)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getNamedPipeInfo(pipe syscall.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) {
 | 
			
		||||
	r1, _, e1 := syscall.Syscall6(procGetNamedPipeInfo.Addr(), 5, uintptr(pipe), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(outSize)), uintptr(unsafe.Pointer(inSize)), uintptr(unsafe.Pointer(maxInstances)), 0)
 | 
			
		||||
	if r1 == 0 {
 | 
			
		||||
		err = errnoErr(e1)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getQueuedCompletionStatus(port syscall.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) {
 | 
			
		||||
	r1, _, e1 := syscall.Syscall6(procGetQueuedCompletionStatus.Addr(), 5, uintptr(port), uintptr(unsafe.Pointer(bytes)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(o)), uintptr(timeout), 0)
 | 
			
		||||
	if r1 == 0 {
 | 
			
		||||
		err = errnoErr(e1)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func localAlloc(uFlags uint32, length uint32) (ptr uintptr) {
 | 
			
		||||
	r0, _, _ := syscall.Syscall(procLocalAlloc.Addr(), 2, uintptr(uFlags), uintptr(length), 0)
 | 
			
		||||
	ptr = uintptr(r0)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func localFree(mem uintptr) {
 | 
			
		||||
	syscall.Syscall(procLocalFree.Addr(), 1, uintptr(mem), 0, 0)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func setFileCompletionNotificationModes(h syscall.Handle, flags uint8) (err error) {
 | 
			
		||||
	r1, _, e1 := syscall.Syscall(procSetFileCompletionNotificationModes.Addr(), 2, uintptr(h), uintptr(flags), 0)
 | 
			
		||||
	if r1 == 0 {
 | 
			
		||||
		err = errnoErr(e1)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ntCreateNamedPipeFile(pipe *syscall.Handle, access uint32, oa *objectAttributes, iosb *ioStatusBlock, share uint32, disposition uint32, options uint32, typ uint32, readMode uint32, completionMode uint32, maxInstances uint32, inboundQuota uint32, outputQuota uint32, timeout *int64) (status ntstatus) {
 | 
			
		||||
	r0, _, _ := syscall.Syscall15(procNtCreateNamedPipeFile.Addr(), 14, uintptr(unsafe.Pointer(pipe)), uintptr(access), uintptr(unsafe.Pointer(oa)), uintptr(unsafe.Pointer(iosb)), uintptr(share), uintptr(disposition), uintptr(options), uintptr(typ), uintptr(readMode), uintptr(completionMode), uintptr(maxInstances), uintptr(inboundQuota), uintptr(outputQuota), uintptr(unsafe.Pointer(timeout)), 0)
 | 
			
		||||
	status = ntstatus(r0)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func rtlDefaultNpAcl(dacl *uintptr) (status ntstatus) {
 | 
			
		||||
	r0, _, _ := syscall.Syscall(procRtlDefaultNpAcl.Addr(), 1, uintptr(unsafe.Pointer(dacl)), 0, 0)
 | 
			
		||||
	status = ntstatus(r0)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func rtlDosPathNameToNtPathName(name *uint16, ntName *unicodeString, filePart uintptr, reserved uintptr) (status ntstatus) {
 | 
			
		||||
	r0, _, _ := syscall.Syscall6(procRtlDosPathNameToNtPathName_U.Addr(), 4, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(ntName)), uintptr(filePart), uintptr(reserved), 0, 0)
 | 
			
		||||
	status = ntstatus(r0)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func rtlNtStatusToDosError(status ntstatus) (winerr error) {
 | 
			
		||||
	r0, _, _ := syscall.Syscall(procRtlNtStatusToDosErrorNoTeb.Addr(), 1, uintptr(status), 0, 0)
 | 
			
		||||
	if r0 != 0 {
 | 
			
		||||
		winerr = syscall.Errno(r0)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func wsaGetOverlappedResult(h syscall.Handle, o *syscall.Overlapped, bytes *uint32, wait bool, flags *uint32) (err error) {
 | 
			
		||||
	var _p0 uint32
 | 
			
		||||
	if wait {
 | 
			
		||||
		_p0 = 1
 | 
			
		||||
	}
 | 
			
		||||
	r1, _, e1 := syscall.Syscall6(procWSAGetOverlappedResult.Addr(), 5, uintptr(h), uintptr(unsafe.Pointer(o)), uintptr(unsafe.Pointer(bytes)), uintptr(_p0), uintptr(unsafe.Pointer(flags)), 0)
 | 
			
		||||
	if r1 == 0 {
 | 
			
		||||
		err = errnoErr(e1)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func bind(s syscall.Handle, name unsafe.Pointer, namelen int32) (err error) {
 | 
			
		||||
	r1, _, e1 := syscall.Syscall(procbind.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen))
 | 
			
		||||
	if r1 == socketError {
 | 
			
		||||
		err = errnoErr(e1)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										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 environments where timing attacks are a concern.
 | 
			
		||||
package brainpool
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/elliptic"
 | 
			
		||||
	"math/big"
 | 
			
		||||
	"sync"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	once                   sync.Once
 | 
			
		||||
	p256t1, p384t1, p512t1 *elliptic.CurveParams
 | 
			
		||||
	p256r1, p384r1, p512r1 *rcurve
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func initAll() {
 | 
			
		||||
	initP256t1()
 | 
			
		||||
	initP384t1()
 | 
			
		||||
	initP512t1()
 | 
			
		||||
	initP256r1()
 | 
			
		||||
	initP384r1()
 | 
			
		||||
	initP512r1()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func initP256t1() {
 | 
			
		||||
	p256t1 = &elliptic.CurveParams{Name: "brainpoolP256t1"}
 | 
			
		||||
	p256t1.P, _ = new(big.Int).SetString("A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377", 16)
 | 
			
		||||
	p256t1.N, _ = new(big.Int).SetString("A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7", 16)
 | 
			
		||||
	p256t1.B, _ = new(big.Int).SetString("662C61C430D84EA4FE66A7733D0B76B7BF93EBC4AF2F49256AE58101FEE92B04", 16)
 | 
			
		||||
	p256t1.Gx, _ = new(big.Int).SetString("A3E8EB3CC1CFE7B7732213B23A656149AFA142C47AAFBC2B79A191562E1305F4", 16)
 | 
			
		||||
	p256t1.Gy, _ = new(big.Int).SetString("2D996C823439C56D7F7B22E14644417E69BCB6DE39D027001DABE8F35B25C9BE", 16)
 | 
			
		||||
	p256t1.BitSize = 256
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func initP256r1() {
 | 
			
		||||
	twisted := p256t1
 | 
			
		||||
	params := &elliptic.CurveParams{
 | 
			
		||||
		Name:    "brainpoolP256r1",
 | 
			
		||||
		P:       twisted.P,
 | 
			
		||||
		N:       twisted.N,
 | 
			
		||||
		BitSize: twisted.BitSize,
 | 
			
		||||
	}
 | 
			
		||||
	params.Gx, _ = new(big.Int).SetString("8BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262", 16)
 | 
			
		||||
	params.Gy, _ = new(big.Int).SetString("547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997", 16)
 | 
			
		||||
	z, _ := new(big.Int).SetString("3E2D4BD9597B58639AE7AA669CAB9837CF5CF20A2C852D10F655668DFC150EF0", 16)
 | 
			
		||||
	p256r1 = newrcurve(twisted, params, z)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func initP384t1() {
 | 
			
		||||
	p384t1 = &elliptic.CurveParams{Name: "brainpoolP384t1"}
 | 
			
		||||
	p384t1.P, _ = new(big.Int).SetString("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC53", 16)
 | 
			
		||||
	p384t1.N, _ = new(big.Int).SetString("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC3103B883202E9046565", 16)
 | 
			
		||||
	p384t1.B, _ = new(big.Int).SetString("7F519EADA7BDA81BD826DBA647910F8C4B9346ED8CCDC64E4B1ABD11756DCE1D2074AA263B88805CED70355A33B471EE", 16)
 | 
			
		||||
	p384t1.Gx, _ = new(big.Int).SetString("18DE98B02DB9A306F2AFCD7235F72A819B80AB12EBD653172476FECD462AABFFC4FF191B946A5F54D8D0AA2F418808CC", 16)
 | 
			
		||||
	p384t1.Gy, _ = new(big.Int).SetString("25AB056962D30651A114AFD2755AD336747F93475B7A1FCA3B88F2B6A208CCFE469408584DC2B2912675BF5B9E582928", 16)
 | 
			
		||||
	p384t1.BitSize = 384
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func initP384r1() {
 | 
			
		||||
	twisted := p384t1
 | 
			
		||||
	params := &elliptic.CurveParams{
 | 
			
		||||
		Name:    "brainpoolP384r1",
 | 
			
		||||
		P:       twisted.P,
 | 
			
		||||
		N:       twisted.N,
 | 
			
		||||
		BitSize: twisted.BitSize,
 | 
			
		||||
	}
 | 
			
		||||
	params.Gx, _ = new(big.Int).SetString("1D1C64F068CF45FFA2A63A81B7C13F6B8847A3E77EF14FE3DB7FCAFE0CBD10E8E826E03436D646AAEF87B2E247D4AF1E", 16)
 | 
			
		||||
	params.Gy, _ = new(big.Int).SetString("8ABE1D7520F9C2A45CB1EB8E95CFD55262B70B29FEEC5864E19C054FF99129280E4646217791811142820341263C5315", 16)
 | 
			
		||||
	z, _ := new(big.Int).SetString("41DFE8DD399331F7166A66076734A89CD0D2BCDB7D068E44E1F378F41ECBAE97D2D63DBC87BCCDDCCC5DA39E8589291C", 16)
 | 
			
		||||
	p384r1 = newrcurve(twisted, params, z)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func initP512t1() {
 | 
			
		||||
	p512t1 = &elliptic.CurveParams{Name: "brainpoolP512t1"}
 | 
			
		||||
	p512t1.P, _ = new(big.Int).SetString("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3", 16)
 | 
			
		||||
	p512t1.N, _ = new(big.Int).SetString("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069", 16)
 | 
			
		||||
	p512t1.B, _ = new(big.Int).SetString("7CBBBCF9441CFAB76E1890E46884EAE321F70C0BCB4981527897504BEC3E36A62BCDFA2304976540F6450085F2DAE145C22553B465763689180EA2571867423E", 16)
 | 
			
		||||
	p512t1.Gx, _ = new(big.Int).SetString("640ECE5C12788717B9C1BA06CBC2A6FEBA85842458C56DDE9DB1758D39C0313D82BA51735CDB3EA499AA77A7D6943A64F7A3F25FE26F06B51BAA2696FA9035DA", 16)
 | 
			
		||||
	p512t1.Gy, _ = new(big.Int).SetString("5B534BD595F5AF0FA2C892376C84ACE1BB4E3019B71634C01131159CAE03CEE9D9932184BEEF216BD71DF2DADF86A627306ECFF96DBB8BACE198B61E00F8B332", 16)
 | 
			
		||||
	p512t1.BitSize = 512
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func initP512r1() {
 | 
			
		||||
	twisted := p512t1
 | 
			
		||||
	params := &elliptic.CurveParams{
 | 
			
		||||
		Name:    "brainpoolP512r1",
 | 
			
		||||
		P:       twisted.P,
 | 
			
		||||
		N:       twisted.N,
 | 
			
		||||
		BitSize: twisted.BitSize,
 | 
			
		||||
	}
 | 
			
		||||
	params.Gx, _ = new(big.Int).SetString("81AEE4BDD82ED9645A21322E9C4C6A9385ED9F70B5D916C1B43B62EEF4D0098EFF3B1F78E2D0D48D50D1687B93B97D5F7C6D5047406A5E688B352209BCB9F822", 16)
 | 
			
		||||
	params.Gy, _ = new(big.Int).SetString("7DDE385D566332ECC0EABFA9CF7822FDF209F70024A57B1AA000C55B881F8111B2DCDE494A5F485E5BCA4BD88A2763AED1CA2B2FA8F0540678CD1E0F3AD80892", 16)
 | 
			
		||||
	z, _ := new(big.Int).SetString("12EE58E6764838B69782136F0F2D3BA06E27695716054092E60A80BEDB212B64E585D90BCE13761F85C3F1D2A64E3BE8FEA2220F01EBA5EEB0F35DBD29D922AB", 16)
 | 
			
		||||
	p512r1 = newrcurve(twisted, params, z)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// P256t1 returns a Curve which implements Brainpool P256t1 (see RFC 5639, section 3.4)
 | 
			
		||||
func P256t1() elliptic.Curve {
 | 
			
		||||
	once.Do(initAll)
 | 
			
		||||
	return p256t1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// P256r1 returns a Curve which implements Brainpool P256r1 (see RFC 5639, section 3.4)
 | 
			
		||||
func P256r1() elliptic.Curve {
 | 
			
		||||
	once.Do(initAll)
 | 
			
		||||
	return p256r1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// P384t1 returns a Curve which implements Brainpool P384t1 (see RFC 5639, section 3.6)
 | 
			
		||||
func P384t1() elliptic.Curve {
 | 
			
		||||
	once.Do(initAll)
 | 
			
		||||
	return p384t1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// P384r1 returns a Curve which implements Brainpool P384r1 (see RFC 5639, section 3.6)
 | 
			
		||||
func P384r1() elliptic.Curve {
 | 
			
		||||
	once.Do(initAll)
 | 
			
		||||
	return p384r1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// P512t1 returns a Curve which implements Brainpool P512t1 (see RFC 5639, section 3.7)
 | 
			
		||||
func P512t1() elliptic.Curve {
 | 
			
		||||
	once.Do(initAll)
 | 
			
		||||
	return p512t1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// P512r1 returns a Curve which implements Brainpool P512r1 (see RFC 5639, section 3.7)
 | 
			
		||||
func P512r1() elliptic.Curve {
 | 
			
		||||
	once.Do(initAll)
 | 
			
		||||
	return p512r1
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										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 across tests.
 | 
			
		||||
var testKey, _ = hex.DecodeString("000102030405060708090A0B0C0D0E0F")
 | 
			
		||||
 | 
			
		||||
var rfc7253testVectors = []struct {
 | 
			
		||||
	nonce, header, plaintext, ciphertext string
 | 
			
		||||
}{
 | 
			
		||||
	{"BBAA99887766554433221100",
 | 
			
		||||
		"",
 | 
			
		||||
		"",
 | 
			
		||||
		"785407BFFFC8AD9EDCC5520AC9111EE6"},
 | 
			
		||||
	{"BBAA99887766554433221101",
 | 
			
		||||
		"0001020304050607",
 | 
			
		||||
		"0001020304050607",
 | 
			
		||||
		"6820B3657B6F615A5725BDA0D3B4EB3A257C9AF1F8F03009"},
 | 
			
		||||
	{"BBAA99887766554433221102",
 | 
			
		||||
		"0001020304050607",
 | 
			
		||||
		"",
 | 
			
		||||
		"81017F8203F081277152FADE694A0A00"},
 | 
			
		||||
	{"BBAA99887766554433221103",
 | 
			
		||||
		"",
 | 
			
		||||
		"0001020304050607",
 | 
			
		||||
		"45DD69F8F5AAE72414054CD1F35D82760B2CD00D2F99BFA9"},
 | 
			
		||||
	{"BBAA99887766554433221104",
 | 
			
		||||
		"000102030405060708090A0B0C0D0E0F",
 | 
			
		||||
		"000102030405060708090A0B0C0D0E0F",
 | 
			
		||||
		"571D535B60B277188BE5147170A9A22C3AD7A4FF3835B8C5701C1CCEC8FC3358"},
 | 
			
		||||
	{"BBAA99887766554433221105",
 | 
			
		||||
		"000102030405060708090A0B0C0D0E0F",
 | 
			
		||||
		"",
 | 
			
		||||
		"8CF761B6902EF764462AD86498CA6B97"},
 | 
			
		||||
	{"BBAA99887766554433221106",
 | 
			
		||||
		"",
 | 
			
		||||
		"000102030405060708090A0B0C0D0E0F",
 | 
			
		||||
		"5CE88EC2E0692706A915C00AEB8B2396F40E1C743F52436BDF06D8FA1ECA343D"},
 | 
			
		||||
	{"BBAA99887766554433221107",
 | 
			
		||||
		"000102030405060708090A0B0C0D0E0F1011121314151617",
 | 
			
		||||
		"000102030405060708090A0B0C0D0E0F1011121314151617",
 | 
			
		||||
		"1CA2207308C87C010756104D8840CE1952F09673A448A122C92C62241051F57356D7F3C90BB0E07F"},
 | 
			
		||||
	{"BBAA99887766554433221108",
 | 
			
		||||
		"000102030405060708090A0B0C0D0E0F1011121314151617",
 | 
			
		||||
		"",
 | 
			
		||||
		"6DC225A071FC1B9F7C69F93B0F1E10DE"},
 | 
			
		||||
	{"BBAA99887766554433221109",
 | 
			
		||||
		"",
 | 
			
		||||
		"000102030405060708090A0B0C0D0E0F1011121314151617",
 | 
			
		||||
		"221BD0DE7FA6FE993ECCD769460A0AF2D6CDED0C395B1C3CE725F32494B9F914D85C0B1EB38357FF"},
 | 
			
		||||
	{"BBAA9988776655443322110A",
 | 
			
		||||
		"000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F",
 | 
			
		||||
		"000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F",
 | 
			
		||||
		"BD6F6C496201C69296C11EFD138A467ABD3C707924B964DEAFFC40319AF5A48540FBBA186C5553C68AD9F592A79A4240"},
 | 
			
		||||
	{"BBAA9988776655443322110B",
 | 
			
		||||
		"000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F",
 | 
			
		||||
		"",
 | 
			
		||||
		"FE80690BEE8A485D11F32965BC9D2A32"},
 | 
			
		||||
	{"BBAA9988776655443322110C",
 | 
			
		||||
		"",
 | 
			
		||||
		"000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F",
 | 
			
		||||
		"2942BFC773BDA23CABC6ACFD9BFD5835BD300F0973792EF46040C53F1432BCDFB5E1DDE3BC18A5F840B52E653444D5DF"},
 | 
			
		||||
	{"BBAA9988776655443322110D",
 | 
			
		||||
		"000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627",
 | 
			
		||||
		"000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627",
 | 
			
		||||
		"D5CA91748410C1751FF8A2F618255B68A0A12E093FF454606E59F9C1D0DDC54B65E8628E568BAD7AED07BA06A4A69483A7035490C5769E60"},
 | 
			
		||||
	{"BBAA9988776655443322110E",
 | 
			
		||||
		"000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627",
 | 
			
		||||
		"",
 | 
			
		||||
		"C5CD9D1850C141E358649994EE701B68"},
 | 
			
		||||
	{"BBAA9988776655443322110F",
 | 
			
		||||
		"",
 | 
			
		||||
		"000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627",
 | 
			
		||||
		"4412923493C57D5DE0D700F753CCE0D1D2D95060122E9F15A5DDBFC5787E50B5CC55EE507BCB084E479AD363AC366B95A98CA5F3000B1479"},
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										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
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										224
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/armor/armor.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										224
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/armor/armor.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,224 @@
 | 
			
		||||
// Copyright 2010 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
// Package armor implements OpenPGP ASCII Armor, see RFC 4880. OpenPGP Armor is
 | 
			
		||||
// very similar to PEM except that it has an additional CRC checksum.
 | 
			
		||||
package armor // import "github.com/ProtonMail/go-crypto/openpgp/armor"
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bufio"
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"encoding/base64"
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/openpgp/errors"
 | 
			
		||||
	"io"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// A Block represents an OpenPGP armored structure.
 | 
			
		||||
//
 | 
			
		||||
// The encoded form is:
 | 
			
		||||
//    -----BEGIN Type-----
 | 
			
		||||
//    Headers
 | 
			
		||||
//
 | 
			
		||||
//    base64-encoded Bytes
 | 
			
		||||
//    '=' base64 encoded checksum
 | 
			
		||||
//    -----END Type-----
 | 
			
		||||
// where Headers is a possibly empty sequence of Key: Value lines.
 | 
			
		||||
//
 | 
			
		||||
// Since the armored data can be very large, this package presents a streaming
 | 
			
		||||
// interface.
 | 
			
		||||
type Block struct {
 | 
			
		||||
	Type    string            // The type, taken from the preamble (i.e. "PGP SIGNATURE").
 | 
			
		||||
	Header  map[string]string // Optional headers.
 | 
			
		||||
	Body    io.Reader         // A Reader from which the contents can be read
 | 
			
		||||
	lReader lineReader
 | 
			
		||||
	oReader openpgpReader
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var ArmorCorrupt error = errors.StructuralError("armor invalid")
 | 
			
		||||
 | 
			
		||||
const crc24Init = 0xb704ce
 | 
			
		||||
const crc24Poly = 0x1864cfb
 | 
			
		||||
const crc24Mask = 0xffffff
 | 
			
		||||
 | 
			
		||||
// crc24 calculates the OpenPGP checksum as specified in RFC 4880, section 6.1
 | 
			
		||||
func crc24(crc uint32, d []byte) uint32 {
 | 
			
		||||
	for _, b := range d {
 | 
			
		||||
		crc ^= uint32(b) << 16
 | 
			
		||||
		for i := 0; i < 8; i++ {
 | 
			
		||||
			crc <<= 1
 | 
			
		||||
			if crc&0x1000000 != 0 {
 | 
			
		||||
				crc ^= crc24Poly
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return crc
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var armorStart = []byte("-----BEGIN ")
 | 
			
		||||
var armorEnd = []byte("-----END ")
 | 
			
		||||
var armorEndOfLine = []byte("-----")
 | 
			
		||||
 | 
			
		||||
// lineReader wraps a line based reader. It watches for the end of an armor
 | 
			
		||||
// block and records the expected CRC value.
 | 
			
		||||
type lineReader struct {
 | 
			
		||||
	in     *bufio.Reader
 | 
			
		||||
	buf    []byte
 | 
			
		||||
	eof    bool
 | 
			
		||||
	crc    uint32
 | 
			
		||||
	crcSet bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *lineReader) Read(p []byte) (n int, err error) {
 | 
			
		||||
	if l.eof {
 | 
			
		||||
		return 0, io.EOF
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(l.buf) > 0 {
 | 
			
		||||
		n = copy(p, l.buf)
 | 
			
		||||
		l.buf = l.buf[n:]
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	line, isPrefix, err := l.in.ReadLine()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if isPrefix {
 | 
			
		||||
		return 0, ArmorCorrupt
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if bytes.HasPrefix(line, armorEnd) {
 | 
			
		||||
		l.eof = true
 | 
			
		||||
		return 0, io.EOF
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(line) == 5 && line[0] == '=' {
 | 
			
		||||
		// This is the checksum line
 | 
			
		||||
		var expectedBytes [3]byte
 | 
			
		||||
		var m int
 | 
			
		||||
		m, err = base64.StdEncoding.Decode(expectedBytes[0:], line[1:])
 | 
			
		||||
		if m != 3 || err != nil {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		l.crc = uint32(expectedBytes[0])<<16 |
 | 
			
		||||
			uint32(expectedBytes[1])<<8 |
 | 
			
		||||
			uint32(expectedBytes[2])
 | 
			
		||||
 | 
			
		||||
		line, _, err = l.in.ReadLine()
 | 
			
		||||
		if err != nil && err != io.EOF {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		if !bytes.HasPrefix(line, armorEnd) {
 | 
			
		||||
			return 0, ArmorCorrupt
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		l.eof = true
 | 
			
		||||
		l.crcSet = true
 | 
			
		||||
		return 0, io.EOF
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(line) > 96 {
 | 
			
		||||
		return 0, ArmorCorrupt
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	n = copy(p, line)
 | 
			
		||||
	bytesToSave := len(line) - n
 | 
			
		||||
	if bytesToSave > 0 {
 | 
			
		||||
		if cap(l.buf) < bytesToSave {
 | 
			
		||||
			l.buf = make([]byte, 0, bytesToSave)
 | 
			
		||||
		}
 | 
			
		||||
		l.buf = l.buf[0:bytesToSave]
 | 
			
		||||
		copy(l.buf, line[n:])
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// openpgpReader passes Read calls to the underlying base64 decoder, but keeps
 | 
			
		||||
// a running CRC of the resulting data and checks the CRC against the value
 | 
			
		||||
// found by the lineReader at EOF.
 | 
			
		||||
type openpgpReader struct {
 | 
			
		||||
	lReader    *lineReader
 | 
			
		||||
	b64Reader  io.Reader
 | 
			
		||||
	currentCRC uint32
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *openpgpReader) Read(p []byte) (n int, err error) {
 | 
			
		||||
	n, err = r.b64Reader.Read(p)
 | 
			
		||||
	r.currentCRC = crc24(r.currentCRC, p[:n])
 | 
			
		||||
 | 
			
		||||
	if err == io.EOF && r.lReader.crcSet && r.lReader.crc != uint32(r.currentCRC&crc24Mask) {
 | 
			
		||||
		return 0, ArmorCorrupt
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Decode reads a PGP armored block from the given Reader. It will ignore
 | 
			
		||||
// leading garbage. If it doesn't find a block, it will return nil, io.EOF. The
 | 
			
		||||
// given Reader is not usable after calling this function: an arbitrary amount
 | 
			
		||||
// of data may have been read past the end of the block.
 | 
			
		||||
func Decode(in io.Reader) (p *Block, err error) {
 | 
			
		||||
	r := bufio.NewReaderSize(in, 100)
 | 
			
		||||
	var line []byte
 | 
			
		||||
	ignoreNext := false
 | 
			
		||||
 | 
			
		||||
TryNextBlock:
 | 
			
		||||
	p = nil
 | 
			
		||||
 | 
			
		||||
	// Skip leading garbage
 | 
			
		||||
	for {
 | 
			
		||||
		ignoreThis := ignoreNext
 | 
			
		||||
		line, ignoreNext, err = r.ReadLine()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		if ignoreNext || ignoreThis {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		line = bytes.TrimSpace(line)
 | 
			
		||||
		if len(line) > len(armorStart)+len(armorEndOfLine) && bytes.HasPrefix(line, armorStart) {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	p = new(Block)
 | 
			
		||||
	p.Type = string(line[len(armorStart) : len(line)-len(armorEndOfLine)])
 | 
			
		||||
	p.Header = make(map[string]string)
 | 
			
		||||
	nextIsContinuation := false
 | 
			
		||||
	var lastKey string
 | 
			
		||||
 | 
			
		||||
	// Read headers
 | 
			
		||||
	for {
 | 
			
		||||
		isContinuation := nextIsContinuation
 | 
			
		||||
		line, nextIsContinuation, err = r.ReadLine()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			p = nil
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		if isContinuation {
 | 
			
		||||
			p.Header[lastKey] += string(line)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		line = bytes.TrimSpace(line)
 | 
			
		||||
		if len(line) == 0 {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		i := bytes.Index(line, []byte(": "))
 | 
			
		||||
		if i == -1 {
 | 
			
		||||
			goto TryNextBlock
 | 
			
		||||
		}
 | 
			
		||||
		lastKey = string(line[:i])
 | 
			
		||||
		p.Header[lastKey] = string(line[i+2:])
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	p.lReader.in = r
 | 
			
		||||
	p.oReader.currentCRC = crc24Init
 | 
			
		||||
	p.oReader.lReader = &p.lReader
 | 
			
		||||
	p.oReader.b64Reader = base64.NewDecoder(base64.StdEncoding, &p.lReader)
 | 
			
		||||
	p.Body = &p.oReader
 | 
			
		||||
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										160
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/armor/encode.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										160
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/armor/encode.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,160 @@
 | 
			
		||||
// Copyright 2010 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package armor
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/base64"
 | 
			
		||||
	"io"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var armorHeaderSep = []byte(": ")
 | 
			
		||||
var blockEnd = []byte("\n=")
 | 
			
		||||
var newline = []byte("\n")
 | 
			
		||||
var armorEndOfLineOut = []byte("-----\n")
 | 
			
		||||
 | 
			
		||||
// writeSlices writes its arguments to the given Writer.
 | 
			
		||||
func writeSlices(out io.Writer, slices ...[]byte) (err error) {
 | 
			
		||||
	for _, s := range slices {
 | 
			
		||||
		_, err = out.Write(s)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// lineBreaker breaks data across several lines, all of the same byte length
 | 
			
		||||
// (except possibly the last). Lines are broken with a single '\n'.
 | 
			
		||||
type lineBreaker struct {
 | 
			
		||||
	lineLength  int
 | 
			
		||||
	line        []byte
 | 
			
		||||
	used        int
 | 
			
		||||
	out         io.Writer
 | 
			
		||||
	haveWritten bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newLineBreaker(out io.Writer, lineLength int) *lineBreaker {
 | 
			
		||||
	return &lineBreaker{
 | 
			
		||||
		lineLength: lineLength,
 | 
			
		||||
		line:       make([]byte, lineLength),
 | 
			
		||||
		used:       0,
 | 
			
		||||
		out:        out,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *lineBreaker) Write(b []byte) (n int, err error) {
 | 
			
		||||
	n = len(b)
 | 
			
		||||
 | 
			
		||||
	if n == 0 {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if l.used == 0 && l.haveWritten {
 | 
			
		||||
		_, err = l.out.Write([]byte{'\n'})
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if l.used+len(b) < l.lineLength {
 | 
			
		||||
		l.used += copy(l.line[l.used:], b)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	l.haveWritten = true
 | 
			
		||||
	_, err = l.out.Write(l.line[0:l.used])
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	excess := l.lineLength - l.used
 | 
			
		||||
	l.used = 0
 | 
			
		||||
 | 
			
		||||
	_, err = l.out.Write(b[0:excess])
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, err = l.Write(b[excess:])
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *lineBreaker) Close() (err error) {
 | 
			
		||||
	if l.used > 0 {
 | 
			
		||||
		_, err = l.out.Write(l.line[0:l.used])
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// encoding keeps track of a running CRC24 over the data which has been written
 | 
			
		||||
// to it and outputs a OpenPGP checksum when closed, followed by an armor
 | 
			
		||||
// trailer.
 | 
			
		||||
//
 | 
			
		||||
// It's built into a stack of io.Writers:
 | 
			
		||||
//    encoding -> base64 encoder -> lineBreaker -> out
 | 
			
		||||
type encoding struct {
 | 
			
		||||
	out       io.Writer
 | 
			
		||||
	breaker   *lineBreaker
 | 
			
		||||
	b64       io.WriteCloser
 | 
			
		||||
	crc       uint32
 | 
			
		||||
	blockType []byte
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e *encoding) Write(data []byte) (n int, err error) {
 | 
			
		||||
	e.crc = crc24(e.crc, data)
 | 
			
		||||
	return e.b64.Write(data)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e *encoding) Close() (err error) {
 | 
			
		||||
	err = e.b64.Close()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	e.breaker.Close()
 | 
			
		||||
 | 
			
		||||
	var checksumBytes [3]byte
 | 
			
		||||
	checksumBytes[0] = byte(e.crc >> 16)
 | 
			
		||||
	checksumBytes[1] = byte(e.crc >> 8)
 | 
			
		||||
	checksumBytes[2] = byte(e.crc)
 | 
			
		||||
 | 
			
		||||
	var b64ChecksumBytes [4]byte
 | 
			
		||||
	base64.StdEncoding.Encode(b64ChecksumBytes[:], checksumBytes[:])
 | 
			
		||||
 | 
			
		||||
	return writeSlices(e.out, blockEnd, b64ChecksumBytes[:], newline, armorEnd, e.blockType, armorEndOfLine)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Encode returns a WriteCloser which will encode the data written to it in
 | 
			
		||||
// OpenPGP armor.
 | 
			
		||||
func Encode(out io.Writer, blockType string, headers map[string]string) (w io.WriteCloser, err error) {
 | 
			
		||||
	bType := []byte(blockType)
 | 
			
		||||
	err = writeSlices(out, armorStart, bType, armorEndOfLineOut)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for k, v := range headers {
 | 
			
		||||
		err = writeSlices(out, []byte(k), armorHeaderSep, []byte(v), newline)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, err = out.Write(newline)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	e := &encoding{
 | 
			
		||||
		out:       out,
 | 
			
		||||
		breaker:   newLineBreaker(out, 64),
 | 
			
		||||
		crc:       crc24Init,
 | 
			
		||||
		blockType: bType,
 | 
			
		||||
	}
 | 
			
		||||
	e.b64 = base64.NewEncoder(base64.StdEncoding, e.breaker)
 | 
			
		||||
	return e, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										65
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/canonical_text.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/canonical_text.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,65 @@
 | 
			
		||||
// Copyright 2011 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package openpgp
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"hash"
 | 
			
		||||
	"io"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// NewCanonicalTextHash reformats text written to it into the canonical
 | 
			
		||||
// form and then applies the hash h.  See RFC 4880, section 5.2.1.
 | 
			
		||||
func NewCanonicalTextHash(h hash.Hash) hash.Hash {
 | 
			
		||||
	return &canonicalTextHash{h, 0}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type canonicalTextHash struct {
 | 
			
		||||
	h hash.Hash
 | 
			
		||||
	s int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var newline = []byte{'\r', '\n'}
 | 
			
		||||
 | 
			
		||||
func writeCanonical(cw io.Writer, buf []byte, s *int) (int, error) {
 | 
			
		||||
	start := 0
 | 
			
		||||
	for i, c := range buf {
 | 
			
		||||
		switch *s {
 | 
			
		||||
		case 0:
 | 
			
		||||
			if c == '\r' {
 | 
			
		||||
				*s = 1
 | 
			
		||||
			} else if c == '\n' {
 | 
			
		||||
				cw.Write(buf[start:i])
 | 
			
		||||
				cw.Write(newline)
 | 
			
		||||
				start = i + 1
 | 
			
		||||
			}
 | 
			
		||||
		case 1:
 | 
			
		||||
			*s = 0
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cw.Write(buf[start:])
 | 
			
		||||
	return len(buf), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (cth *canonicalTextHash) Write(buf []byte) (int, error) {
 | 
			
		||||
	return writeCanonical(cth.h, buf, &cth.s)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (cth *canonicalTextHash) Sum(in []byte) []byte {
 | 
			
		||||
	return cth.h.Sum(in)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (cth *canonicalTextHash) Reset() {
 | 
			
		||||
	cth.h.Reset()
 | 
			
		||||
	cth.s = 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (cth *canonicalTextHash) Size() int {
 | 
			
		||||
	return cth.h.Size()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (cth *canonicalTextHash) BlockSize() int {
 | 
			
		||||
	return cth.h.BlockSize()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										206
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/ecdh/ecdh.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										206
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/ecdh/ecdh.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,206 @@
 | 
			
		||||
// Copyright 2017 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
// Package ecdh implements ECDH encryption, suitable for OpenPGP,
 | 
			
		||||
// as specified in RFC 6637, section 8.
 | 
			
		||||
package ecdh
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"io"
 | 
			
		||||
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/openpgp/aes/keywrap"
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/openpgp/internal/algorithm"
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/openpgp/internal/ecc"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type KDF struct {
 | 
			
		||||
	Hash   algorithm.Hash
 | 
			
		||||
	Cipher algorithm.Cipher
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type PublicKey struct {
 | 
			
		||||
	curve ecc.ECDHCurve
 | 
			
		||||
	Point []byte
 | 
			
		||||
	KDF
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type PrivateKey struct {
 | 
			
		||||
	PublicKey
 | 
			
		||||
	D []byte
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewPublicKey(curve ecc.ECDHCurve, kdfHash algorithm.Hash, kdfCipher algorithm.Cipher) *PublicKey {
 | 
			
		||||
	return &PublicKey{
 | 
			
		||||
		curve:     curve,
 | 
			
		||||
		KDF: KDF{
 | 
			
		||||
			Hash:   kdfHash,
 | 
			
		||||
			Cipher: kdfCipher,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewPrivateKey(key PublicKey) *PrivateKey {
 | 
			
		||||
	return &PrivateKey{
 | 
			
		||||
		PublicKey: key,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (pk *PublicKey) GetCurve() ecc.ECDHCurve {
 | 
			
		||||
	return pk.curve
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (pk *PublicKey) MarshalPoint() []byte {
 | 
			
		||||
	return pk.curve.MarshalBytePoint(pk.Point)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (pk *PublicKey) UnmarshalPoint(p []byte) error {
 | 
			
		||||
	pk.Point = pk.curve.UnmarshalBytePoint(p)
 | 
			
		||||
	if pk.Point == nil {
 | 
			
		||||
		return errors.New("ecdh: failed to parse EC point")
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (sk *PrivateKey) MarshalByteSecret() []byte {
 | 
			
		||||
	return sk.curve.MarshalByteSecret(sk.D)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (sk *PrivateKey) UnmarshalByteSecret(d []byte) error {
 | 
			
		||||
	sk.D = sk.curve.UnmarshalByteSecret(d)
 | 
			
		||||
 | 
			
		||||
	if sk.D == nil {
 | 
			
		||||
		return errors.New("ecdh: failed to parse scalar")
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func GenerateKey(rand io.Reader, c ecc.ECDHCurve, kdf KDF) (priv *PrivateKey, err error) {
 | 
			
		||||
	priv = new(PrivateKey)
 | 
			
		||||
	priv.PublicKey.curve = c
 | 
			
		||||
	priv.PublicKey.KDF = kdf
 | 
			
		||||
	priv.PublicKey.Point, priv.D, err = c.GenerateECDH(rand)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Encrypt(random io.Reader, pub *PublicKey, msg, curveOID, fingerprint []byte) (vsG, c []byte, err error) {
 | 
			
		||||
	if len(msg) > 40 {
 | 
			
		||||
		return nil, nil, errors.New("ecdh: message too long")
 | 
			
		||||
	}
 | 
			
		||||
	// the sender MAY use 21, 13, and 5 bytes of padding for AES-128,
 | 
			
		||||
	// AES-192, and AES-256, respectively, to provide the same number of
 | 
			
		||||
	// octets, 40 total, as an input to the key wrapping method.
 | 
			
		||||
	padding := make([]byte, 40-len(msg))
 | 
			
		||||
	for i := range padding {
 | 
			
		||||
		padding[i] = byte(40 - len(msg))
 | 
			
		||||
	}
 | 
			
		||||
	m := append(msg, padding...)
 | 
			
		||||
 | 
			
		||||
	ephemeral, zb, err := pub.curve.Encaps(random, pub.Point)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	vsG = pub.curve.MarshalBytePoint(ephemeral)
 | 
			
		||||
 | 
			
		||||
	z, err := buildKey(pub, zb, curveOID, fingerprint, false, false)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if c, err = keywrap.Wrap(z, m); err != nil {
 | 
			
		||||
		return nil, nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return vsG, c, nil
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Decrypt(priv *PrivateKey, vsG, c, curveOID, fingerprint []byte) (msg []byte, err error) {
 | 
			
		||||
	var m []byte
 | 
			
		||||
	zb, err := priv.PublicKey.curve.Decaps(priv.curve.UnmarshalBytePoint(vsG), priv.D)
 | 
			
		||||
 | 
			
		||||
	// Try buildKey three times to workaround an old bug, see comments in buildKey.
 | 
			
		||||
	for i := 0; i < 3; i++ {
 | 
			
		||||
		var z []byte
 | 
			
		||||
		// RFC6637 §8: "Compute Z = KDF( S, Z_len, Param );"
 | 
			
		||||
		z, err = buildKey(&priv.PublicKey, zb, curveOID, fingerprint, i == 1, i == 2)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// RFC6637 §8: "Compute C = AESKeyWrap( Z, c ) as per [RFC3394]"
 | 
			
		||||
		m, err = keywrap.Unwrap(z, c)
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Only return an error after we've tried all (required) variants of buildKey.
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// RFC6637 §8: "m = symm_alg_ID || session key || checksum || pkcs5_padding"
 | 
			
		||||
	// The last byte should be the length of the padding, as per PKCS5; strip it off.
 | 
			
		||||
	return m[:len(m)-int(m[len(m)-1])], nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func buildKey(pub *PublicKey, zb []byte, curveOID, fingerprint []byte, stripLeading, stripTrailing bool) ([]byte, error) {
 | 
			
		||||
	// Param = curve_OID_len || curve_OID || public_key_alg_ID || 03
 | 
			
		||||
	//         || 01 || KDF_hash_ID || KEK_alg_ID for AESKeyWrap
 | 
			
		||||
	//         || "Anonymous Sender    " || recipient_fingerprint;
 | 
			
		||||
	param := new(bytes.Buffer)
 | 
			
		||||
	if _, err := param.Write(curveOID); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	algKDF := []byte{18, 3, 1, pub.KDF.Hash.Id(), pub.KDF.Cipher.Id()}
 | 
			
		||||
	if _, err := param.Write(algKDF); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	if _, err := param.Write([]byte("Anonymous Sender    ")); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	// For v5 keys, the 20 leftmost octets of the fingerprint are used.
 | 
			
		||||
	if _, err := param.Write(fingerprint[:20]); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	if param.Len() - len(curveOID) != 45 {
 | 
			
		||||
		return nil, errors.New("ecdh: malformed KDF Param")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// MB = Hash ( 00 || 00 || 00 || 01 || ZB || Param );
 | 
			
		||||
	h := pub.KDF.Hash.New()
 | 
			
		||||
	if _, err := h.Write([]byte{0x0, 0x0, 0x0, 0x1}); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	zbLen := len(zb)
 | 
			
		||||
	i := 0
 | 
			
		||||
	j := zbLen - 1
 | 
			
		||||
	if stripLeading {
 | 
			
		||||
		// Work around old go crypto bug where the leading zeros are missing.
 | 
			
		||||
		for ; i < zbLen && zb[i] == 0; i++ {}
 | 
			
		||||
	}
 | 
			
		||||
	if stripTrailing {
 | 
			
		||||
		// Work around old OpenPGP.js bug where insignificant trailing zeros in
 | 
			
		||||
		// this little-endian number are missing.
 | 
			
		||||
		// (See https://github.com/openpgpjs/openpgpjs/pull/853.)
 | 
			
		||||
		for ; j >= 0 && zb[j] == 0; j-- {}
 | 
			
		||||
	}
 | 
			
		||||
	if _, err := h.Write(zb[i:j+1]); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	if _, err := h.Write(param.Bytes()); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	mb := h.Sum(nil)
 | 
			
		||||
 | 
			
		||||
	return mb[:pub.KDF.Cipher.KeySize()], nil // return oBits leftmost bits of MB.
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Validate(priv *PrivateKey) error {
 | 
			
		||||
	return priv.curve.ValidateECDH(priv.Point, priv.D)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										80
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/ecdsa/ecdsa.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/ecdsa/ecdsa.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,80 @@
 | 
			
		||||
// Package ecdsa implements ECDSA signature, suitable for OpenPGP,
 | 
			
		||||
// as specified in RFC 6637, section 5.
 | 
			
		||||
package ecdsa
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/openpgp/internal/ecc"
 | 
			
		||||
	"io"
 | 
			
		||||
	"math/big"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type PublicKey struct {
 | 
			
		||||
	X, Y *big.Int
 | 
			
		||||
	curve ecc.ECDSACurve
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type PrivateKey struct {
 | 
			
		||||
	PublicKey
 | 
			
		||||
	D *big.Int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewPublicKey(curve ecc.ECDSACurve) *PublicKey {
 | 
			
		||||
	return &PublicKey{
 | 
			
		||||
		curve: curve,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewPrivateKey(key PublicKey) *PrivateKey {
 | 
			
		||||
	return &PrivateKey{
 | 
			
		||||
		PublicKey: key,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (pk *PublicKey) GetCurve() ecc.ECDSACurve {
 | 
			
		||||
	return pk.curve
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (pk *PublicKey) MarshalPoint() []byte {
 | 
			
		||||
	return pk.curve.MarshalIntegerPoint(pk.X, pk.Y)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (pk *PublicKey) UnmarshalPoint(p []byte) error {
 | 
			
		||||
	pk.X, pk.Y = pk.curve.UnmarshalIntegerPoint(p)
 | 
			
		||||
	if pk.X == nil {
 | 
			
		||||
		return errors.New("ecdsa: failed to parse EC point")
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (sk *PrivateKey) MarshalIntegerSecret() []byte {
 | 
			
		||||
	return sk.curve.MarshalIntegerSecret(sk.D)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (sk *PrivateKey) UnmarshalIntegerSecret(d []byte) error {
 | 
			
		||||
	sk.D = sk.curve.UnmarshalIntegerSecret(d)
 | 
			
		||||
 | 
			
		||||
	if sk.D == nil {
 | 
			
		||||
		return errors.New("ecdsa: failed to parse scalar")
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func GenerateKey(rand io.Reader, c ecc.ECDSACurve) (priv *PrivateKey, err error) {
 | 
			
		||||
	priv = new(PrivateKey)
 | 
			
		||||
	priv.PublicKey.curve = c
 | 
			
		||||
	priv.PublicKey.X, priv.PublicKey.Y, priv.D, err = c.GenerateECDSA(rand)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error) {
 | 
			
		||||
	return priv.PublicKey.curve.Sign(rand, priv.X, priv.Y, priv.D, hash)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool {
 | 
			
		||||
	return pub.curve.Verify(pub.X, pub.Y, hash, r, s)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Validate(priv *PrivateKey) error {
 | 
			
		||||
	return priv.curve.ValidateECDSA(priv.X, priv.Y, priv.D.Bytes())
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										91
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/eddsa/eddsa.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/eddsa/eddsa.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,91 @@
 | 
			
		||||
// Package eddsa implements EdDSA signature, suitable for OpenPGP, as specified in
 | 
			
		||||
// https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-13.7
 | 
			
		||||
package eddsa
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/openpgp/internal/ecc"
 | 
			
		||||
	"io"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type PublicKey struct {
 | 
			
		||||
	X []byte
 | 
			
		||||
	curve ecc.EdDSACurve
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type PrivateKey struct {
 | 
			
		||||
	PublicKey
 | 
			
		||||
	D []byte
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewPublicKey(curve ecc.EdDSACurve) *PublicKey {
 | 
			
		||||
	return &PublicKey{
 | 
			
		||||
		curve: curve,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewPrivateKey(key PublicKey) *PrivateKey {
 | 
			
		||||
	return &PrivateKey{
 | 
			
		||||
		PublicKey: key,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (pk *PublicKey) GetCurve() ecc.EdDSACurve {
 | 
			
		||||
	return pk.curve
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (pk *PublicKey) MarshalPoint() []byte {
 | 
			
		||||
	return pk.curve.MarshalBytePoint(pk.X)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (pk *PublicKey) UnmarshalPoint(x []byte) error {
 | 
			
		||||
	pk.X = pk.curve.UnmarshalBytePoint(x)
 | 
			
		||||
 | 
			
		||||
	if pk.X == nil {
 | 
			
		||||
		return errors.New("eddsa: failed to parse EC point")
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (sk *PrivateKey) MarshalByteSecret() []byte {
 | 
			
		||||
	return sk.curve.MarshalByteSecret(sk.D)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (sk *PrivateKey) UnmarshalByteSecret(d []byte) error {
 | 
			
		||||
	sk.D = sk.curve.UnmarshalByteSecret(d)
 | 
			
		||||
 | 
			
		||||
	if sk.D == nil {
 | 
			
		||||
		return errors.New("eddsa: failed to parse scalar")
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func GenerateKey(rand io.Reader, c ecc.EdDSACurve) (priv *PrivateKey, err error) {
 | 
			
		||||
	priv = new(PrivateKey)
 | 
			
		||||
	priv.PublicKey.curve = c
 | 
			
		||||
	priv.PublicKey.X, priv.D, err = c.GenerateEdDSA(rand)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Sign(priv *PrivateKey, message []byte) (r, s []byte, err error) {
 | 
			
		||||
	sig, err := priv.PublicKey.curve.Sign(priv.PublicKey.X, priv.D, message)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	r, s = priv.PublicKey.curve.MarshalSignature(sig)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Verify(pub *PublicKey, message, r, s []byte) bool {
 | 
			
		||||
	sig := pub.curve.UnmarshalSignature(r, s)
 | 
			
		||||
	if sig == nil {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return pub.curve.Verify(pub.X, message, sig)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Validate(priv *PrivateKey) error {
 | 
			
		||||
	return priv.curve.ValidateEdDSA(priv.PublicKey.X, priv.D)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										124
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/elgamal/elgamal.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/elgamal/elgamal.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,124 @@
 | 
			
		||||
// Copyright 2011 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
// Package elgamal implements ElGamal encryption, suitable for OpenPGP,
 | 
			
		||||
// as specified in "A Public-Key Cryptosystem and a Signature Scheme Based on
 | 
			
		||||
// Discrete Logarithms," IEEE Transactions on Information Theory, v. IT-31,
 | 
			
		||||
// n. 4, 1985, pp. 469-472.
 | 
			
		||||
//
 | 
			
		||||
// This form of ElGamal embeds PKCS#1 v1.5 padding, which may make it
 | 
			
		||||
// unsuitable for other protocols. RSA should be used in preference in any
 | 
			
		||||
// case.
 | 
			
		||||
package elgamal // import "github.com/ProtonMail/go-crypto/openpgp/elgamal"
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/rand"
 | 
			
		||||
	"crypto/subtle"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"io"
 | 
			
		||||
	"math/big"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// PublicKey represents an ElGamal public key.
 | 
			
		||||
type PublicKey struct {
 | 
			
		||||
	G, P, Y *big.Int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PrivateKey represents an ElGamal private key.
 | 
			
		||||
type PrivateKey struct {
 | 
			
		||||
	PublicKey
 | 
			
		||||
	X *big.Int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Encrypt encrypts the given message to the given public key. The result is a
 | 
			
		||||
// pair of integers. Errors can result from reading random, or because msg is
 | 
			
		||||
// too large to be encrypted to the public key.
 | 
			
		||||
func Encrypt(random io.Reader, pub *PublicKey, msg []byte) (c1, c2 *big.Int, err error) {
 | 
			
		||||
	pLen := (pub.P.BitLen() + 7) / 8
 | 
			
		||||
	if len(msg) > pLen-11 {
 | 
			
		||||
		err = errors.New("elgamal: message too long")
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// EM = 0x02 || PS || 0x00 || M
 | 
			
		||||
	em := make([]byte, pLen-1)
 | 
			
		||||
	em[0] = 2
 | 
			
		||||
	ps, mm := em[1:len(em)-len(msg)-1], em[len(em)-len(msg):]
 | 
			
		||||
	err = nonZeroRandomBytes(ps, random)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	em[len(em)-len(msg)-1] = 0
 | 
			
		||||
	copy(mm, msg)
 | 
			
		||||
 | 
			
		||||
	m := new(big.Int).SetBytes(em)
 | 
			
		||||
 | 
			
		||||
	k, err := rand.Int(random, pub.P)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c1 = new(big.Int).Exp(pub.G, k, pub.P)
 | 
			
		||||
	s := new(big.Int).Exp(pub.Y, k, pub.P)
 | 
			
		||||
	c2 = s.Mul(s, m)
 | 
			
		||||
	c2.Mod(c2, pub.P)
 | 
			
		||||
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Decrypt takes two integers, resulting from an ElGamal encryption, and
 | 
			
		||||
// returns the plaintext of the message. An error can result only if the
 | 
			
		||||
// ciphertext is invalid. Users should keep in mind that this is a padding
 | 
			
		||||
// oracle and thus, if exposed to an adaptive chosen ciphertext attack, can
 | 
			
		||||
// be used to break the cryptosystem.  See ``Chosen Ciphertext Attacks
 | 
			
		||||
// Against Protocols Based on the RSA Encryption Standard PKCS #1'', Daniel
 | 
			
		||||
// Bleichenbacher, Advances in Cryptology (Crypto '98),
 | 
			
		||||
func Decrypt(priv *PrivateKey, c1, c2 *big.Int) (msg []byte, err error) {
 | 
			
		||||
	s := new(big.Int).Exp(c1, priv.X, priv.P)
 | 
			
		||||
	if s.ModInverse(s, priv.P) == nil {
 | 
			
		||||
		return nil, errors.New("elgamal: invalid private key")
 | 
			
		||||
	}
 | 
			
		||||
	s.Mul(s, c2)
 | 
			
		||||
	s.Mod(s, priv.P)
 | 
			
		||||
	em := s.Bytes()
 | 
			
		||||
 | 
			
		||||
	firstByteIsTwo := subtle.ConstantTimeByteEq(em[0], 2)
 | 
			
		||||
 | 
			
		||||
	// The remainder of the plaintext must be a string of non-zero random
 | 
			
		||||
	// octets, followed by a 0, followed by the message.
 | 
			
		||||
	//   lookingForIndex: 1 iff we are still looking for the zero.
 | 
			
		||||
	//   index: the offset of the first zero byte.
 | 
			
		||||
	var lookingForIndex, index int
 | 
			
		||||
	lookingForIndex = 1
 | 
			
		||||
 | 
			
		||||
	for i := 1; i < len(em); i++ {
 | 
			
		||||
		equals0 := subtle.ConstantTimeByteEq(em[i], 0)
 | 
			
		||||
		index = subtle.ConstantTimeSelect(lookingForIndex&equals0, i, index)
 | 
			
		||||
		lookingForIndex = subtle.ConstantTimeSelect(equals0, 0, lookingForIndex)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if firstByteIsTwo != 1 || lookingForIndex != 0 || index < 9 {
 | 
			
		||||
		return nil, errors.New("elgamal: decryption error")
 | 
			
		||||
	}
 | 
			
		||||
	return em[index+1:], nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// nonZeroRandomBytes fills the given slice with non-zero random octets.
 | 
			
		||||
func nonZeroRandomBytes(s []byte, rand io.Reader) (err error) {
 | 
			
		||||
	_, err = io.ReadFull(rand, s)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for i := 0; i < len(s); i++ {
 | 
			
		||||
		for s[i] == 0 {
 | 
			
		||||
			_, err = io.ReadFull(rand, s[i:i+1])
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										116
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/errors/errors.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/errors/errors.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,116 @@
 | 
			
		||||
// Copyright 2010 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
// Package errors contains common error types for the OpenPGP packages.
 | 
			
		||||
package errors // import "github.com/ProtonMail/go-crypto/openpgp/errors"
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"strconv"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// A StructuralError is returned when OpenPGP data is found to be syntactically
 | 
			
		||||
// invalid.
 | 
			
		||||
type StructuralError string
 | 
			
		||||
 | 
			
		||||
func (s StructuralError) Error() string {
 | 
			
		||||
	return "openpgp: invalid data: " + string(s)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UnsupportedError indicates that, although the OpenPGP data is valid, it
 | 
			
		||||
// makes use of currently unimplemented features.
 | 
			
		||||
type UnsupportedError string
 | 
			
		||||
 | 
			
		||||
func (s UnsupportedError) Error() string {
 | 
			
		||||
	return "openpgp: unsupported feature: " + string(s)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// InvalidArgumentError indicates that the caller is in error and passed an
 | 
			
		||||
// incorrect value.
 | 
			
		||||
type InvalidArgumentError string
 | 
			
		||||
 | 
			
		||||
func (i InvalidArgumentError) Error() string {
 | 
			
		||||
	return "openpgp: invalid argument: " + string(i)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SignatureError indicates that a syntactically valid signature failed to
 | 
			
		||||
// validate.
 | 
			
		||||
type SignatureError string
 | 
			
		||||
 | 
			
		||||
func (b SignatureError) Error() string {
 | 
			
		||||
	return "openpgp: invalid signature: " + string(b)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var ErrMDCHashMismatch error = SignatureError("MDC hash mismatch")
 | 
			
		||||
var ErrMDCMissing error = SignatureError("MDC packet not found")
 | 
			
		||||
 | 
			
		||||
type signatureExpiredError int
 | 
			
		||||
 | 
			
		||||
func (se signatureExpiredError) Error() string {
 | 
			
		||||
	return "openpgp: signature expired"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var ErrSignatureExpired error = signatureExpiredError(0)
 | 
			
		||||
 | 
			
		||||
type keyExpiredError int
 | 
			
		||||
 | 
			
		||||
func (ke keyExpiredError) Error() string {
 | 
			
		||||
	return "openpgp: key expired"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var ErrKeyExpired error = keyExpiredError(0)
 | 
			
		||||
 | 
			
		||||
type keyIncorrectError int
 | 
			
		||||
 | 
			
		||||
func (ki keyIncorrectError) Error() string {
 | 
			
		||||
	return "openpgp: incorrect key"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var ErrKeyIncorrect error = keyIncorrectError(0)
 | 
			
		||||
 | 
			
		||||
// KeyInvalidError indicates that the public key parameters are invalid
 | 
			
		||||
// as they do not match the private ones
 | 
			
		||||
type KeyInvalidError string
 | 
			
		||||
 | 
			
		||||
func (e KeyInvalidError) Error() string {
 | 
			
		||||
	return "openpgp: invalid key: " + string(e)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type unknownIssuerError int
 | 
			
		||||
 | 
			
		||||
func (unknownIssuerError) Error() string {
 | 
			
		||||
	return "openpgp: signature made by unknown entity"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var ErrUnknownIssuer error = unknownIssuerError(0)
 | 
			
		||||
 | 
			
		||||
type keyRevokedError int
 | 
			
		||||
 | 
			
		||||
func (keyRevokedError) Error() string {
 | 
			
		||||
	return "openpgp: signature made by revoked key"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var ErrKeyRevoked error = keyRevokedError(0)
 | 
			
		||||
 | 
			
		||||
type UnknownPacketTypeError uint8
 | 
			
		||||
 | 
			
		||||
func (upte UnknownPacketTypeError) Error() string {
 | 
			
		||||
	return "openpgp: unknown packet type: " + strconv.Itoa(int(upte))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AEADError indicates that there is a problem when initializing or using a
 | 
			
		||||
// AEAD instance, configuration struct, nonces or index values.
 | 
			
		||||
type AEADError string
 | 
			
		||||
 | 
			
		||||
func (ae AEADError) Error() string {
 | 
			
		||||
	return "openpgp: aead error: " + string(ae)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ErrDummyPrivateKey results when operations are attempted on a private key
 | 
			
		||||
// that is just a dummy key. See
 | 
			
		||||
// https://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=blob;f=doc/DETAILS;h=fe55ae16ab4e26d8356dc574c9e8bc935e71aef1;hb=23191d7851eae2217ecdac6484349849a24fd94a#l1109
 | 
			
		||||
type ErrDummyPrivateKey string
 | 
			
		||||
 | 
			
		||||
func (dke ErrDummyPrivateKey) Error() string {
 | 
			
		||||
	return "openpgp: s2k GNU dummy key: " + string(dke)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										65
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/internal/algorithm/aead.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/internal/algorithm/aead.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,65 @@
 | 
			
		||||
// Copyright (C) 2019 ProtonTech AG
 | 
			
		||||
 | 
			
		||||
package algorithm
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/cipher"
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/eax"
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/ocb"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// AEADMode defines the Authenticated Encryption with Associated Data mode of
 | 
			
		||||
// operation.
 | 
			
		||||
type AEADMode uint8
 | 
			
		||||
 | 
			
		||||
// Supported modes of operation (see RFC4880bis [EAX] and RFC7253)
 | 
			
		||||
const (
 | 
			
		||||
	AEADModeEAX = AEADMode(1)
 | 
			
		||||
	AEADModeOCB = AEADMode(2)
 | 
			
		||||
	AEADModeGCM = AEADMode(100)
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// TagLength returns the length in bytes of authentication tags.
 | 
			
		||||
func (mode AEADMode) TagLength() int {
 | 
			
		||||
	switch mode {
 | 
			
		||||
	case AEADModeEAX:
 | 
			
		||||
		return 16
 | 
			
		||||
	case AEADModeOCB:
 | 
			
		||||
		return 16
 | 
			
		||||
	case AEADModeGCM:
 | 
			
		||||
		return 16
 | 
			
		||||
	default:
 | 
			
		||||
		return 0
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NonceLength returns the length in bytes of nonces.
 | 
			
		||||
func (mode AEADMode) NonceLength() int {
 | 
			
		||||
	switch mode {
 | 
			
		||||
	case AEADModeEAX:
 | 
			
		||||
		return 16
 | 
			
		||||
	case AEADModeOCB:
 | 
			
		||||
		return 15
 | 
			
		||||
	case AEADModeGCM:
 | 
			
		||||
		return 12
 | 
			
		||||
	default:
 | 
			
		||||
		return 0
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New returns a fresh instance of the given mode
 | 
			
		||||
func (mode AEADMode) New(block cipher.Block) (alg cipher.AEAD) {
 | 
			
		||||
	var err error
 | 
			
		||||
	switch mode {
 | 
			
		||||
	case AEADModeEAX:
 | 
			
		||||
		alg, err = eax.NewEAX(block)
 | 
			
		||||
	case AEADModeOCB:
 | 
			
		||||
		alg, err = ocb.NewOCB(block)
 | 
			
		||||
	case AEADModeGCM:
 | 
			
		||||
		alg, err = cipher.NewGCM(block)
 | 
			
		||||
	}
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err.Error())
 | 
			
		||||
	}
 | 
			
		||||
	return alg
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										107
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/internal/algorithm/cipher.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/internal/algorithm/cipher.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,107 @@
 | 
			
		||||
// Copyright 2017 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package algorithm
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/aes"
 | 
			
		||||
	"crypto/cipher"
 | 
			
		||||
	"crypto/des"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/crypto/cast5"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Cipher is an official symmetric key cipher algorithm. See RFC 4880,
 | 
			
		||||
// section 9.2.
 | 
			
		||||
type Cipher interface {
 | 
			
		||||
	// Id returns the algorithm ID, as a byte, of the cipher.
 | 
			
		||||
	Id() uint8
 | 
			
		||||
	// KeySize returns the key size, in bytes, of the cipher.
 | 
			
		||||
	KeySize() int
 | 
			
		||||
	// BlockSize returns the block size, in bytes, of the cipher.
 | 
			
		||||
	BlockSize() int
 | 
			
		||||
	// New returns a fresh instance of the given cipher.
 | 
			
		||||
	New(key []byte) cipher.Block
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// The following constants mirror the OpenPGP standard (RFC 4880).
 | 
			
		||||
const (
 | 
			
		||||
	TripleDES = CipherFunction(2)
 | 
			
		||||
	CAST5     = CipherFunction(3)
 | 
			
		||||
	AES128    = CipherFunction(7)
 | 
			
		||||
	AES192    = CipherFunction(8)
 | 
			
		||||
	AES256    = CipherFunction(9)
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// CipherById represents the different block ciphers specified for OpenPGP. See
 | 
			
		||||
// http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-13
 | 
			
		||||
var CipherById = map[uint8]Cipher{
 | 
			
		||||
	TripleDES.Id(): TripleDES,
 | 
			
		||||
	CAST5.Id():     CAST5,
 | 
			
		||||
	AES128.Id():    AES128,
 | 
			
		||||
	AES192.Id():    AES192,
 | 
			
		||||
	AES256.Id():    AES256,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type CipherFunction uint8
 | 
			
		||||
 | 
			
		||||
// ID returns the algorithm Id, as a byte, of cipher.
 | 
			
		||||
func (sk CipherFunction) Id() uint8 {
 | 
			
		||||
	return uint8(sk)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var keySizeByID = map[uint8]int{
 | 
			
		||||
	TripleDES.Id(): 24,
 | 
			
		||||
	CAST5.Id():     cast5.KeySize,
 | 
			
		||||
	AES128.Id():    16,
 | 
			
		||||
	AES192.Id():    24,
 | 
			
		||||
	AES256.Id():    32,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// KeySize returns the key size, in bytes, of cipher.
 | 
			
		||||
func (cipher CipherFunction) KeySize() int {
 | 
			
		||||
	switch cipher {
 | 
			
		||||
	case TripleDES:
 | 
			
		||||
		return 24
 | 
			
		||||
	case CAST5:
 | 
			
		||||
		return cast5.KeySize
 | 
			
		||||
	case AES128:
 | 
			
		||||
		return 16
 | 
			
		||||
	case AES192:
 | 
			
		||||
		return 24
 | 
			
		||||
	case AES256:
 | 
			
		||||
		return 32
 | 
			
		||||
	}
 | 
			
		||||
	return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// BlockSize returns the block size, in bytes, of cipher.
 | 
			
		||||
func (cipher CipherFunction) BlockSize() int {
 | 
			
		||||
	switch cipher {
 | 
			
		||||
	case TripleDES:
 | 
			
		||||
		return des.BlockSize
 | 
			
		||||
	case CAST5:
 | 
			
		||||
		return 8
 | 
			
		||||
	case AES128, AES192, AES256:
 | 
			
		||||
		return 16
 | 
			
		||||
	}
 | 
			
		||||
	return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New returns a fresh instance of the given cipher.
 | 
			
		||||
func (cipher CipherFunction) New(key []byte) (block cipher.Block) {
 | 
			
		||||
	var err error
 | 
			
		||||
	switch cipher {
 | 
			
		||||
	case TripleDES:
 | 
			
		||||
		block, err = des.NewTripleDESCipher(key)
 | 
			
		||||
	case CAST5:
 | 
			
		||||
		block, err = cast5.NewCipher(key)
 | 
			
		||||
	case AES128, AES192, AES256:
 | 
			
		||||
		block, err = aes.NewCipher(key)
 | 
			
		||||
	}
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err.Error())
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										86
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/internal/algorithm/hash.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/internal/algorithm/hash.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,86 @@
 | 
			
		||||
// Copyright 2017 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package algorithm
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"hash"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Hash is an official hash function algorithm. See RFC 4880, section 9.4.
 | 
			
		||||
type Hash interface {
 | 
			
		||||
	// Id returns the algorithm ID, as a byte, of Hash.
 | 
			
		||||
	Id() uint8
 | 
			
		||||
	// Available reports whether the given hash function is linked into the binary.
 | 
			
		||||
	Available() bool
 | 
			
		||||
	// HashFunc simply returns the value of h so that Hash implements SignerOpts.
 | 
			
		||||
	HashFunc() crypto.Hash
 | 
			
		||||
	// New returns a new hash.Hash calculating the given hash function. New
 | 
			
		||||
	// panics if the hash function is not linked into the binary.
 | 
			
		||||
	New() hash.Hash
 | 
			
		||||
	// Size returns the length, in bytes, of a digest resulting from the given
 | 
			
		||||
	// hash function. It doesn't require that the hash function in question be
 | 
			
		||||
	// linked into the program.
 | 
			
		||||
	Size() int
 | 
			
		||||
	// String is the name of the hash function corresponding to the given
 | 
			
		||||
	// OpenPGP hash id.
 | 
			
		||||
	String() string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// The following vars mirror the crypto/Hash supported hash functions.
 | 
			
		||||
var (
 | 
			
		||||
	MD5       Hash = cryptoHash{1, crypto.MD5}
 | 
			
		||||
	SHA1      Hash = cryptoHash{2, crypto.SHA1}
 | 
			
		||||
	RIPEMD160 Hash = cryptoHash{3, crypto.RIPEMD160}
 | 
			
		||||
	SHA256    Hash = cryptoHash{8, crypto.SHA256}
 | 
			
		||||
	SHA384    Hash = cryptoHash{9, crypto.SHA384}
 | 
			
		||||
	SHA512    Hash = cryptoHash{10, crypto.SHA512}
 | 
			
		||||
	SHA224    Hash = cryptoHash{11, crypto.SHA224}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// HashById represents the different hash functions specified for OpenPGP. See
 | 
			
		||||
// http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-14
 | 
			
		||||
var (
 | 
			
		||||
	HashById = map[uint8]Hash{
 | 
			
		||||
		MD5.Id():       MD5,
 | 
			
		||||
		SHA1.Id():      SHA1,
 | 
			
		||||
		RIPEMD160.Id(): RIPEMD160,
 | 
			
		||||
		SHA256.Id():    SHA256,
 | 
			
		||||
		SHA384.Id():    SHA384,
 | 
			
		||||
		SHA512.Id():    SHA512,
 | 
			
		||||
		SHA224.Id():    SHA224,
 | 
			
		||||
	}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// cryptoHash contains pairs relating OpenPGP's hash identifier with
 | 
			
		||||
// Go's crypto.Hash type. See RFC 4880, section 9.4.
 | 
			
		||||
type cryptoHash struct {
 | 
			
		||||
	id uint8
 | 
			
		||||
	crypto.Hash
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Id returns the algorithm ID, as a byte, of cryptoHash.
 | 
			
		||||
func (h cryptoHash) Id() uint8 {
 | 
			
		||||
	return h.id
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var hashNames = map[uint8]string{
 | 
			
		||||
	MD5.Id():       "MD5",
 | 
			
		||||
	SHA1.Id():      "SHA1",
 | 
			
		||||
	RIPEMD160.Id(): "RIPEMD160",
 | 
			
		||||
	SHA256.Id():    "SHA256",
 | 
			
		||||
	SHA384.Id():    "SHA384",
 | 
			
		||||
	SHA512.Id():    "SHA512",
 | 
			
		||||
	SHA224.Id():    "SHA224",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h cryptoHash) String() string {
 | 
			
		||||
	s, ok := hashNames[h.id]
 | 
			
		||||
	if !ok {
 | 
			
		||||
		panic(fmt.Sprintf("Unsupported hash function %d", h.id))
 | 
			
		||||
	}
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										171
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/curve25519.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										171
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/curve25519.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,171 @@
 | 
			
		||||
// Package ecc implements a generic interface for ECDH, ECDSA, and EdDSA.
 | 
			
		||||
package ecc
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/subtle"
 | 
			
		||||
	"io"
 | 
			
		||||
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/openpgp/errors"
 | 
			
		||||
	x25519lib "github.com/cloudflare/circl/dh/x25519"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type curve25519 struct {}
 | 
			
		||||
 | 
			
		||||
func NewCurve25519() *curve25519 {
 | 
			
		||||
	return &curve25519{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *curve25519) GetCurveName() string {
 | 
			
		||||
	return "curve25519"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MarshalBytePoint encodes the public point from native format, adding the prefix.
 | 
			
		||||
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.6
 | 
			
		||||
func (c *curve25519) MarshalBytePoint(point [] byte) []byte {
 | 
			
		||||
	return append([]byte{0x40}, point...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UnmarshalBytePoint decodes the public point to native format, removing the prefix.
 | 
			
		||||
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.6
 | 
			
		||||
func (c *curve25519) UnmarshalBytePoint(point []byte) []byte {
 | 
			
		||||
	if len(point) != x25519lib.Size + 1 {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Remove prefix
 | 
			
		||||
	return point[1:]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MarshalByteSecret encodes the secret scalar from native format.
 | 
			
		||||
// Note that the EC secret scalar differs from the definition of public keys in
 | 
			
		||||
// [Curve25519] in two ways: (1) the byte-ordering is big-endian, which is
 | 
			
		||||
// more uniform with how big integers are represented in OpenPGP, and (2) the
 | 
			
		||||
// leading zeros are truncated.
 | 
			
		||||
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.6.1.1
 | 
			
		||||
// Note that leading zero bytes are stripped later when encoding as an MPI.
 | 
			
		||||
func (c *curve25519) MarshalByteSecret(secret []byte) []byte {
 | 
			
		||||
	d := make([]byte, x25519lib.Size)
 | 
			
		||||
	copyReversed(d, secret)
 | 
			
		||||
 | 
			
		||||
	// The following ensures that the private key is a number of the form
 | 
			
		||||
	// 2^{254} + 8 * [0, 2^{251}), in order to avoid the small subgroup of
 | 
			
		||||
	// the curve.
 | 
			
		||||
	//
 | 
			
		||||
	// This masking is done internally in the underlying lib and so is unnecessary
 | 
			
		||||
	// for security, but OpenPGP implementations require that private keys be
 | 
			
		||||
	// pre-masked.
 | 
			
		||||
	d[0] &= 127
 | 
			
		||||
	d[0] |= 64
 | 
			
		||||
	d[31] &= 248
 | 
			
		||||
 | 
			
		||||
	return d
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UnmarshalByteSecret decodes the secret scalar from native format.
 | 
			
		||||
// Note that the EC secret scalar differs from the definition of public keys in
 | 
			
		||||
// [Curve25519] in two ways: (1) the byte-ordering is big-endian, which is
 | 
			
		||||
// more uniform with how big integers are represented in OpenPGP, and (2) the
 | 
			
		||||
// leading zeros are truncated.
 | 
			
		||||
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.6.1.1
 | 
			
		||||
func (c *curve25519) UnmarshalByteSecret(d []byte) []byte {
 | 
			
		||||
	if len(d) > x25519lib.Size {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Ensure truncated leading bytes are re-added
 | 
			
		||||
	secret := make([]byte, x25519lib.Size)
 | 
			
		||||
	copyReversed(secret, d)
 | 
			
		||||
 | 
			
		||||
	return secret
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// generateKeyPairBytes Generates a private-public key-pair.
 | 
			
		||||
// 'priv' is a private key; a little-endian scalar belonging to the set
 | 
			
		||||
// 2^{254} + 8 * [0, 2^{251}), in order to avoid the small subgroup of the
 | 
			
		||||
// curve. 'pub' is simply 'priv' * G where G is the base point.
 | 
			
		||||
// See https://cr.yp.to/ecdh.html and RFC7748, sec 5.
 | 
			
		||||
func (c *curve25519) generateKeyPairBytes(rand io.Reader) (priv, pub x25519lib.Key, err error) {
 | 
			
		||||
	_, err = io.ReadFull(rand, priv[:])
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	x25519lib.KeyGen(&pub, &priv)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *curve25519) GenerateECDH(rand io.Reader) (point []byte, secret []byte, err error) {
 | 
			
		||||
	priv, pub, err := c.generateKeyPairBytes(rand)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return pub[:], priv[:], nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *genericCurve) MaskSecret(secret []byte) []byte {
 | 
			
		||||
	return secret
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *curve25519) Encaps(rand io.Reader, point []byte) (ephemeral, sharedSecret []byte, err error) {
 | 
			
		||||
	// RFC6637 §8: "Generate an ephemeral key pair {v, V=vG}"
 | 
			
		||||
	// ephemeralPrivate corresponds to `v`.
 | 
			
		||||
	// ephemeralPublic corresponds to `V`.
 | 
			
		||||
	ephemeralPrivate, ephemeralPublic, err := c.generateKeyPairBytes(rand)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// RFC6637 §8: "Obtain the authenticated recipient public key R"
 | 
			
		||||
	// pubKey corresponds to `R`.
 | 
			
		||||
	var pubKey x25519lib.Key
 | 
			
		||||
	copy(pubKey[:], point)
 | 
			
		||||
 | 
			
		||||
	// RFC6637 §8: "Compute the shared point S = vR"
 | 
			
		||||
	//	"VB = convert point V to the octet string"
 | 
			
		||||
	// sharedPoint corresponds to `VB`.
 | 
			
		||||
	var sharedPoint x25519lib.Key
 | 
			
		||||
	x25519lib.Shared(&sharedPoint, &ephemeralPrivate, &pubKey)
 | 
			
		||||
 | 
			
		||||
	return ephemeralPublic[:], sharedPoint[:], nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *curve25519) Decaps(vsG, secret []byte) (sharedSecret []byte, err error) {
 | 
			
		||||
	var ephemeralPublic, decodedPrivate, sharedPoint x25519lib.Key
 | 
			
		||||
	// RFC6637 §8: "The decryption is the inverse of the method given."
 | 
			
		||||
	// All quoted descriptions in comments below describe encryption, and
 | 
			
		||||
	// the reverse is performed.
 | 
			
		||||
	// vsG corresponds to `VB` in RFC6637 §8 .
 | 
			
		||||
 | 
			
		||||
	// RFC6637 §8: "VB = convert point V to the octet string"
 | 
			
		||||
	copy(ephemeralPublic[:], vsG)
 | 
			
		||||
 | 
			
		||||
	// decodedPrivate corresponds to `r` in RFC6637 §8 .
 | 
			
		||||
	copy(decodedPrivate[:], secret)
 | 
			
		||||
 | 
			
		||||
	// RFC6637 §8: "Note that the recipient obtains the shared secret by calculating
 | 
			
		||||
	//   S = rV = rvG, where (r,R) is the recipient's key pair."
 | 
			
		||||
	// sharedPoint corresponds to `S`.
 | 
			
		||||
	x25519lib.Shared(&sharedPoint, &decodedPrivate, &ephemeralPublic)
 | 
			
		||||
 | 
			
		||||
	return sharedPoint[:], nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *curve25519) ValidateECDH(point []byte, secret []byte) (err error) {
 | 
			
		||||
	var pk, sk x25519lib.Key
 | 
			
		||||
	copy(sk[:], secret)
 | 
			
		||||
	x25519lib.KeyGen(&pk, &sk)
 | 
			
		||||
 | 
			
		||||
	if subtle.ConstantTimeCompare(point, pk[:]) == 0 {
 | 
			
		||||
		return errors.KeyInvalidError("ecc: invalid curve25519 public point")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func copyReversed(out []byte, in []byte) {
 | 
			
		||||
	l := len(in)
 | 
			
		||||
	for i := 0; i < l; i++ {
 | 
			
		||||
		out[i] = in[l-i-1]
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										140
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/curve_info.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										140
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/curve_info.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,140 @@
 | 
			
		||||
// Package ecc implements a generic interface for ECDH, ECDSA, and EdDSA.
 | 
			
		||||
package ecc
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"crypto/elliptic"
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/bitcurves"
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/brainpool"
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/openpgp/internal/encoding"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type CurveInfo struct {
 | 
			
		||||
	GenName string
 | 
			
		||||
	Oid *encoding.OID
 | 
			
		||||
	Curve Curve
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var Curves = []CurveInfo{
 | 
			
		||||
	{
 | 
			
		||||
		// NIST P-256
 | 
			
		||||
		GenName: "P256",
 | 
			
		||||
		Oid: encoding.NewOID([]byte{0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07}),
 | 
			
		||||
		Curve: NewGenericCurve(elliptic.P256()),
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		// NIST P-384
 | 
			
		||||
		GenName: "P384",
 | 
			
		||||
		Oid: encoding.NewOID([]byte{0x2B, 0x81, 0x04, 0x00, 0x22}),
 | 
			
		||||
		Curve: NewGenericCurve(elliptic.P384()),
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		// NIST P-521
 | 
			
		||||
		GenName: "P521",
 | 
			
		||||
		Oid: encoding.NewOID([]byte{0x2B, 0x81, 0x04, 0x00, 0x23}),
 | 
			
		||||
		Curve: NewGenericCurve(elliptic.P521()),
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		// SecP256k1
 | 
			
		||||
		GenName: "SecP256k1",
 | 
			
		||||
		Oid: encoding.NewOID([]byte{0x2B, 0x81, 0x04, 0x00, 0x0A}),
 | 
			
		||||
		Curve: NewGenericCurve(bitcurves.S256()),
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		// Curve25519
 | 
			
		||||
		GenName: "Curve25519",
 | 
			
		||||
		Oid: encoding.NewOID([]byte{0x2B, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01}),
 | 
			
		||||
		Curve: NewCurve25519(),
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		// X448
 | 
			
		||||
		GenName: "Curve448",
 | 
			
		||||
		Oid: encoding.NewOID([]byte{0x2B, 0x65, 0x6F}),
 | 
			
		||||
		Curve: NewX448(),
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		// Ed25519
 | 
			
		||||
		GenName: "Curve25519",
 | 
			
		||||
		Oid: encoding.NewOID([]byte{0x2B, 0x06, 0x01, 0x04, 0x01, 0xDA, 0x47, 0x0F, 0x01}),
 | 
			
		||||
		Curve: NewEd25519(),
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		// Ed448
 | 
			
		||||
		GenName: "Curve448",
 | 
			
		||||
		Oid: encoding.NewOID([]byte{0x2B, 0x65, 0x71}),
 | 
			
		||||
		Curve: NewEd448(),
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		// BrainpoolP256r1
 | 
			
		||||
		GenName: "BrainpoolP256",
 | 
			
		||||
		Oid: encoding.NewOID([]byte{0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x07}),
 | 
			
		||||
		Curve: NewGenericCurve(brainpool.P256r1()),
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		// BrainpoolP384r1
 | 
			
		||||
		GenName: "BrainpoolP384",
 | 
			
		||||
		Oid: encoding.NewOID([]byte{0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0B}),
 | 
			
		||||
		Curve: NewGenericCurve(brainpool.P384r1()),
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		// BrainpoolP512r1
 | 
			
		||||
		GenName: "BrainpoolP512",
 | 
			
		||||
		Oid: encoding.NewOID([]byte{0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0D}),
 | 
			
		||||
		Curve: NewGenericCurve(brainpool.P512r1()),
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func FindByCurve(curve Curve) *CurveInfo {
 | 
			
		||||
	for _, curveInfo := range Curves {
 | 
			
		||||
		if curveInfo.Curve.GetCurveName() == curve.GetCurveName() {
 | 
			
		||||
			return &curveInfo
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func FindByOid(oid encoding.Field) *CurveInfo {
 | 
			
		||||
	var rawBytes = oid.Bytes()
 | 
			
		||||
	for _, curveInfo := range Curves {
 | 
			
		||||
		if bytes.Equal(curveInfo.Oid.Bytes(), rawBytes) {
 | 
			
		||||
			return &curveInfo
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func FindEdDSAByGenName(curveGenName string) EdDSACurve {
 | 
			
		||||
	for _, curveInfo := range Curves {
 | 
			
		||||
		if curveInfo.GenName == curveGenName {
 | 
			
		||||
			curve, ok := curveInfo.Curve.(EdDSACurve)
 | 
			
		||||
			if ok {
 | 
			
		||||
				return curve
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func FindECDSAByGenName(curveGenName string) ECDSACurve {
 | 
			
		||||
	for _, curveInfo := range Curves {
 | 
			
		||||
		if curveInfo.GenName == curveGenName {
 | 
			
		||||
			curve, ok := curveInfo.Curve.(ECDSACurve)
 | 
			
		||||
			if ok {
 | 
			
		||||
				return curve
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func FindECDHByGenName(curveGenName string) ECDHCurve {
 | 
			
		||||
	for _, curveInfo := range Curves {
 | 
			
		||||
		if curveInfo.GenName == curveGenName {
 | 
			
		||||
			curve, ok := curveInfo.Curve.(ECDHCurve)
 | 
			
		||||
			if ok {
 | 
			
		||||
				return curve
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										48
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/curves.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/curves.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,48 @@
 | 
			
		||||
// Package ecc implements a generic interface for ECDH, ECDSA, and EdDSA.
 | 
			
		||||
package ecc
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"io"
 | 
			
		||||
	"math/big"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Curve interface {
 | 
			
		||||
	GetCurveName() string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ECDSACurve interface {
 | 
			
		||||
	Curve
 | 
			
		||||
	MarshalIntegerPoint(x, y *big.Int) []byte
 | 
			
		||||
	UnmarshalIntegerPoint([]byte) (x, y *big.Int)
 | 
			
		||||
	MarshalIntegerSecret(d *big.Int) []byte
 | 
			
		||||
	UnmarshalIntegerSecret(d []byte) *big.Int
 | 
			
		||||
	GenerateECDSA(rand io.Reader) (x, y, secret *big.Int, err error)
 | 
			
		||||
	Sign(rand io.Reader, x, y, d *big.Int, hash []byte) (r, s *big.Int, err error)
 | 
			
		||||
	Verify(x, y *big.Int, hash []byte, r, s *big.Int) bool
 | 
			
		||||
	ValidateECDSA(x, y *big.Int, secret []byte) error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type EdDSACurve interface {
 | 
			
		||||
	Curve
 | 
			
		||||
	MarshalBytePoint(x []byte) []byte
 | 
			
		||||
	UnmarshalBytePoint([]byte) (x []byte)
 | 
			
		||||
	MarshalByteSecret(d []byte) []byte
 | 
			
		||||
	UnmarshalByteSecret(d []byte) []byte
 | 
			
		||||
	MarshalSignature(sig []byte) (r, s []byte)
 | 
			
		||||
	UnmarshalSignature(r, s []byte) (sig []byte)
 | 
			
		||||
	GenerateEdDSA(rand io.Reader) (pub, priv []byte, err error)
 | 
			
		||||
	Sign(publicKey, privateKey, message []byte) (sig []byte, err error)
 | 
			
		||||
	Verify(publicKey, message, sig []byte) bool
 | 
			
		||||
	ValidateEdDSA(publicKey, privateKey []byte) (err error)
 | 
			
		||||
}
 | 
			
		||||
type ECDHCurve interface {
 | 
			
		||||
	Curve
 | 
			
		||||
	MarshalBytePoint([]byte) (encoded []byte)
 | 
			
		||||
	UnmarshalBytePoint(encoded []byte) ([]byte)
 | 
			
		||||
	MarshalByteSecret(d []byte) []byte
 | 
			
		||||
	UnmarshalByteSecret(d []byte) []byte
 | 
			
		||||
	GenerateECDH(rand io.Reader) (point []byte, secret []byte, err error)
 | 
			
		||||
	Encaps(rand io.Reader, point []byte) (ephemeral, sharedSecret []byte, err error)
 | 
			
		||||
	Decaps(ephemeral, secret []byte) (sharedSecret []byte, err error)
 | 
			
		||||
	ValidateECDH(public []byte, secret []byte) error
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										111
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/ed25519.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/ed25519.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,111 @@
 | 
			
		||||
// Package ecc implements a generic interface for ECDH, ECDSA, and EdDSA.
 | 
			
		||||
package ecc
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/subtle"
 | 
			
		||||
	"io"
 | 
			
		||||
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/openpgp/errors"
 | 
			
		||||
	ed25519lib "github.com/cloudflare/circl/sign/ed25519"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const ed25519Size = 32
 | 
			
		||||
type ed25519 struct {}
 | 
			
		||||
 | 
			
		||||
func NewEd25519() *ed25519 {
 | 
			
		||||
	return &ed25519{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *ed25519) GetCurveName() string {
 | 
			
		||||
	return "ed25519"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MarshalBytePoint encodes the public point from native format, adding the prefix.
 | 
			
		||||
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.5
 | 
			
		||||
func (c *ed25519) MarshalBytePoint(x []byte) []byte {
 | 
			
		||||
	return append([]byte{0x40}, x...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UnmarshalBytePoint decodes a point from prefixed format to native.
 | 
			
		||||
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.5
 | 
			
		||||
func (c *ed25519) UnmarshalBytePoint(point []byte) (x []byte) {
 | 
			
		||||
	if len(point) != ed25519lib.PublicKeySize + 1 {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Return unprefixed
 | 
			
		||||
	return point[1:]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MarshalByteSecret encodes a scalar in native format.
 | 
			
		||||
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.5
 | 
			
		||||
func (c *ed25519) MarshalByteSecret(d []byte) []byte {
 | 
			
		||||
	return d
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UnmarshalByteSecret decodes a scalar in native format and re-adds the stripped leading zeroes
 | 
			
		||||
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.5
 | 
			
		||||
func (c *ed25519) UnmarshalByteSecret(s []byte) (d []byte) {
 | 
			
		||||
	if len(s) > ed25519lib.SeedSize {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Handle stripped leading zeroes
 | 
			
		||||
	d = make([]byte, ed25519lib.SeedSize)
 | 
			
		||||
	copy(d[ed25519lib.SeedSize - len(s):], s)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MarshalSignature splits a signature in R and S.
 | 
			
		||||
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.2.3.3.1
 | 
			
		||||
func (c *ed25519) MarshalSignature(sig []byte) (r, s []byte) {
 | 
			
		||||
	return sig[:ed25519Size], sig[ed25519Size:]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UnmarshalSignature decodes R and S in the native format, re-adding the stripped leading zeroes
 | 
			
		||||
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.2.3.3.1
 | 
			
		||||
func (c *ed25519) UnmarshalSignature(r, s []byte) (sig []byte) {
 | 
			
		||||
	// Check size
 | 
			
		||||
	if len(r) > 32 || len(s) > 32 {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sig = make([]byte, ed25519lib.SignatureSize)
 | 
			
		||||
 | 
			
		||||
	// Handle stripped leading zeroes
 | 
			
		||||
	copy(sig[ed25519Size-len(r):ed25519Size], r)
 | 
			
		||||
	copy(sig[ed25519lib.SignatureSize-len(s):], s)
 | 
			
		||||
	return sig
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *ed25519) GenerateEdDSA(rand io.Reader) (pub, priv []byte, err error) {
 | 
			
		||||
	pk, sk, err := ed25519lib.GenerateKey(rand)
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return pk, sk[:ed25519lib.SeedSize], nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getEd25519Sk(publicKey, privateKey []byte) ed25519lib.PrivateKey {
 | 
			
		||||
	return append(privateKey, publicKey...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *ed25519) Sign(publicKey, privateKey, message []byte) (sig []byte, err error) {
 | 
			
		||||
	sig = ed25519lib.Sign(getEd25519Sk(publicKey, privateKey), message)
 | 
			
		||||
	return sig, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *ed25519) Verify(publicKey, message, sig []byte) bool {
 | 
			
		||||
	return ed25519lib.Verify(publicKey, message, sig)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *ed25519) ValidateEdDSA(publicKey, privateKey []byte) (err error) {
 | 
			
		||||
	priv := getEd25519Sk(publicKey, privateKey)
 | 
			
		||||
	expectedPriv := ed25519lib.NewKeyFromSeed(priv.Seed())
 | 
			
		||||
	if subtle.ConstantTimeCompare(priv, expectedPriv) == 0 {
 | 
			
		||||
		return errors.KeyInvalidError("ecc: invalid ed25519 secret")
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										111
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/ed448.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/ed448.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,111 @@
 | 
			
		||||
// Package ecc implements a generic interface for ECDH, ECDSA, and EdDSA.
 | 
			
		||||
package ecc
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/subtle"
 | 
			
		||||
	"io"
 | 
			
		||||
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/openpgp/errors"
 | 
			
		||||
	ed448lib "github.com/cloudflare/circl/sign/ed448"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type ed448 struct {}
 | 
			
		||||
 | 
			
		||||
func NewEd448() *ed448 {
 | 
			
		||||
	return &ed448{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *ed448) GetCurveName() string {
 | 
			
		||||
	return "ed448"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MarshalBytePoint encodes the public point from native format, adding the prefix.
 | 
			
		||||
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.5
 | 
			
		||||
func (c *ed448) MarshalBytePoint(x []byte) []byte {
 | 
			
		||||
	// Return prefixed
 | 
			
		||||
	return append([]byte{0x40}, x...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UnmarshalBytePoint decodes a point from prefixed format to native.
 | 
			
		||||
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.5
 | 
			
		||||
func (c *ed448) UnmarshalBytePoint(point []byte) (x []byte) {
 | 
			
		||||
	if len(point) != ed448lib.PublicKeySize + 1 {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Strip prefix
 | 
			
		||||
	return point[1:]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MarshalByteSecret encoded a scalar from native format to prefixed.
 | 
			
		||||
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.5
 | 
			
		||||
func (c *ed448) MarshalByteSecret(d []byte) []byte {
 | 
			
		||||
	// Return prefixed
 | 
			
		||||
	return append([]byte{0x40}, d...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UnmarshalByteSecret decodes a scalar from prefixed format to native.
 | 
			
		||||
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.5
 | 
			
		||||
func (c *ed448) UnmarshalByteSecret(s []byte) (d []byte) {
 | 
			
		||||
	// Check prefixed size
 | 
			
		||||
	if len(s) != ed448lib.SeedSize + 1 {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Strip prefix
 | 
			
		||||
	return s[1:]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MarshalSignature splits a signature in R and S, where R is in prefixed native format and
 | 
			
		||||
// S is an MPI with value zero.
 | 
			
		||||
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.2.3.3.2
 | 
			
		||||
func (c *ed448) MarshalSignature(sig []byte) (r, s []byte) {
 | 
			
		||||
	return append([]byte{0x40}, sig...), []byte{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UnmarshalSignature decodes R and S in the native format. Only R is used, in prefixed native format.
 | 
			
		||||
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.2.3.3.2
 | 
			
		||||
func (c *ed448) UnmarshalSignature(r, s []byte) (sig []byte) {
 | 
			
		||||
	if len(r) != ed448lib.SignatureSize + 1 {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return r[1:]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *ed448) GenerateEdDSA(rand io.Reader) (pub, priv []byte, err error) {
 | 
			
		||||
	pk, sk, err := ed448lib.GenerateKey(rand)
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return pk, sk[:ed448lib.SeedSize], nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getEd448Sk(publicKey, privateKey []byte) ed448lib.PrivateKey {
 | 
			
		||||
	return append(privateKey, publicKey...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *ed448) Sign(publicKey, privateKey, message []byte) (sig []byte, err error) {
 | 
			
		||||
	// Ed448 is used with the empty string as a context string.
 | 
			
		||||
	// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-13.7
 | 
			
		||||
	sig = ed448lib.Sign(getEd448Sk(publicKey, privateKey), message, "")
 | 
			
		||||
 | 
			
		||||
	return sig, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *ed448) Verify(publicKey, message, sig []byte) bool {
 | 
			
		||||
	// Ed448 is used with the empty string as a context string.
 | 
			
		||||
	// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-13.7
 | 
			
		||||
	return ed448lib.Verify(publicKey, message, sig, "")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *ed448) ValidateEdDSA(publicKey, privateKey []byte) (err error) {
 | 
			
		||||
	priv := getEd448Sk(publicKey, privateKey)
 | 
			
		||||
	expectedPriv := ed448lib.NewKeyFromSeed(priv.Seed())
 | 
			
		||||
	if subtle.ConstantTimeCompare(priv, expectedPriv) == 0 {
 | 
			
		||||
		return errors.KeyInvalidError("ecc: invalid ed448 secret")
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										149
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/generic.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										149
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/generic.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,149 @@
 | 
			
		||||
// Package ecc implements a generic interface for ECDH, ECDSA, and EdDSA.
 | 
			
		||||
package ecc
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/ecdsa"
 | 
			
		||||
	"crypto/elliptic"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/openpgp/errors"
 | 
			
		||||
	"io"
 | 
			
		||||
	"math/big"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type genericCurve struct {
 | 
			
		||||
	Curve elliptic.Curve
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewGenericCurve(c elliptic.Curve) *genericCurve {
 | 
			
		||||
	return &genericCurve{
 | 
			
		||||
		Curve: c,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *genericCurve) GetCurveName() string {
 | 
			
		||||
	return c.Curve.Params().Name
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *genericCurve) MarshalBytePoint(point []byte) []byte {
 | 
			
		||||
	return point
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *genericCurve) UnmarshalBytePoint(point []byte) []byte {
 | 
			
		||||
	return point
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *genericCurve) MarshalIntegerPoint(x, y *big.Int) []byte {
 | 
			
		||||
	return elliptic.Marshal(c.Curve, x, y)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *genericCurve) UnmarshalIntegerPoint(point []byte) (x, y *big.Int) {
 | 
			
		||||
	return elliptic.Unmarshal(c.Curve, point)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *genericCurve) MarshalByteSecret(d []byte) []byte {
 | 
			
		||||
	return d
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *genericCurve) UnmarshalByteSecret(d []byte) []byte {
 | 
			
		||||
	return d
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *genericCurve) MarshalIntegerSecret(d *big.Int) []byte {
 | 
			
		||||
	return d.Bytes()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *genericCurve) UnmarshalIntegerSecret(d []byte) *big.Int {
 | 
			
		||||
	return new(big.Int).SetBytes(d)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *genericCurve) GenerateECDH(rand io.Reader) (point, secret []byte, err error) {
 | 
			
		||||
	secret, x, y, err := elliptic.GenerateKey(c.Curve, rand)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	point = elliptic.Marshal(c.Curve, x, y)
 | 
			
		||||
	return point, secret, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *genericCurve) GenerateECDSA(rand io.Reader) (x, y, secret *big.Int, err error) {
 | 
			
		||||
	priv, err := ecdsa.GenerateKey(c.Curve, rand)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return priv.X, priv.Y, priv.D, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *genericCurve) Encaps(rand io.Reader, point []byte) (ephemeral, sharedSecret []byte, err error) {
 | 
			
		||||
	xP, yP := elliptic.Unmarshal(c.Curve, point)
 | 
			
		||||
	if xP == nil {
 | 
			
		||||
		panic("invalid point")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	d, x, y, err := elliptic.GenerateKey(c.Curve, rand)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	vsG := elliptic.Marshal(c.Curve, x, y)
 | 
			
		||||
	zbBig, _ := c.Curve.ScalarMult(xP, yP, d)
 | 
			
		||||
 | 
			
		||||
	byteLen := (c.Curve.Params().BitSize + 7) >> 3
 | 
			
		||||
	zb := make([]byte, byteLen)
 | 
			
		||||
	zbBytes := zbBig.Bytes()
 | 
			
		||||
	copy(zb[byteLen-len(zbBytes):], zbBytes)
 | 
			
		||||
 | 
			
		||||
	return vsG, zb, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *genericCurve) Decaps(ephemeral, secret []byte) (sharedSecret []byte, err error) {
 | 
			
		||||
	x, y := elliptic.Unmarshal(c.Curve, ephemeral)
 | 
			
		||||
	zbBig, _ := c.Curve.ScalarMult(x, y, secret)
 | 
			
		||||
	byteLen := (c.Curve.Params().BitSize + 7) >> 3
 | 
			
		||||
	zb := make([]byte, byteLen)
 | 
			
		||||
	zbBytes := zbBig.Bytes()
 | 
			
		||||
	copy(zb[byteLen-len(zbBytes):], zbBytes)
 | 
			
		||||
 | 
			
		||||
	return zb, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *genericCurve) Sign(rand io.Reader, x, y, d *big.Int, hash []byte) (r, s *big.Int, err error) {
 | 
			
		||||
	priv := &ecdsa.PrivateKey{D: d, PublicKey: ecdsa.PublicKey{X: x, Y: y, Curve: c.Curve}}
 | 
			
		||||
	return ecdsa.Sign(rand, priv, hash)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *genericCurve) Verify(x, y *big.Int, hash []byte, r, s *big.Int) bool {
 | 
			
		||||
	pub := &ecdsa.PublicKey{X: x, Y: y, Curve: c.Curve}
 | 
			
		||||
	return ecdsa.Verify(pub, hash, r, s)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *genericCurve) validate(xP, yP *big.Int, secret []byte) error {
 | 
			
		||||
	// the public point should not be at infinity (0,0)
 | 
			
		||||
	zero := new(big.Int)
 | 
			
		||||
	if xP.Cmp(zero) == 0 && yP.Cmp(zero) == 0 {
 | 
			
		||||
		return errors.KeyInvalidError(fmt.Sprintf("ecc (%s): infinity point", c.Curve.Params().Name))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// re-derive the public point Q' = (X,Y) = dG
 | 
			
		||||
	// to compare to declared Q in public key
 | 
			
		||||
	expectedX, expectedY := c.Curve.ScalarBaseMult(secret)
 | 
			
		||||
	if xP.Cmp(expectedX) != 0 || yP.Cmp(expectedY) != 0 {
 | 
			
		||||
		return errors.KeyInvalidError(fmt.Sprintf("ecc (%s): invalid point", c.Curve.Params().Name))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *genericCurve) ValidateECDSA(xP, yP *big.Int, secret []byte) error {
 | 
			
		||||
	return c.validate(xP, yP, secret)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *genericCurve) ValidateECDH(point []byte, secret []byte) error {
 | 
			
		||||
	xP, yP := elliptic.Unmarshal(c.Curve, point)
 | 
			
		||||
	if xP == nil {
 | 
			
		||||
		return errors.KeyInvalidError(fmt.Sprintf("ecc (%s): invalid point", c.Curve.Params().Name))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return c.validate(xP, yP, secret)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										105
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/x448.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/x448.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,105 @@
 | 
			
		||||
// Package ecc implements a generic interface for ECDH, ECDSA, and EdDSA.
 | 
			
		||||
package ecc
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/subtle"
 | 
			
		||||
	"io"
 | 
			
		||||
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/openpgp/errors"
 | 
			
		||||
	x448lib "github.com/cloudflare/circl/dh/x448"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type x448 struct {}
 | 
			
		||||
 | 
			
		||||
func NewX448() *x448 {
 | 
			
		||||
	return &x448{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *x448) GetCurveName() string {
 | 
			
		||||
	return "x448"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MarshalBytePoint encodes the public point from native format, adding the prefix.
 | 
			
		||||
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.6
 | 
			
		||||
func (c *x448) MarshalBytePoint(point []byte) []byte {
 | 
			
		||||
	return append([]byte{0x40}, point...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UnmarshalBytePoint decodes a point from prefixed format to native.
 | 
			
		||||
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.6
 | 
			
		||||
func (c *x448) UnmarshalBytePoint(point []byte) []byte {
 | 
			
		||||
	if len(point) != x448lib.Size + 1 {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return point[1:]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MarshalByteSecret encoded a scalar from native format to prefixed.
 | 
			
		||||
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.6.1.2
 | 
			
		||||
func (c *x448) MarshalByteSecret(d []byte) []byte {
 | 
			
		||||
	return append([]byte{0x40}, d...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UnmarshalByteSecret decodes a scalar from prefixed format to native.
 | 
			
		||||
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.6.1.2
 | 
			
		||||
func (c *x448) UnmarshalByteSecret(d []byte) []byte {
 | 
			
		||||
	if len(d) != x448lib.Size + 1 {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Store without prefix
 | 
			
		||||
	return d[1:]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *x448) generateKeyPairBytes(rand io.Reader) (sk, pk x448lib.Key, err error) {
 | 
			
		||||
	if _, err = rand.Read(sk[:]); err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	x448lib.KeyGen(&pk, &sk)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *x448) GenerateECDH(rand io.Reader) (point []byte, secret []byte, err error) {
 | 
			
		||||
	priv, pub, err := c.generateKeyPairBytes(rand)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return pub[:], priv[:], nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *x448) Encaps(rand io.Reader, point []byte) (ephemeral, sharedSecret []byte, err error) {
 | 
			
		||||
	var pk, ss x448lib.Key
 | 
			
		||||
	seed, e, err := c.generateKeyPairBytes(rand)
 | 
			
		||||
 | 
			
		||||
	copy(pk[:], point)
 | 
			
		||||
	x448lib.Shared(&ss, &seed, &pk)
 | 
			
		||||
 | 
			
		||||
	return e[:], ss[:], nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *x448) Decaps(ephemeral, secret []byte) (sharedSecret []byte, err error) {
 | 
			
		||||
	var ss, sk, e x448lib.Key
 | 
			
		||||
 | 
			
		||||
	copy(sk[:], secret)
 | 
			
		||||
	copy(e[:], ephemeral)
 | 
			
		||||
	x448lib.Shared(&ss, &sk, &e)
 | 
			
		||||
 | 
			
		||||
	return ss[:], nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *x448) ValidateECDH(point []byte, secret []byte) error {
 | 
			
		||||
	var sk, pk, expectedPk x448lib.Key
 | 
			
		||||
 | 
			
		||||
	copy(pk[:], point)
 | 
			
		||||
	copy(sk[:], secret)
 | 
			
		||||
	x448lib.KeyGen(&expectedPk, &sk)
 | 
			
		||||
 | 
			
		||||
	if subtle.ConstantTimeCompare(expectedPk[:], pk[:]) == 0 {
 | 
			
		||||
		return errors.KeyInvalidError("ecc: invalid curve25519 public point")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										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 argument too large")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &OID{
 | 
			
		||||
		bytes: bytes,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Bytes returns the decoded data.
 | 
			
		||||
func (o *OID) Bytes() []byte {
 | 
			
		||||
	return o.bytes
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// BitLength is the size in bits of the decoded data.
 | 
			
		||||
func (o *OID) BitLength() uint16 {
 | 
			
		||||
	return uint16(len(o.bytes) * 8)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// EncodedBytes returns the encoded data.
 | 
			
		||||
func (o *OID) EncodedBytes() []byte {
 | 
			
		||||
	return append([]byte{byte(len(o.bytes))}, o.bytes...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// EncodedLength is the size in bytes of the encoded data.
 | 
			
		||||
func (o *OID) EncodedLength() uint16 {
 | 
			
		||||
	return uint16(1 + len(o.bytes))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ReadFrom reads into b the next OID from r.
 | 
			
		||||
func (o *OID) ReadFrom(r io.Reader) (int64, error) {
 | 
			
		||||
	var buf [1]byte
 | 
			
		||||
	n, err := io.ReadFull(r, buf[:])
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if err == io.EOF {
 | 
			
		||||
			err = io.ErrUnexpectedEOF
 | 
			
		||||
		}
 | 
			
		||||
		return int64(n), err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch buf[0] {
 | 
			
		||||
	case reservedOIDLength1, reservedOIDLength2:
 | 
			
		||||
		return int64(n), errors.UnsupportedError("reserved for future extensions")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	o.bytes = make([]byte, buf[0])
 | 
			
		||||
 | 
			
		||||
	nn, err := io.ReadFull(r, o.bytes)
 | 
			
		||||
	if err == io.EOF {
 | 
			
		||||
		err = io.ErrUnexpectedEOF
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return int64(n) + int64(nn), err
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										403
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/key_generation.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										403
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/key_generation.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,403 @@
 | 
			
		||||
// Copyright 2011 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package openpgp
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto"
 | 
			
		||||
	"crypto/rand"
 | 
			
		||||
	"crypto/rsa"
 | 
			
		||||
	goerrors "errors"
 | 
			
		||||
	"io"
 | 
			
		||||
	"math/big"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/openpgp/ecdh"
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/openpgp/ecdsa"
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/openpgp/eddsa"
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/openpgp/errors"
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/openpgp/internal/algorithm"
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/openpgp/internal/ecc"
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/openpgp/packet"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// NewEntity returns an Entity that contains a fresh RSA/RSA keypair with a
 | 
			
		||||
// single identity composed of the given full name, comment and email, any of
 | 
			
		||||
// which may be empty but must not contain any of "()<>\x00".
 | 
			
		||||
// If config is nil, sensible defaults will be used.
 | 
			
		||||
func NewEntity(name, comment, email string, config *packet.Config) (*Entity, error) {
 | 
			
		||||
	creationTime := config.Now()
 | 
			
		||||
	keyLifetimeSecs := config.KeyLifetime()
 | 
			
		||||
 | 
			
		||||
	// Generate a primary signing key
 | 
			
		||||
	primaryPrivRaw, err := newSigner(config)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	primary := packet.NewSignerPrivateKey(creationTime, primaryPrivRaw)
 | 
			
		||||
	if config != nil && config.V5Keys {
 | 
			
		||||
		primary.UpgradeToV5()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	e := &Entity{
 | 
			
		||||
		PrimaryKey: &primary.PublicKey,
 | 
			
		||||
		PrivateKey: primary,
 | 
			
		||||
		Identities: make(map[string]*Identity),
 | 
			
		||||
		Subkeys:    []Subkey{},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = e.addUserId(name, comment, email, config, creationTime, keyLifetimeSecs)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// NOTE: No key expiry here, but we will not return this subkey in EncryptionKey()
 | 
			
		||||
	// if the primary/master key has expired.
 | 
			
		||||
	err = e.addEncryptionSubkey(config, creationTime, 0)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return e, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (t *Entity) AddUserId(name, comment, email string, config *packet.Config) error {
 | 
			
		||||
	creationTime := config.Now()
 | 
			
		||||
	keyLifetimeSecs := config.KeyLifetime()
 | 
			
		||||
	return t.addUserId(name, comment, email, config, creationTime, keyLifetimeSecs)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (t *Entity) addUserId(name, comment, email string, config *packet.Config, creationTime time.Time, keyLifetimeSecs uint32) error {
 | 
			
		||||
	uid := packet.NewUserId(name, comment, email)
 | 
			
		||||
	if uid == nil {
 | 
			
		||||
		return errors.InvalidArgumentError("user id field contained invalid characters")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if _, ok := t.Identities[uid.Id]; ok {
 | 
			
		||||
		return errors.InvalidArgumentError("user id exist")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	primary := t.PrivateKey
 | 
			
		||||
 | 
			
		||||
	isPrimaryId := len(t.Identities) == 0
 | 
			
		||||
 | 
			
		||||
	selfSignature := &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))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// We set CompressionNone as the preferred compression algorithm because
 | 
			
		||||
	// of compression side channel attacks, then append the configured
 | 
			
		||||
	// DefaultCompressionAlgo if any is set (to signal support for cases
 | 
			
		||||
	// where the application knows that using compression is safe).
 | 
			
		||||
	selfSignature.PreferredCompression = []uint8{uint8(packet.CompressionNone)}
 | 
			
		||||
	if config.Compression() != packet.CompressionNone {
 | 
			
		||||
		selfSignature.PreferredCompression = append(selfSignature.PreferredCompression, uint8(config.Compression()))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// And for DefaultMode.
 | 
			
		||||
	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 err
 | 
			
		||||
	}
 | 
			
		||||
	t.Identities[uid.Id] = &Identity{
 | 
			
		||||
		Name:          uid.Id,
 | 
			
		||||
		UserId:        uid,
 | 
			
		||||
		SelfSignature: selfSignature,
 | 
			
		||||
		Signatures:    []*packet.Signature{selfSignature},
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AddSigningSubkey adds a signing keypair as a subkey to the Entity.
 | 
			
		||||
// If config is nil, sensible defaults will be used.
 | 
			
		||||
func (e *Entity) AddSigningSubkey(config *packet.Config) error {
 | 
			
		||||
	creationTime := config.Now()
 | 
			
		||||
	keyLifetimeSecs := config.KeyLifetime()
 | 
			
		||||
 | 
			
		||||
	subPrivRaw, err := newSigner(config)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	sub := packet.NewSignerPrivateKey(creationTime, subPrivRaw)
 | 
			
		||||
 | 
			
		||||
	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()
 | 
			
		||||
	return e.addEncryptionSubkey(config, creationTime, keyLifetimeSecs)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e *Entity) addEncryptionSubkey(config *packet.Config, creationTime time.Time, keyLifetimeSecs uint32) error {
 | 
			
		||||
	subPrivRaw, err := newDecrypter(config)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	sub := packet.NewDecrypterPrivateKey(creationTime, subPrivRaw)
 | 
			
		||||
 | 
			
		||||
	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 interface{}, err error) {
 | 
			
		||||
	switch config.PublicKeyAlgorithm() {
 | 
			
		||||
	case packet.PubKeyAlgoRSA:
 | 
			
		||||
		bits := config.RSAModulusBits()
 | 
			
		||||
		if bits < 1024 {
 | 
			
		||||
			return nil, errors.InvalidArgumentError("bits must be >= 1024")
 | 
			
		||||
		}
 | 
			
		||||
		if config != nil && len(config.RSAPrimes) >= 2 {
 | 
			
		||||
			primes := config.RSAPrimes[0:2]
 | 
			
		||||
			config.RSAPrimes = config.RSAPrimes[2:]
 | 
			
		||||
			return generateRSAKeyWithPrimes(config.Random(), 2, bits, primes)
 | 
			
		||||
		}
 | 
			
		||||
		return rsa.GenerateKey(config.Random(), bits)
 | 
			
		||||
	case packet.PubKeyAlgoEdDSA:
 | 
			
		||||
		curve := ecc.FindEdDSAByGenName(string(config.CurveName()))
 | 
			
		||||
		if curve == nil {
 | 
			
		||||
			return nil, errors.InvalidArgumentError("unsupported curve")
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		priv, err := eddsa.GenerateKey(config.Random(), curve)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		return priv, nil
 | 
			
		||||
	case packet.PubKeyAlgoECDSA:
 | 
			
		||||
		curve := ecc.FindECDSAByGenName(string(config.CurveName()))
 | 
			
		||||
		if curve == nil {
 | 
			
		||||
			return nil, errors.InvalidArgumentError("unsupported curve")
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		priv, err := ecdsa.GenerateKey(config.Random(), curve)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		return priv, nil
 | 
			
		||||
	default:
 | 
			
		||||
		return nil, errors.InvalidArgumentError("unsupported public key algorithm")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Generates an encryption/decryption key
 | 
			
		||||
func newDecrypter(config *packet.Config) (decrypter interface{}, err error) {
 | 
			
		||||
	switch config.PublicKeyAlgorithm() {
 | 
			
		||||
	case packet.PubKeyAlgoRSA:
 | 
			
		||||
		bits := config.RSAModulusBits()
 | 
			
		||||
		if bits < 1024 {
 | 
			
		||||
			return nil, errors.InvalidArgumentError("bits must be >= 1024")
 | 
			
		||||
		}
 | 
			
		||||
		if config != nil && len(config.RSAPrimes) >= 2 {
 | 
			
		||||
			primes := config.RSAPrimes[0:2]
 | 
			
		||||
			config.RSAPrimes = config.RSAPrimes[2:]
 | 
			
		||||
			return generateRSAKeyWithPrimes(config.Random(), 2, bits, primes)
 | 
			
		||||
		}
 | 
			
		||||
		return rsa.GenerateKey(config.Random(), bits)
 | 
			
		||||
	case packet.PubKeyAlgoEdDSA, packet.PubKeyAlgoECDSA:
 | 
			
		||||
		fallthrough // When passing EdDSA or ECDSA, we generate an ECDH subkey
 | 
			
		||||
	case packet.PubKeyAlgoECDH:
 | 
			
		||||
		var kdf = ecdh.KDF{
 | 
			
		||||
			Hash:   algorithm.SHA512,
 | 
			
		||||
			Cipher: algorithm.AES256,
 | 
			
		||||
		}
 | 
			
		||||
		curve := ecc.FindECDHByGenName(string(config.CurveName()))
 | 
			
		||||
		if curve == nil {
 | 
			
		||||
			return nil, errors.InvalidArgumentError("unsupported curve")
 | 
			
		||||
		}
 | 
			
		||||
		return ecdh.GenerateKey(config.Random(), curve, kdf)
 | 
			
		||||
	default:
 | 
			
		||||
		return nil, errors.InvalidArgumentError("unsupported public key algorithm")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var bigOne = big.NewInt(1)
 | 
			
		||||
 | 
			
		||||
// generateRSAKeyWithPrimes generates a multi-prime RSA keypair of the
 | 
			
		||||
// given bit size, using the given random source and prepopulated primes.
 | 
			
		||||
func generateRSAKeyWithPrimes(random io.Reader, nprimes int, bits int, prepopulatedPrimes []*big.Int) (*rsa.PrivateKey, error) {
 | 
			
		||||
	priv := new(rsa.PrivateKey)
 | 
			
		||||
	priv.E = 65537
 | 
			
		||||
 | 
			
		||||
	if nprimes < 2 {
 | 
			
		||||
		return nil, goerrors.New("generateRSAKeyWithPrimes: nprimes must be >= 2")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if bits < 1024 {
 | 
			
		||||
		return nil, goerrors.New("generateRSAKeyWithPrimes: bits must be >= 1024")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	primes := make([]*big.Int, nprimes)
 | 
			
		||||
 | 
			
		||||
NextSetOfPrimes:
 | 
			
		||||
	for {
 | 
			
		||||
		todo := bits
 | 
			
		||||
		// crypto/rand should set the top two bits in each prime.
 | 
			
		||||
		// Thus each prime has the form
 | 
			
		||||
		//   p_i = 2^bitlen(p_i) × 0.11... (in base 2).
 | 
			
		||||
		// And the product is:
 | 
			
		||||
		//   P = 2^todo × α
 | 
			
		||||
		// where α is the product of nprimes numbers of the form 0.11...
 | 
			
		||||
		//
 | 
			
		||||
		// If α < 1/2 (which can happen for nprimes > 2), we need to
 | 
			
		||||
		// shift todo to compensate for lost bits: the mean value of 0.11...
 | 
			
		||||
		// is 7/8, so todo + shift - nprimes * log2(7/8) ~= bits - 1/2
 | 
			
		||||
		// will give good results.
 | 
			
		||||
		if nprimes >= 7 {
 | 
			
		||||
			todo += (nprimes - 2) / 5
 | 
			
		||||
		}
 | 
			
		||||
		for i := 0; i < nprimes; i++ {
 | 
			
		||||
			var err error
 | 
			
		||||
			if len(prepopulatedPrimes) == 0 {
 | 
			
		||||
				primes[i], err = rand.Prime(random, todo/(nprimes-i))
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return nil, err
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				primes[i] = prepopulatedPrimes[0]
 | 
			
		||||
				prepopulatedPrimes = prepopulatedPrimes[1:]
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			todo -= primes[i].BitLen()
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Make sure that primes is pairwise unequal.
 | 
			
		||||
		for i, prime := range primes {
 | 
			
		||||
			for j := 0; j < i; j++ {
 | 
			
		||||
				if prime.Cmp(primes[j]) == 0 {
 | 
			
		||||
					continue NextSetOfPrimes
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		n := new(big.Int).Set(bigOne)
 | 
			
		||||
		totient := new(big.Int).Set(bigOne)
 | 
			
		||||
		pminus1 := new(big.Int)
 | 
			
		||||
		for _, prime := range primes {
 | 
			
		||||
			n.Mul(n, prime)
 | 
			
		||||
			pminus1.Sub(prime, bigOne)
 | 
			
		||||
			totient.Mul(totient, pminus1)
 | 
			
		||||
		}
 | 
			
		||||
		if n.BitLen() != bits {
 | 
			
		||||
			// This should never happen for nprimes == 2 because
 | 
			
		||||
			// crypto/rand should set the top two bits in each prime.
 | 
			
		||||
			// For nprimes > 2 we hope it does not happen often.
 | 
			
		||||
			continue NextSetOfPrimes
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		priv.D = new(big.Int)
 | 
			
		||||
		e := big.NewInt(int64(priv.E))
 | 
			
		||||
		ok := priv.D.ModInverse(e, totient)
 | 
			
		||||
 | 
			
		||||
		if ok != nil {
 | 
			
		||||
			priv.Primes = primes
 | 
			
		||||
			priv.N = n
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	priv.Precompute()
 | 
			
		||||
	return priv, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										829
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/keys.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										829
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/keys.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,829 @@
 | 
			
		||||
// Copyright 2011 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package openpgp
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	goerrors "errors"
 | 
			
		||||
	"io"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/openpgp/armor"
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/openpgp/errors"
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/openpgp/packet"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// PublicKeyType is the armor type for a PGP public key.
 | 
			
		||||
var PublicKeyType = "PGP PUBLIC KEY BLOCK"
 | 
			
		||||
 | 
			
		||||
// PrivateKeyType is the armor type for a PGP private key.
 | 
			
		||||
var PrivateKeyType = "PGP PRIVATE KEY BLOCK"
 | 
			
		||||
 | 
			
		||||
// An Entity represents the components of an OpenPGP key: a primary public key
 | 
			
		||||
// (which must be a signing key), one or more identities claimed by that key,
 | 
			
		||||
// and zero or more subkeys, which may be encryption keys.
 | 
			
		||||
type Entity struct {
 | 
			
		||||
	PrimaryKey  *packet.PublicKey
 | 
			
		||||
	PrivateKey  *packet.PrivateKey
 | 
			
		||||
	Identities  map[string]*Identity // indexed by Identity.Name
 | 
			
		||||
	Revocations []*packet.Signature
 | 
			
		||||
	Subkeys     []Subkey
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// An Identity represents an identity claimed by an Entity and zero or more
 | 
			
		||||
// assertions by other entities about that claim.
 | 
			
		||||
type Identity struct {
 | 
			
		||||
	Name          string // by convention, has the form "Full Name (comment) <email@example.com>"
 | 
			
		||||
	UserId        *packet.UserId
 | 
			
		||||
	SelfSignature *packet.Signature
 | 
			
		||||
	Revocations   []*packet.Signature
 | 
			
		||||
	Signatures    []*packet.Signature // all (potentially unverified) self-signatures, revocations, and third-party signatures
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A Subkey is an additional public key in an Entity. Subkeys can be used for
 | 
			
		||||
// encryption.
 | 
			
		||||
type Subkey struct {
 | 
			
		||||
	PublicKey   *packet.PublicKey
 | 
			
		||||
	PrivateKey  *packet.PrivateKey
 | 
			
		||||
	Sig         *packet.Signature
 | 
			
		||||
	Revocations []*packet.Signature
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A Key identifies a specific public key in an Entity. This is either the
 | 
			
		||||
// Entity's primary key or a subkey.
 | 
			
		||||
type Key struct {
 | 
			
		||||
	Entity        *Entity
 | 
			
		||||
	PublicKey     *packet.PublicKey
 | 
			
		||||
	PrivateKey    *packet.PrivateKey
 | 
			
		||||
	SelfSignature *packet.Signature
 | 
			
		||||
	Revocations   []*packet.Signature
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A KeyRing provides access to public and private keys.
 | 
			
		||||
type KeyRing interface {
 | 
			
		||||
	// KeysById returns the set of keys that have the given key id.
 | 
			
		||||
	KeysById(id uint64) []Key
 | 
			
		||||
	// KeysByIdAndUsage returns the set of keys with the given id
 | 
			
		||||
	// that also meet the key usage given by requiredUsage.
 | 
			
		||||
	// The requiredUsage is expressed as the bitwise-OR of
 | 
			
		||||
	// packet.KeyFlag* values.
 | 
			
		||||
	KeysByIdUsage(id uint64, requiredUsage byte) []Key
 | 
			
		||||
	// DecryptionKeys returns all private keys that are valid for
 | 
			
		||||
	// decryption.
 | 
			
		||||
	DecryptionKeys() []Key
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PrimaryIdentity returns an Identity, preferring non-revoked identities,
 | 
			
		||||
// identities marked as primary, or the latest-created identity, in that order.
 | 
			
		||||
func (e *Entity) PrimaryIdentity() *Identity {
 | 
			
		||||
	var primaryIdentity *Identity
 | 
			
		||||
	for _, ident := range e.Identities {
 | 
			
		||||
		if shouldPreferIdentity(primaryIdentity, ident) {
 | 
			
		||||
			primaryIdentity = ident
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return primaryIdentity
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func shouldPreferIdentity(existingId, potentialNewId *Identity) bool {
 | 
			
		||||
	if existingId == nil {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(existingId.Revocations) > len(potentialNewId.Revocations) {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(existingId.Revocations) < len(potentialNewId.Revocations) {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if existingId.SelfSignature == nil {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if existingId.SelfSignature.IsPrimaryId != nil && *existingId.SelfSignature.IsPrimaryId &&
 | 
			
		||||
		!(potentialNewId.SelfSignature.IsPrimaryId != nil && *potentialNewId.SelfSignature.IsPrimaryId) {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !(existingId.SelfSignature.IsPrimaryId != nil && *existingId.SelfSignature.IsPrimaryId) &&
 | 
			
		||||
		potentialNewId.SelfSignature.IsPrimaryId != nil && *potentialNewId.SelfSignature.IsPrimaryId {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return potentialNewId.SelfSignature.CreationTime.After(existingId.SelfSignature.CreationTime)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// EncryptionKey returns the best candidate Key for encrypting a message to the
 | 
			
		||||
// given Entity.
 | 
			
		||||
func (e *Entity) EncryptionKey(now time.Time) (Key, bool) {
 | 
			
		||||
	// Fail to find any encryption key if the...
 | 
			
		||||
	i := e.PrimaryIdentity()
 | 
			
		||||
	if e.PrimaryKey.KeyExpired(i.SelfSignature, now) || // primary key has expired
 | 
			
		||||
		i.SelfSignature == nil || // user ID has no self-signature
 | 
			
		||||
		i.SelfSignature.SigExpired(now) || // user ID self-signature has expired
 | 
			
		||||
		e.Revoked(now) || // primary key has been revoked
 | 
			
		||||
		i.Revoked(now) { // user ID has been revoked
 | 
			
		||||
		return Key{}, false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Iterate the keys to find the newest, unexpired one
 | 
			
		||||
	candidateSubkey := -1
 | 
			
		||||
	var maxTime time.Time
 | 
			
		||||
	for i, subkey := range e.Subkeys {
 | 
			
		||||
		if subkey.Sig.FlagsValid &&
 | 
			
		||||
			subkey.Sig.FlagEncryptCommunications &&
 | 
			
		||||
			subkey.PublicKey.PubKeyAlgo.CanEncrypt() &&
 | 
			
		||||
			!subkey.PublicKey.KeyExpired(subkey.Sig, now) &&
 | 
			
		||||
			!subkey.Sig.SigExpired(now) &&
 | 
			
		||||
			!subkey.Revoked(now) &&
 | 
			
		||||
			(maxTime.IsZero() || subkey.Sig.CreationTime.After(maxTime)) {
 | 
			
		||||
			candidateSubkey = i
 | 
			
		||||
			maxTime = subkey.Sig.CreationTime
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if candidateSubkey != -1 {
 | 
			
		||||
		subkey := e.Subkeys[candidateSubkey]
 | 
			
		||||
		return Key{e, subkey.PublicKey, subkey.PrivateKey, subkey.Sig, subkey.Revocations}, true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// If we don't have any candidate subkeys for encryption and
 | 
			
		||||
	// the primary key doesn't have any usage metadata then we
 | 
			
		||||
	// assume that the primary key is ok. Or, if the primary key is
 | 
			
		||||
	// marked as ok to encrypt with, then we can obviously use it.
 | 
			
		||||
	if !i.SelfSignature.FlagsValid || i.SelfSignature.FlagEncryptCommunications &&
 | 
			
		||||
		e.PrimaryKey.PubKeyAlgo.CanEncrypt() {
 | 
			
		||||
		return Key{e, e.PrimaryKey, e.PrivateKey, i.SelfSignature, e.Revocations}, true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return Key{}, false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// CertificationKey return the best candidate Key for certifying a key with this
 | 
			
		||||
// Entity.
 | 
			
		||||
func (e *Entity) CertificationKey(now time.Time) (Key, bool) {
 | 
			
		||||
	return e.CertificationKeyById(now, 0)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CertificationKeyById return the Key for key certification with this
 | 
			
		||||
// Entity and keyID.
 | 
			
		||||
func (e *Entity) CertificationKeyById(now time.Time, id uint64) (Key, bool) {
 | 
			
		||||
	return e.signingKeyByIdUsage(now, id, packet.KeyFlagCertify)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SigningKey return the best candidate Key for signing a message with this
 | 
			
		||||
// Entity.
 | 
			
		||||
func (e *Entity) SigningKey(now time.Time) (Key, bool) {
 | 
			
		||||
	return e.SigningKeyById(now, 0)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SigningKeyById return the Key for signing a message with this
 | 
			
		||||
// Entity and keyID.
 | 
			
		||||
func (e *Entity) SigningKeyById(now time.Time, id uint64) (Key, bool) {
 | 
			
		||||
	return e.signingKeyByIdUsage(now, id, packet.KeyFlagSign)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e *Entity) signingKeyByIdUsage(now time.Time, id uint64, flags int) (Key, bool) {
 | 
			
		||||
	// Fail to find any signing key if the...
 | 
			
		||||
	i := e.PrimaryIdentity()
 | 
			
		||||
	if e.PrimaryKey.KeyExpired(i.SelfSignature, now) || // primary key has expired
 | 
			
		||||
		i.SelfSignature == nil || // user ID has no self-signature
 | 
			
		||||
		i.SelfSignature.SigExpired(now) || // user ID self-signature has expired
 | 
			
		||||
		e.Revoked(now) || // primary key has been revoked
 | 
			
		||||
		i.Revoked(now) { // user ID has been revoked
 | 
			
		||||
		return Key{}, false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Iterate the keys to find the newest, unexpired one
 | 
			
		||||
	candidateSubkey := -1
 | 
			
		||||
	var maxTime time.Time
 | 
			
		||||
	for idx, subkey := range e.Subkeys {
 | 
			
		||||
		if subkey.Sig.FlagsValid &&
 | 
			
		||||
			(flags & packet.KeyFlagCertify == 0 || subkey.Sig.FlagCertify) &&
 | 
			
		||||
			(flags & packet.KeyFlagSign == 0 || subkey.Sig.FlagSign) &&
 | 
			
		||||
			subkey.PublicKey.PubKeyAlgo.CanSign() &&
 | 
			
		||||
			!subkey.PublicKey.KeyExpired(subkey.Sig, now) &&
 | 
			
		||||
			!subkey.Sig.SigExpired(now) &&
 | 
			
		||||
			!subkey.Revoked(now) &&
 | 
			
		||||
			(maxTime.IsZero() || subkey.Sig.CreationTime.After(maxTime)) &&
 | 
			
		||||
			(id == 0 || subkey.PublicKey.KeyId == id) {
 | 
			
		||||
			candidateSubkey = idx
 | 
			
		||||
			maxTime = subkey.Sig.CreationTime
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if candidateSubkey != -1 {
 | 
			
		||||
		subkey := e.Subkeys[candidateSubkey]
 | 
			
		||||
		return Key{e, subkey.PublicKey, subkey.PrivateKey, subkey.Sig, subkey.Revocations}, true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// If we have no candidate subkey then we assume that it's ok to sign
 | 
			
		||||
	// with the primary key.  Or, if the primary key is marked as ok to
 | 
			
		||||
	// sign with, then we can use it.
 | 
			
		||||
	if !i.SelfSignature.FlagsValid || (
 | 
			
		||||
			(flags & packet.KeyFlagCertify == 0 || i.SelfSignature.FlagCertify) &&
 | 
			
		||||
			(flags & packet.KeyFlagSign == 0 || i.SelfSignature.FlagSign)) &&
 | 
			
		||||
		e.PrimaryKey.PubKeyAlgo.CanSign() &&
 | 
			
		||||
		(id == 0 || e.PrimaryKey.KeyId == id) {
 | 
			
		||||
		return Key{e, e.PrimaryKey, e.PrivateKey, i.SelfSignature, e.Revocations}, true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// No keys with a valid Signing Flag or no keys matched the id passed in
 | 
			
		||||
	return Key{}, false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func revoked(revocations []*packet.Signature, now time.Time) bool {
 | 
			
		||||
	for _, revocation := range revocations {
 | 
			
		||||
		if revocation.RevocationReason != nil && *revocation.RevocationReason == packet.KeyCompromised {
 | 
			
		||||
			// If the key is compromised, the key is considered revoked even before the revocation date.
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
		if !revocation.SigExpired(now) {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Revoked returns whether the entity has any direct key revocation signatures.
 | 
			
		||||
// Note that third-party revocation signatures are not supported.
 | 
			
		||||
// Note also that Identity and Subkey revocation should be checked separately.
 | 
			
		||||
func (e *Entity) Revoked(now time.Time) bool {
 | 
			
		||||
	return revoked(e.Revocations, now)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Revoked returns whether the identity has been revoked by a self-signature.
 | 
			
		||||
// Note that third-party revocation signatures are not supported.
 | 
			
		||||
func (i *Identity) Revoked(now time.Time) bool {
 | 
			
		||||
	return revoked(i.Revocations, now)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Revoked returns whether the subkey has been revoked by a self-signature.
 | 
			
		||||
// Note that third-party revocation signatures are not supported.
 | 
			
		||||
func (s *Subkey) Revoked(now time.Time) bool {
 | 
			
		||||
	return revoked(s.Revocations, now)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Revoked returns whether the key or subkey has been revoked by a self-signature.
 | 
			
		||||
// Note that third-party revocation signatures are not supported.
 | 
			
		||||
// Note also that Identity revocation should be checked separately.
 | 
			
		||||
// Normally, it's not necessary to call this function, except on keys returned by
 | 
			
		||||
// KeysById or KeysByIdUsage.
 | 
			
		||||
func (key *Key) Revoked(now time.Time) bool {
 | 
			
		||||
	return revoked(key.Revocations, now)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// An EntityList contains one or more Entities.
 | 
			
		||||
type EntityList []*Entity
 | 
			
		||||
 | 
			
		||||
// KeysById returns the set of keys that have the given key id.
 | 
			
		||||
func (el EntityList) KeysById(id uint64) (keys []Key) {
 | 
			
		||||
	for _, e := range el {
 | 
			
		||||
		if e.PrimaryKey.KeyId == id {
 | 
			
		||||
			ident := e.PrimaryIdentity()
 | 
			
		||||
			selfSig := ident.SelfSignature
 | 
			
		||||
			keys = append(keys, Key{e, e.PrimaryKey, e.PrivateKey, selfSig, e.Revocations})
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for _, subKey := range e.Subkeys {
 | 
			
		||||
			if subKey.PublicKey.KeyId == id {
 | 
			
		||||
				keys = append(keys, Key{e, subKey.PublicKey, subKey.PrivateKey, subKey.Sig, subKey.Revocations})
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// KeysByIdAndUsage returns the set of keys with the given id that also meet
 | 
			
		||||
// the key usage given by requiredUsage.  The requiredUsage is expressed as
 | 
			
		||||
// the bitwise-OR of packet.KeyFlag* values.
 | 
			
		||||
func (el EntityList) KeysByIdUsage(id uint64, requiredUsage byte) (keys []Key) {
 | 
			
		||||
	for _, key := range el.KeysById(id) {
 | 
			
		||||
		if key.SelfSignature != nil && key.SelfSignature.FlagsValid && requiredUsage != 0 {
 | 
			
		||||
			var usage byte
 | 
			
		||||
			if key.SelfSignature.FlagCertify {
 | 
			
		||||
				usage |= packet.KeyFlagCertify
 | 
			
		||||
			}
 | 
			
		||||
			if key.SelfSignature.FlagSign {
 | 
			
		||||
				usage |= packet.KeyFlagSign
 | 
			
		||||
			}
 | 
			
		||||
			if key.SelfSignature.FlagEncryptCommunications {
 | 
			
		||||
				usage |= packet.KeyFlagEncryptCommunications
 | 
			
		||||
			}
 | 
			
		||||
			if key.SelfSignature.FlagEncryptStorage {
 | 
			
		||||
				usage |= packet.KeyFlagEncryptStorage
 | 
			
		||||
			}
 | 
			
		||||
			if usage&requiredUsage != requiredUsage {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		keys = append(keys, key)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DecryptionKeys returns all private keys that are valid for decryption.
 | 
			
		||||
func (el EntityList) DecryptionKeys() (keys []Key) {
 | 
			
		||||
	for _, e := range el {
 | 
			
		||||
		for _, subKey := range e.Subkeys {
 | 
			
		||||
			if subKey.PrivateKey != nil && (!subKey.Sig.FlagsValid || subKey.Sig.FlagEncryptStorage || subKey.Sig.FlagEncryptCommunications) {
 | 
			
		||||
				keys = append(keys, Key{e, subKey.PublicKey, subKey.PrivateKey, subKey.Sig, subKey.Revocations})
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ReadArmoredKeyRing reads one or more public/private keys from an armor keyring file.
 | 
			
		||||
func ReadArmoredKeyRing(r io.Reader) (EntityList, error) {
 | 
			
		||||
	block, err := armor.Decode(r)
 | 
			
		||||
	if err == io.EOF {
 | 
			
		||||
		return nil, errors.InvalidArgumentError("no armored data found")
 | 
			
		||||
	}
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	if block.Type != PublicKeyType && block.Type != PrivateKeyType {
 | 
			
		||||
		return nil, errors.InvalidArgumentError("expected public or private key block, got: " + block.Type)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ReadKeyRing(block.Body)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ReadKeyRing reads one or more public/private keys. Unsupported keys are
 | 
			
		||||
// ignored as long as at least a single valid key is found.
 | 
			
		||||
func ReadKeyRing(r io.Reader) (el EntityList, err error) {
 | 
			
		||||
	packets := packet.NewReader(r)
 | 
			
		||||
	var lastUnsupportedError error
 | 
			
		||||
 | 
			
		||||
	for {
 | 
			
		||||
		var e *Entity
 | 
			
		||||
		e, err = ReadEntity(packets)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			// TODO: warn about skipped unsupported/unreadable keys
 | 
			
		||||
			if _, ok := err.(errors.UnsupportedError); ok {
 | 
			
		||||
				lastUnsupportedError = err
 | 
			
		||||
				err = readToNextPublicKey(packets)
 | 
			
		||||
			} else if _, ok := err.(errors.StructuralError); ok {
 | 
			
		||||
				// Skip unreadable, badly-formatted keys
 | 
			
		||||
				lastUnsupportedError = err
 | 
			
		||||
				err = readToNextPublicKey(packets)
 | 
			
		||||
			}
 | 
			
		||||
			if err == io.EOF {
 | 
			
		||||
				err = nil
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				el = nil
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			el = append(el, e)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(el) == 0 && err == nil {
 | 
			
		||||
		err = lastUnsupportedError
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// readToNextPublicKey reads packets until the start of the entity and leaves
 | 
			
		||||
// the first packet of the new entity in the Reader.
 | 
			
		||||
func readToNextPublicKey(packets *packet.Reader) (err error) {
 | 
			
		||||
	var p packet.Packet
 | 
			
		||||
	for {
 | 
			
		||||
		p, err = packets.Next()
 | 
			
		||||
		if err == io.EOF {
 | 
			
		||||
			return
 | 
			
		||||
		} else if err != nil {
 | 
			
		||||
			if _, ok := err.(errors.UnsupportedError); ok {
 | 
			
		||||
				err = nil
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if pk, ok := p.(*packet.PublicKey); ok && !pk.IsSubkey {
 | 
			
		||||
			packets.Unread(p)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ReadEntity reads an entity (public key, identities, subkeys etc) from the
 | 
			
		||||
// given Reader.
 | 
			
		||||
func ReadEntity(packets *packet.Reader) (*Entity, error) {
 | 
			
		||||
	e := new(Entity)
 | 
			
		||||
	e.Identities = make(map[string]*Identity)
 | 
			
		||||
 | 
			
		||||
	p, err := packets.Next()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var ok bool
 | 
			
		||||
	if e.PrimaryKey, ok = p.(*packet.PublicKey); !ok {
 | 
			
		||||
		if e.PrivateKey, ok = p.(*packet.PrivateKey); !ok {
 | 
			
		||||
			packets.Unread(p)
 | 
			
		||||
			return nil, errors.StructuralError("first packet was not a public/private key")
 | 
			
		||||
		}
 | 
			
		||||
		e.PrimaryKey = &e.PrivateKey.PublicKey
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !e.PrimaryKey.PubKeyAlgo.CanSign() {
 | 
			
		||||
		return nil, errors.StructuralError("primary key cannot be used for signatures")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var revocations []*packet.Signature
 | 
			
		||||
EachPacket:
 | 
			
		||||
	for {
 | 
			
		||||
		p, err := packets.Next()
 | 
			
		||||
		if err == io.EOF {
 | 
			
		||||
			break
 | 
			
		||||
		} else if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		switch pkt := p.(type) {
 | 
			
		||||
		case *packet.UserId:
 | 
			
		||||
			if err := addUserID(e, packets, pkt); err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
		case *packet.Signature:
 | 
			
		||||
			if pkt.SigType == packet.SigTypeKeyRevocation {
 | 
			
		||||
				revocations = append(revocations, pkt)
 | 
			
		||||
			} else if pkt.SigType == packet.SigTypeDirectSignature {
 | 
			
		||||
				// TODO: RFC4880 5.2.1 permits signatures
 | 
			
		||||
				// directly on keys (eg. to bind additional
 | 
			
		||||
				// revocation keys).
 | 
			
		||||
			}
 | 
			
		||||
			// Else, ignoring the signature as it does not follow anything
 | 
			
		||||
			// we would know to attach it to.
 | 
			
		||||
		case *packet.PrivateKey:
 | 
			
		||||
			if pkt.IsSubkey == false {
 | 
			
		||||
				packets.Unread(p)
 | 
			
		||||
				break EachPacket
 | 
			
		||||
			}
 | 
			
		||||
			err = addSubkey(e, packets, &pkt.PublicKey, pkt)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
		case *packet.PublicKey:
 | 
			
		||||
			if pkt.IsSubkey == false {
 | 
			
		||||
				packets.Unread(p)
 | 
			
		||||
				break EachPacket
 | 
			
		||||
			}
 | 
			
		||||
			err = addSubkey(e, packets, pkt, nil)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
		default:
 | 
			
		||||
			// we ignore unknown packets
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(e.Identities) == 0 {
 | 
			
		||||
		return nil, errors.StructuralError("entity without any identities")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, revocation := range revocations {
 | 
			
		||||
		err = e.PrimaryKey.VerifyRevocationSignature(revocation)
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			e.Revocations = append(e.Revocations, revocation)
 | 
			
		||||
		} else {
 | 
			
		||||
			// TODO: RFC 4880 5.2.3.15 defines revocation keys.
 | 
			
		||||
			return nil, errors.StructuralError("revocation signature signed by alternate key")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return e, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func addUserID(e *Entity, packets *packet.Reader, pkt *packet.UserId) error {
 | 
			
		||||
	// Make a new Identity object, that we might wind up throwing away.
 | 
			
		||||
	// We'll only add it if we get a valid self-signature over this
 | 
			
		||||
	// userID.
 | 
			
		||||
	identity := new(Identity)
 | 
			
		||||
	identity.Name = pkt.Id
 | 
			
		||||
	identity.UserId = pkt
 | 
			
		||||
 | 
			
		||||
	for {
 | 
			
		||||
		p, err := packets.Next()
 | 
			
		||||
		if err == io.EOF {
 | 
			
		||||
			break
 | 
			
		||||
		} else if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		sig, ok := p.(*packet.Signature)
 | 
			
		||||
		if !ok {
 | 
			
		||||
			packets.Unread(p)
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if sig.SigType != packet.SigTypeGenericCert &&
 | 
			
		||||
			sig.SigType != packet.SigTypePersonaCert &&
 | 
			
		||||
			sig.SigType != packet.SigTypeCasualCert &&
 | 
			
		||||
			sig.SigType != packet.SigTypePositiveCert &&
 | 
			
		||||
			sig.SigType != packet.SigTypeCertificationRevocation {
 | 
			
		||||
			return errors.StructuralError("user ID signature with wrong type")
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if sig.CheckKeyIdOrFingerprint(e.PrimaryKey) {
 | 
			
		||||
			if err = e.PrimaryKey.VerifyUserIdSignature(pkt.Id, e.PrimaryKey, sig); err != nil {
 | 
			
		||||
				return errors.StructuralError("user ID self-signature invalid: " + err.Error())
 | 
			
		||||
			}
 | 
			
		||||
			if sig.SigType == packet.SigTypeCertificationRevocation {
 | 
			
		||||
				identity.Revocations = append(identity.Revocations, sig)
 | 
			
		||||
			} else if identity.SelfSignature == nil || sig.CreationTime.After(identity.SelfSignature.CreationTime) {
 | 
			
		||||
				identity.SelfSignature = sig
 | 
			
		||||
			}
 | 
			
		||||
			identity.Signatures = append(identity.Signatures, sig)
 | 
			
		||||
			e.Identities[pkt.Id] = identity
 | 
			
		||||
		} else {
 | 
			
		||||
			identity.Signatures = append(identity.Signatures, sig)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func addSubkey(e *Entity, packets *packet.Reader, pub *packet.PublicKey, priv *packet.PrivateKey) error {
 | 
			
		||||
	var subKey Subkey
 | 
			
		||||
	subKey.PublicKey = pub
 | 
			
		||||
	subKey.PrivateKey = priv
 | 
			
		||||
 | 
			
		||||
	for {
 | 
			
		||||
		p, err := packets.Next()
 | 
			
		||||
		if err == io.EOF {
 | 
			
		||||
			break
 | 
			
		||||
		} else if err != nil {
 | 
			
		||||
			return errors.StructuralError("subkey signature invalid: " + err.Error())
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		sig, ok := p.(*packet.Signature)
 | 
			
		||||
		if !ok {
 | 
			
		||||
			packets.Unread(p)
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if sig.SigType != packet.SigTypeSubkeyBinding && sig.SigType != packet.SigTypeSubkeyRevocation {
 | 
			
		||||
			return errors.StructuralError("subkey signature with wrong type")
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if err := e.PrimaryKey.VerifyKeySignature(subKey.PublicKey, sig); err != nil {
 | 
			
		||||
			return errors.StructuralError("subkey signature invalid: " + err.Error())
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		switch sig.SigType {
 | 
			
		||||
		case packet.SigTypeSubkeyRevocation:
 | 
			
		||||
			subKey.Revocations = append(subKey.Revocations, sig)
 | 
			
		||||
		case packet.SigTypeSubkeyBinding:
 | 
			
		||||
			if subKey.Sig == nil || sig.CreationTime.After(subKey.Sig.CreationTime) {
 | 
			
		||||
				subKey.Sig = sig
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if subKey.Sig == nil {
 | 
			
		||||
		return errors.StructuralError("subkey packet not followed by signature")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	e.Subkeys = append(e.Subkeys, subKey)
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SerializePrivate serializes an Entity, including private key material, but
 | 
			
		||||
// excluding signatures from other entities, to the given Writer.
 | 
			
		||||
// Identities and subkeys are re-signed in case they changed since NewEntry.
 | 
			
		||||
// If config is nil, sensible defaults will be used.
 | 
			
		||||
func (e *Entity) SerializePrivate(w io.Writer, config *packet.Config) (err error) {
 | 
			
		||||
	if e.PrivateKey.Dummy() {
 | 
			
		||||
		return errors.ErrDummyPrivateKey("dummy private key cannot re-sign identities")
 | 
			
		||||
	}
 | 
			
		||||
	return e.serializePrivate(w, config, true)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SerializePrivateWithoutSigning serializes an Entity, including private key
 | 
			
		||||
// material, but excluding signatures from other entities, to the given Writer.
 | 
			
		||||
// Self-signatures of identities and subkeys are not re-signed. This is useful
 | 
			
		||||
// when serializing GNU dummy keys, among other things.
 | 
			
		||||
// If config is nil, sensible defaults will be used.
 | 
			
		||||
func (e *Entity) SerializePrivateWithoutSigning(w io.Writer, config *packet.Config) (err error) {
 | 
			
		||||
	return e.serializePrivate(w, config, false)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e *Entity) serializePrivate(w io.Writer, config *packet.Config, reSign bool) (err error) {
 | 
			
		||||
	if e.PrivateKey == nil {
 | 
			
		||||
		return goerrors.New("openpgp: private key is missing")
 | 
			
		||||
	}
 | 
			
		||||
	err = e.PrivateKey.Serialize(w)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	for _, revocation := range e.Revocations {
 | 
			
		||||
		err := revocation.Serialize(w)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for _, ident := range e.Identities {
 | 
			
		||||
		err = ident.UserId.Serialize(w)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		if reSign {
 | 
			
		||||
			if ident.SelfSignature == nil {
 | 
			
		||||
				return goerrors.New("openpgp: can't re-sign identity without valid self-signature")
 | 
			
		||||
			}
 | 
			
		||||
			err = ident.SelfSignature.SignUserId(ident.UserId.Id, e.PrimaryKey, e.PrivateKey, config)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		for _, sig := range ident.Signatures {
 | 
			
		||||
			err = sig.Serialize(w)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for _, subkey := range e.Subkeys {
 | 
			
		||||
		err = subkey.PrivateKey.Serialize(w)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		if reSign {
 | 
			
		||||
			err = subkey.Sig.SignKey(subkey.PublicKey, e.PrivateKey, config)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
			if subkey.Sig.EmbeddedSignature != nil {
 | 
			
		||||
				err = subkey.Sig.EmbeddedSignature.CrossSignKey(subkey.PublicKey, e.PrimaryKey,
 | 
			
		||||
					subkey.PrivateKey, config)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		for _, revocation := range subkey.Revocations {
 | 
			
		||||
			err := revocation.Serialize(w)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		err = subkey.Sig.Serialize(w)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Serialize writes the public part of the given Entity to w, including
 | 
			
		||||
// signatures from other entities. No private key material will be output.
 | 
			
		||||
func (e *Entity) Serialize(w io.Writer) error {
 | 
			
		||||
	err := e.PrimaryKey.Serialize(w)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	for _, revocation := range e.Revocations {
 | 
			
		||||
		err := revocation.Serialize(w)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for _, ident := range e.Identities {
 | 
			
		||||
		err = ident.UserId.Serialize(w)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		for _, sig := range ident.Signatures {
 | 
			
		||||
			err = sig.Serialize(w)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for _, subkey := range e.Subkeys {
 | 
			
		||||
		err = subkey.PublicKey.Serialize(w)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		for _, revocation := range subkey.Revocations {
 | 
			
		||||
			err := revocation.Serialize(w)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		err = subkey.Sig.Serialize(w)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SignIdentity adds a signature to e, from signer, attesting that identity is
 | 
			
		||||
// associated with e. The provided identity must already be an element of
 | 
			
		||||
// e.Identities and the private key of signer must have been decrypted if
 | 
			
		||||
// necessary.
 | 
			
		||||
// If config is nil, sensible defaults will be used.
 | 
			
		||||
func (e *Entity) SignIdentity(identity string, signer *Entity, config *packet.Config) error {
 | 
			
		||||
	certificationKey, ok := signer.CertificationKey(config.Now())
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return errors.InvalidArgumentError("no valid certification key found")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if certificationKey.PrivateKey.Encrypted {
 | 
			
		||||
		return errors.InvalidArgumentError("signing Entity's private key must be decrypted")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ident, ok := e.Identities[identity]
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return errors.InvalidArgumentError("given identity string not found in Entity")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sig := &packet.Signature{
 | 
			
		||||
		Version:      certificationKey.PrivateKey.Version,
 | 
			
		||||
		SigType:      packet.SigTypeGenericCert,
 | 
			
		||||
		PubKeyAlgo:   certificationKey.PrivateKey.PubKeyAlgo,
 | 
			
		||||
		Hash:         config.Hash(),
 | 
			
		||||
		CreationTime: config.Now(),
 | 
			
		||||
		IssuerKeyId:  &certificationKey.PrivateKey.KeyId,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if config.SigLifetime() != 0 {
 | 
			
		||||
		sig.SigLifetimeSecs = &config.SigLifetimeSecs
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	signingUserID := config.SigningUserId()
 | 
			
		||||
	if signingUserID != "" {
 | 
			
		||||
		if _, ok := signer.Identities[signingUserID]; !ok {
 | 
			
		||||
			return errors.InvalidArgumentError("signer identity string not found in signer Entity")
 | 
			
		||||
		}
 | 
			
		||||
		sig.SignerUserId = &signingUserID
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := sig.SignUserId(identity, e.PrimaryKey, certificationKey.PrivateKey, config); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	ident.Signatures = append(ident.Signatures, sig)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RevokeKey generates a key revocation signature (packet.SigTypeKeyRevocation) with the
 | 
			
		||||
// specified reason code and text (RFC4880 section-5.2.3.23).
 | 
			
		||||
// If config is nil, sensible defaults will be used.
 | 
			
		||||
func (e *Entity) RevokeKey(reason packet.ReasonForRevocation, reasonText string, config *packet.Config) error {
 | 
			
		||||
	revSig := &packet.Signature{
 | 
			
		||||
		Version:              e.PrimaryKey.Version,
 | 
			
		||||
		CreationTime:         config.Now(),
 | 
			
		||||
		SigType:              packet.SigTypeKeyRevocation,
 | 
			
		||||
		PubKeyAlgo:           e.PrimaryKey.PubKeyAlgo,
 | 
			
		||||
		Hash:                 config.Hash(),
 | 
			
		||||
		RevocationReason:     &reason,
 | 
			
		||||
		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")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	revSig := &packet.Signature{
 | 
			
		||||
		Version:              e.PrimaryKey.Version,
 | 
			
		||||
		CreationTime:         config.Now(),
 | 
			
		||||
		SigType:              packet.SigTypeSubkeyRevocation,
 | 
			
		||||
		PubKeyAlgo:           e.PrimaryKey.PubKeyAlgo,
 | 
			
		||||
		Hash:                 config.Hash(),
 | 
			
		||||
		RevocationReason:     &reason,
 | 
			
		||||
		RevocationReasonText: reasonText,
 | 
			
		||||
		IssuerKeyId:          &e.PrimaryKey.KeyId,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := revSig.RevokeSubkey(sk.PublicKey, e.PrivateKey, config); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sk.Revocations = append(sk.Revocations, revSig)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										520
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/keys_test_data.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										520
									
								
								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 across 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 performs an integer increment by 1 of the integer represented by the
 | 
			
		||||
// slice, modifying it accordingly.
 | 
			
		||||
func (wo *aeadCrypter) incrementIndex() error {
 | 
			
		||||
	index := wo.chunkIndex
 | 
			
		||||
	if len(index) == 0 {
 | 
			
		||||
		return errors.AEADError("Index has length 0")
 | 
			
		||||
	}
 | 
			
		||||
	for i := len(index) - 1; i >= 0; i-- {
 | 
			
		||||
		if index[i] < 255 {
 | 
			
		||||
			index[i]++
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
		index[i] = 0
 | 
			
		||||
	}
 | 
			
		||||
	return errors.AEADError("cannot further increment index")
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										125
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/compressed.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/compressed.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,125 @@
 | 
			
		||||
// Copyright 2011 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package packet
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"compress/bzip2"
 | 
			
		||||
	"compress/flate"
 | 
			
		||||
	"compress/zlib"
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/openpgp/errors"
 | 
			
		||||
	"io"
 | 
			
		||||
	"strconv"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Compressed represents a compressed OpenPGP packet. The decompressed contents
 | 
			
		||||
// will contain more OpenPGP packets. See RFC 4880, section 5.6.
 | 
			
		||||
type Compressed struct {
 | 
			
		||||
	Body io.Reader
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	NoCompression      = flate.NoCompression
 | 
			
		||||
	BestSpeed          = flate.BestSpeed
 | 
			
		||||
	BestCompression    = flate.BestCompression
 | 
			
		||||
	DefaultCompression = flate.DefaultCompression
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// CompressionConfig contains compressor configuration settings.
 | 
			
		||||
type CompressionConfig struct {
 | 
			
		||||
	// Level is the compression level to use. It must be set to
 | 
			
		||||
	// between -1 and 9, with -1 causing the compressor to use the
 | 
			
		||||
	// default compression level, 0 causing the compressor to use
 | 
			
		||||
	// no compression and 1 to 9 representing increasing (better,
 | 
			
		||||
	// slower) compression levels. If Level is less than -1 or
 | 
			
		||||
	// more then 9, a non-nil error will be returned during
 | 
			
		||||
	// encryption. See the constants above for convenient common
 | 
			
		||||
	// settings for Level.
 | 
			
		||||
	Level int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Compressed) parse(r io.Reader) error {
 | 
			
		||||
	var buf [1]byte
 | 
			
		||||
	_, err := readFull(r, buf[:])
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch buf[0] {
 | 
			
		||||
	case 0:
 | 
			
		||||
		c.Body = r
 | 
			
		||||
	case 1:
 | 
			
		||||
		c.Body = flate.NewReader(r)
 | 
			
		||||
	case 2:
 | 
			
		||||
		c.Body, err = zlib.NewReader(r)
 | 
			
		||||
	case 3:
 | 
			
		||||
		c.Body = bzip2.NewReader(r)
 | 
			
		||||
	default:
 | 
			
		||||
		err = errors.UnsupportedError("unknown compression algorithm: " + strconv.Itoa(int(buf[0])))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// compressedWriterCloser represents the serialized compression stream
 | 
			
		||||
// header and the compressor. Its Close() method ensures that both the
 | 
			
		||||
// compressor and serialized stream header are closed. Its Write()
 | 
			
		||||
// method writes to the compressor.
 | 
			
		||||
type compressedWriteCloser struct {
 | 
			
		||||
	sh io.Closer      // Stream Header
 | 
			
		||||
	c  io.WriteCloser // Compressor
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (cwc compressedWriteCloser) Write(p []byte) (int, error) {
 | 
			
		||||
	return cwc.c.Write(p)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (cwc compressedWriteCloser) Close() (err error) {
 | 
			
		||||
	err = cwc.c.Close()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return cwc.sh.Close()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SerializeCompressed serializes a compressed data packet to w and
 | 
			
		||||
// returns a WriteCloser to which the literal data packets themselves
 | 
			
		||||
// can be written and which MUST be closed on completion. If cc is
 | 
			
		||||
// nil, sensible defaults will be used to configure the compression
 | 
			
		||||
// algorithm.
 | 
			
		||||
func SerializeCompressed(w io.WriteCloser, algo CompressionAlgo, cc *CompressionConfig) (literaldata io.WriteCloser, err error) {
 | 
			
		||||
	compressed, err := serializeStreamHeader(w, packetTypeCompressed)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, err = compressed.Write([]byte{uint8(algo)})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	level := DefaultCompression
 | 
			
		||||
	if cc != nil {
 | 
			
		||||
		level = cc.Level
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var compressor io.WriteCloser
 | 
			
		||||
	switch algo {
 | 
			
		||||
	case CompressionZIP:
 | 
			
		||||
		compressor, err = flate.NewWriter(compressed, level)
 | 
			
		||||
	case CompressionZLIB:
 | 
			
		||||
		compressor, err = zlib.NewWriterLevel(compressed, level)
 | 
			
		||||
	default:
 | 
			
		||||
		s := strconv.Itoa(int(algo))
 | 
			
		||||
		err = errors.UnsupportedError("Unsupported compression algorithm: " + s)
 | 
			
		||||
	}
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	literaldata = compressedWriteCloser{compressed, compressor}
 | 
			
		||||
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										188
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/config.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										188
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/config.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,188 @@
 | 
			
		||||
// Copyright 2012 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package packet
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto"
 | 
			
		||||
	"crypto/rand"
 | 
			
		||||
	"io"
 | 
			
		||||
	"math/big"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Config collects a number of parameters along with sensible defaults.
 | 
			
		||||
// A nil *Config is valid and results in all default values.
 | 
			
		||||
type Config struct {
 | 
			
		||||
	// Rand provides the source of entropy.
 | 
			
		||||
	// If nil, the crypto/rand Reader is used.
 | 
			
		||||
	Rand io.Reader
 | 
			
		||||
	// DefaultHash is the default hash function to be used.
 | 
			
		||||
	// If zero, SHA-256 is used.
 | 
			
		||||
	DefaultHash crypto.Hash
 | 
			
		||||
	// DefaultCipher is the cipher to be used.
 | 
			
		||||
	// If zero, AES-128 is used.
 | 
			
		||||
	DefaultCipher CipherFunction
 | 
			
		||||
	// Time returns the current time as the number of seconds since the
 | 
			
		||||
	// epoch. If Time is nil, time.Now is used.
 | 
			
		||||
	Time func() time.Time
 | 
			
		||||
	// DefaultCompressionAlgo is the compression algorithm to be
 | 
			
		||||
	// applied to the plaintext before encryption. If zero, no
 | 
			
		||||
	// compression is done.
 | 
			
		||||
	DefaultCompressionAlgo CompressionAlgo
 | 
			
		||||
	// CompressionConfig configures the compression settings.
 | 
			
		||||
	CompressionConfig *CompressionConfig
 | 
			
		||||
	// S2KCount is only used for symmetric encryption. It
 | 
			
		||||
	// determines the strength of the passphrase stretching when
 | 
			
		||||
	// the said passphrase is hashed to produce a key. S2KCount
 | 
			
		||||
	// should be between 1024 and 65011712, inclusive. If Config
 | 
			
		||||
	// is nil or S2KCount is 0, the value 65536 used. Not all
 | 
			
		||||
	// values in the above range can be represented. S2KCount will
 | 
			
		||||
	// be rounded up to the next representable value if it cannot
 | 
			
		||||
	// be encoded exactly. When set, it is strongly encrouraged to
 | 
			
		||||
	// use a value that is at least 65536. See RFC 4880 Section
 | 
			
		||||
	// 3.7.1.3.
 | 
			
		||||
	S2KCount int
 | 
			
		||||
	// RSABits is the number of bits in new RSA keys made with NewEntity.
 | 
			
		||||
	// If zero, then 2048 bit keys are created.
 | 
			
		||||
	RSABits int
 | 
			
		||||
	// The public key algorithm to use - will always create a signing primary
 | 
			
		||||
	// key and encryption subkey.
 | 
			
		||||
	Algorithm PublicKeyAlgorithm
 | 
			
		||||
	// Some known primes that are optionally prepopulated by the caller
 | 
			
		||||
	RSAPrimes []*big.Int
 | 
			
		||||
	// Curve configures the desired packet.Curve if the Algorithm is PubKeyAlgoECDSA,
 | 
			
		||||
	// PubKeyAlgoEdDSA, or PubKeyAlgoECDH. If empty Curve25519 is used.
 | 
			
		||||
	Curve Curve
 | 
			
		||||
	// AEADConfig configures the use of the new AEAD Encrypted Data Packet,
 | 
			
		||||
	// defined in the draft of the next version of the OpenPGP specification.
 | 
			
		||||
	// If a non-nil AEADConfig is passed, usage of this packet is enabled. By
 | 
			
		||||
	// default, it is disabled. See the documentation of AEADConfig for more
 | 
			
		||||
	// configuration options related to AEAD.
 | 
			
		||||
	// **Note: using this option may break compatibility with other OpenPGP
 | 
			
		||||
	// implementations, as well as future versions of this library.**
 | 
			
		||||
	AEADConfig *AEADConfig
 | 
			
		||||
	// V5Keys configures version 5 key generation. If false, this package still
 | 
			
		||||
	// supports version 5 keys, but produces version 4 keys.
 | 
			
		||||
	V5Keys bool
 | 
			
		||||
	// "The validity period of the key.  This is the number of seconds after
 | 
			
		||||
	// the key creation time that the key expires.  If this is not present
 | 
			
		||||
	// or has a value of zero, the key never expires.  This is found only on
 | 
			
		||||
	// a self-signature.""
 | 
			
		||||
	// https://tools.ietf.org/html/rfc4880#section-5.2.3.6
 | 
			
		||||
	KeyLifetimeSecs uint32
 | 
			
		||||
	// "The validity period of the signature.  This is the number of seconds
 | 
			
		||||
	// after the signature creation time that the signature expires.  If
 | 
			
		||||
	// this is not present or has a value of zero, it never expires."
 | 
			
		||||
	// https://tools.ietf.org/html/rfc4880#section-5.2.3.10
 | 
			
		||||
	SigLifetimeSecs uint32
 | 
			
		||||
	// SigningKeyId is used to specify the signing key to use (by Key ID).
 | 
			
		||||
	// By default, the signing key is selected automatically, preferring
 | 
			
		||||
	// signing subkeys if available.
 | 
			
		||||
	SigningKeyId uint64
 | 
			
		||||
	// SigningIdentity is used to specify a user ID (packet Signer's User ID, type 28)
 | 
			
		||||
	// when producing a generic certification signature onto an existing user ID.
 | 
			
		||||
	// The identity must be present in the signer Entity.
 | 
			
		||||
	SigningIdentity string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Config) Random() io.Reader {
 | 
			
		||||
	if c == nil || c.Rand == nil {
 | 
			
		||||
		return rand.Reader
 | 
			
		||||
	}
 | 
			
		||||
	return c.Rand
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Config) Hash() crypto.Hash {
 | 
			
		||||
	if c == nil || uint(c.DefaultHash) == 0 {
 | 
			
		||||
		return crypto.SHA256
 | 
			
		||||
	}
 | 
			
		||||
	return c.DefaultHash
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Config) Cipher() CipherFunction {
 | 
			
		||||
	if c == nil || uint8(c.DefaultCipher) == 0 {
 | 
			
		||||
		return CipherAES128
 | 
			
		||||
	}
 | 
			
		||||
	return c.DefaultCipher
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Config) Now() time.Time {
 | 
			
		||||
	if c == nil || c.Time == nil {
 | 
			
		||||
		return time.Now()
 | 
			
		||||
	}
 | 
			
		||||
	return c.Time()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// KeyLifetime returns the validity period of the key.
 | 
			
		||||
func (c *Config) KeyLifetime() uint32 {
 | 
			
		||||
	if c == nil {
 | 
			
		||||
		return 0
 | 
			
		||||
	}
 | 
			
		||||
	return c.KeyLifetimeSecs
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SigLifetime returns the validity period of the signature.
 | 
			
		||||
func (c *Config) SigLifetime() uint32 {
 | 
			
		||||
	if c == nil {
 | 
			
		||||
		return 0
 | 
			
		||||
	}
 | 
			
		||||
	return c.SigLifetimeSecs
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Config) Compression() CompressionAlgo {
 | 
			
		||||
	if c == nil {
 | 
			
		||||
		return CompressionNone
 | 
			
		||||
	}
 | 
			
		||||
	return c.DefaultCompressionAlgo
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Config) PasswordHashIterations() int {
 | 
			
		||||
	if c == nil || c.S2KCount == 0 {
 | 
			
		||||
		return 0
 | 
			
		||||
	}
 | 
			
		||||
	return c.S2KCount
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Config) RSAModulusBits() int {
 | 
			
		||||
	if c == nil || c.RSABits == 0 {
 | 
			
		||||
		return 2048
 | 
			
		||||
	}
 | 
			
		||||
	return c.RSABits
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Config) PublicKeyAlgorithm() PublicKeyAlgorithm {
 | 
			
		||||
	if c == nil || c.Algorithm == 0 {
 | 
			
		||||
		return PubKeyAlgoRSA
 | 
			
		||||
	}
 | 
			
		||||
	return c.Algorithm
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Config) CurveName() Curve {
 | 
			
		||||
	if c == nil || c.Curve == "" {
 | 
			
		||||
		return Curve25519
 | 
			
		||||
	}
 | 
			
		||||
	return c.Curve
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Config) AEAD() *AEADConfig {
 | 
			
		||||
	if c == nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	return c.AEADConfig
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Config) SigningKey() uint64 {
 | 
			
		||||
	if c == nil {
 | 
			
		||||
		return 0
 | 
			
		||||
	}
 | 
			
		||||
	return c.SigningKeyId
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Config) SigningUserId() string {
 | 
			
		||||
	if c == nil {
 | 
			
		||||
		return ""
 | 
			
		||||
	}
 | 
			
		||||
	return c.SigningIdentity
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										282
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/encrypted_key.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										282
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/encrypted_key.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,282 @@
 | 
			
		||||
// Copyright 2011 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package packet
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto"
 | 
			
		||||
	"crypto/rsa"
 | 
			
		||||
	"encoding/binary"
 | 
			
		||||
	"io"
 | 
			
		||||
	"math/big"
 | 
			
		||||
	"strconv"
 | 
			
		||||
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/openpgp/ecdh"
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/openpgp/elgamal"
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/openpgp/errors"
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/openpgp/internal/encoding"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const encryptedKeyVersion = 3
 | 
			
		||||
 | 
			
		||||
// EncryptedKey represents a public-key encrypted session key. See RFC 4880,
 | 
			
		||||
// section 5.1.
 | 
			
		||||
type EncryptedKey struct {
 | 
			
		||||
	KeyId      uint64
 | 
			
		||||
	Algo       PublicKeyAlgorithm
 | 
			
		||||
	CipherFunc CipherFunction // only valid after a successful Decrypt
 | 
			
		||||
	Key        []byte         // only valid after a successful Decrypt
 | 
			
		||||
 | 
			
		||||
	encryptedMPI1, encryptedMPI2 encoding.Field
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e *EncryptedKey) parse(r io.Reader) (err error) {
 | 
			
		||||
	var buf [10]byte
 | 
			
		||||
	_, err = readFull(r, buf[:])
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if buf[0] != encryptedKeyVersion {
 | 
			
		||||
		return errors.UnsupportedError("unknown EncryptedKey version " + strconv.Itoa(int(buf[0])))
 | 
			
		||||
	}
 | 
			
		||||
	e.KeyId = binary.BigEndian.Uint64(buf[1:9])
 | 
			
		||||
	e.Algo = PublicKeyAlgorithm(buf[9])
 | 
			
		||||
	switch e.Algo {
 | 
			
		||||
	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
 | 
			
		||||
		e.encryptedMPI1 = new(encoding.MPI)
 | 
			
		||||
		if _, err = e.encryptedMPI1.ReadFrom(r); err != nil {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	case PubKeyAlgoElGamal:
 | 
			
		||||
		e.encryptedMPI1 = new(encoding.MPI)
 | 
			
		||||
		if _, err = e.encryptedMPI1.ReadFrom(r); err != nil {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		e.encryptedMPI2 = new(encoding.MPI)
 | 
			
		||||
		if _, err = e.encryptedMPI2.ReadFrom(r); err != nil {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	case PubKeyAlgoECDH:
 | 
			
		||||
		e.encryptedMPI1 = new(encoding.MPI)
 | 
			
		||||
		if _, err = e.encryptedMPI1.ReadFrom(r); err != nil {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		e.encryptedMPI2 = new(encoding.OID)
 | 
			
		||||
		if _, err = e.encryptedMPI2.ReadFrom(r); err != nil {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	_, err = consumeAll(r)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func checksumKeyMaterial(key []byte) uint16 {
 | 
			
		||||
	var checksum uint16
 | 
			
		||||
	for _, v := range key {
 | 
			
		||||
		checksum += uint16(v)
 | 
			
		||||
	}
 | 
			
		||||
	return checksum
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Decrypt decrypts an encrypted session key with the given private key. The
 | 
			
		||||
// private key must have been decrypted first.
 | 
			
		||||
// If config is nil, sensible defaults will be used.
 | 
			
		||||
func (e *EncryptedKey) Decrypt(priv *PrivateKey, config *Config) error {
 | 
			
		||||
	if e.KeyId != 0 && e.KeyId != priv.KeyId {
 | 
			
		||||
		return errors.InvalidArgumentError("cannot decrypt encrypted session key for key id " + strconv.FormatUint(e.KeyId, 16) + " with private key id " + strconv.FormatUint(priv.KeyId, 16))
 | 
			
		||||
	}
 | 
			
		||||
	if e.Algo != priv.PubKeyAlgo {
 | 
			
		||||
		return errors.InvalidArgumentError("cannot decrypt encrypted session key of type " + strconv.Itoa(int(e.Algo)) + " with private key of type " + strconv.Itoa(int(priv.PubKeyAlgo)))
 | 
			
		||||
	}
 | 
			
		||||
	if priv.Dummy() {
 | 
			
		||||
		return errors.ErrDummyPrivateKey("dummy key found")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var err error
 | 
			
		||||
	var b []byte
 | 
			
		||||
 | 
			
		||||
	// TODO(agl): use session key decryption routines here to avoid
 | 
			
		||||
	// padding oracle attacks.
 | 
			
		||||
	switch priv.PubKeyAlgo {
 | 
			
		||||
	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
 | 
			
		||||
		// Supports both *rsa.PrivateKey and crypto.Decrypter
 | 
			
		||||
		k := priv.PrivateKey.(crypto.Decrypter)
 | 
			
		||||
		b, err = k.Decrypt(config.Random(), padToKeySize(k.Public().(*rsa.PublicKey), e.encryptedMPI1.Bytes()), nil)
 | 
			
		||||
	case PubKeyAlgoElGamal:
 | 
			
		||||
		c1 := new(big.Int).SetBytes(e.encryptedMPI1.Bytes())
 | 
			
		||||
		c2 := new(big.Int).SetBytes(e.encryptedMPI2.Bytes())
 | 
			
		||||
		b, err = elgamal.Decrypt(priv.PrivateKey.(*elgamal.PrivateKey), c1, c2)
 | 
			
		||||
	case PubKeyAlgoECDH:
 | 
			
		||||
		vsG := e.encryptedMPI1.Bytes()
 | 
			
		||||
		m := e.encryptedMPI2.Bytes()
 | 
			
		||||
		oid := priv.PublicKey.oid.EncodedBytes()
 | 
			
		||||
		b, err = ecdh.Decrypt(priv.PrivateKey.(*ecdh.PrivateKey), vsG, m, oid, priv.PublicKey.Fingerprint[:])
 | 
			
		||||
	default:
 | 
			
		||||
		err = errors.InvalidArgumentError("cannot decrypt encrypted session key with private key of type " + strconv.Itoa(int(priv.PubKeyAlgo)))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	e.CipherFunc = CipherFunction(b[0])
 | 
			
		||||
	e.Key = b[1 : len(b)-2]
 | 
			
		||||
	expectedChecksum := uint16(b[len(b)-2])<<8 | uint16(b[len(b)-1])
 | 
			
		||||
	checksum := checksumKeyMaterial(e.Key)
 | 
			
		||||
	if checksum != expectedChecksum {
 | 
			
		||||
		return errors.StructuralError("EncryptedKey checksum incorrect")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Serialize writes the encrypted key packet, e, to w.
 | 
			
		||||
func (e *EncryptedKey) Serialize(w io.Writer) error {
 | 
			
		||||
	var mpiLen int
 | 
			
		||||
	switch e.Algo {
 | 
			
		||||
	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
 | 
			
		||||
		mpiLen = int(e.encryptedMPI1.EncodedLength())
 | 
			
		||||
	case PubKeyAlgoElGamal:
 | 
			
		||||
		mpiLen = int(e.encryptedMPI1.EncodedLength()) + int(e.encryptedMPI2.EncodedLength())
 | 
			
		||||
	case PubKeyAlgoECDH:
 | 
			
		||||
		mpiLen = int(e.encryptedMPI1.EncodedLength()) + int(e.encryptedMPI2.EncodedLength())
 | 
			
		||||
	default:
 | 
			
		||||
		return errors.InvalidArgumentError("don't know how to serialize encrypted key type " + strconv.Itoa(int(e.Algo)))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err := serializeHeader(w, packetTypeEncryptedKey, 1 /* version */ +8 /* key id */ +1 /* algo */ +mpiLen)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	w.Write([]byte{encryptedKeyVersion})
 | 
			
		||||
	binary.Write(w, binary.BigEndian, e.KeyId)
 | 
			
		||||
	w.Write([]byte{byte(e.Algo)})
 | 
			
		||||
 | 
			
		||||
	switch e.Algo {
 | 
			
		||||
	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
 | 
			
		||||
		_, err := w.Write(e.encryptedMPI1.EncodedBytes())
 | 
			
		||||
		return err
 | 
			
		||||
	case PubKeyAlgoElGamal:
 | 
			
		||||
		if _, err := w.Write(e.encryptedMPI1.EncodedBytes()); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		_, err := w.Write(e.encryptedMPI2.EncodedBytes())
 | 
			
		||||
		return err
 | 
			
		||||
	case PubKeyAlgoECDH:
 | 
			
		||||
		if _, err := w.Write(e.encryptedMPI1.EncodedBytes()); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		_, err := w.Write(e.encryptedMPI2.EncodedBytes())
 | 
			
		||||
		return err
 | 
			
		||||
	default:
 | 
			
		||||
		panic("internal error")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SerializeEncryptedKey serializes an encrypted key packet to w that contains
 | 
			
		||||
// key, encrypted to pub.
 | 
			
		||||
// If config is nil, sensible defaults will be used.
 | 
			
		||||
func SerializeEncryptedKey(w io.Writer, pub *PublicKey, cipherFunc CipherFunction, key []byte, config *Config) error {
 | 
			
		||||
	var buf [10]byte
 | 
			
		||||
	buf[0] = encryptedKeyVersion
 | 
			
		||||
	binary.BigEndian.PutUint64(buf[1:9], pub.KeyId)
 | 
			
		||||
	buf[9] = byte(pub.PubKeyAlgo)
 | 
			
		||||
 | 
			
		||||
	keyBlock := make([]byte, 1 /* cipher type */ +len(key)+2 /* checksum */)
 | 
			
		||||
	keyBlock[0] = byte(cipherFunc)
 | 
			
		||||
	copy(keyBlock[1:], key)
 | 
			
		||||
	checksum := checksumKeyMaterial(key)
 | 
			
		||||
	keyBlock[1+len(key)] = byte(checksum >> 8)
 | 
			
		||||
	keyBlock[1+len(key)+1] = byte(checksum)
 | 
			
		||||
 | 
			
		||||
	switch pub.PubKeyAlgo {
 | 
			
		||||
	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
 | 
			
		||||
		return serializeEncryptedKeyRSA(w, config.Random(), buf, pub.PublicKey.(*rsa.PublicKey), keyBlock)
 | 
			
		||||
	case PubKeyAlgoElGamal:
 | 
			
		||||
		return serializeEncryptedKeyElGamal(w, config.Random(), buf, pub.PublicKey.(*elgamal.PublicKey), keyBlock)
 | 
			
		||||
	case PubKeyAlgoECDH:
 | 
			
		||||
		return serializeEncryptedKeyECDH(w, config.Random(), buf, pub.PublicKey.(*ecdh.PublicKey), keyBlock, pub.oid, pub.Fingerprint)
 | 
			
		||||
	case PubKeyAlgoDSA, PubKeyAlgoRSASignOnly:
 | 
			
		||||
		return errors.InvalidArgumentError("cannot encrypt to public key of type " + strconv.Itoa(int(pub.PubKeyAlgo)))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return errors.UnsupportedError("encrypting a key to public key of type " + strconv.Itoa(int(pub.PubKeyAlgo)))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func serializeEncryptedKeyRSA(w io.Writer, rand io.Reader, header [10]byte, pub *rsa.PublicKey, keyBlock []byte) error {
 | 
			
		||||
	cipherText, err := rsa.EncryptPKCS1v15(rand, pub, keyBlock)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return errors.InvalidArgumentError("RSA encryption failed: " + err.Error())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cipherMPI := encoding.NewMPI(cipherText)
 | 
			
		||||
	packetLen := 10 /* header length */ + int(cipherMPI.EncodedLength())
 | 
			
		||||
 | 
			
		||||
	err = serializeHeader(w, packetTypeEncryptedKey, packetLen)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	_, err = w.Write(header[:])
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	_, err = w.Write(cipherMPI.EncodedBytes())
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func serializeEncryptedKeyElGamal(w io.Writer, rand io.Reader, header [10]byte, pub *elgamal.PublicKey, keyBlock []byte) error {
 | 
			
		||||
	c1, c2, err := elgamal.Encrypt(rand, pub, keyBlock)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return errors.InvalidArgumentError("ElGamal encryption failed: " + err.Error())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	packetLen := 10 /* header length */
 | 
			
		||||
	packetLen += 2 /* mpi size */ + (c1.BitLen()+7)/8
 | 
			
		||||
	packetLen += 2 /* mpi size */ + (c2.BitLen()+7)/8
 | 
			
		||||
 | 
			
		||||
	err = serializeHeader(w, packetTypeEncryptedKey, packetLen)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	_, err = w.Write(header[:])
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if _, err = w.Write(new(encoding.MPI).SetBig(c1).EncodedBytes()); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	_, err = w.Write(new(encoding.MPI).SetBig(c2).EncodedBytes())
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func serializeEncryptedKeyECDH(w io.Writer, rand io.Reader, header [10]byte, pub *ecdh.PublicKey, keyBlock []byte, oid encoding.Field, fingerprint []byte) error {
 | 
			
		||||
	vsG, c, err := ecdh.Encrypt(rand, pub, keyBlock, oid.EncodedBytes(), fingerprint)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return errors.InvalidArgumentError("ECDH encryption failed: " + err.Error())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	g := encoding.NewMPI(vsG)
 | 
			
		||||
	m := encoding.NewOID(c)
 | 
			
		||||
 | 
			
		||||
	packetLen := 10 /* header length */
 | 
			
		||||
	packetLen += int(g.EncodedLength()) + int(m.EncodedLength())
 | 
			
		||||
 | 
			
		||||
	err = serializeHeader(w, packetTypeEncryptedKey, packetLen)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, err = w.Write(header[:])
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if _, err = w.Write(g.EncodedBytes()); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	_, err = w.Write(m.EncodedBytes())
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										91
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/literal.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/literal.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,91 @@
 | 
			
		||||
// Copyright 2011 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package packet
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/binary"
 | 
			
		||||
	"io"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// LiteralData represents an encrypted file. See RFC 4880, section 5.9.
 | 
			
		||||
type LiteralData struct {
 | 
			
		||||
	Format   uint8
 | 
			
		||||
	IsBinary bool
 | 
			
		||||
	FileName string
 | 
			
		||||
	Time     uint32 // Unix epoch time. Either creation time or modification time. 0 means undefined.
 | 
			
		||||
	Body     io.Reader
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ForEyesOnly returns whether the contents of the LiteralData have been marked
 | 
			
		||||
// as especially sensitive.
 | 
			
		||||
func (l *LiteralData) ForEyesOnly() bool {
 | 
			
		||||
	return l.FileName == "_CONSOLE"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *LiteralData) parse(r io.Reader) (err error) {
 | 
			
		||||
	var buf [256]byte
 | 
			
		||||
 | 
			
		||||
	_, err = readFull(r, buf[:2])
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	l.Format = buf[0]
 | 
			
		||||
	l.IsBinary = l.Format == 'b'
 | 
			
		||||
	fileNameLen := int(buf[1])
 | 
			
		||||
 | 
			
		||||
	_, err = readFull(r, buf[:fileNameLen])
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	l.FileName = string(buf[:fileNameLen])
 | 
			
		||||
 | 
			
		||||
	_, err = readFull(r, buf[:4])
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	l.Time = binary.BigEndian.Uint32(buf[:4])
 | 
			
		||||
	l.Body = r
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SerializeLiteral serializes a literal data packet to w and returns a
 | 
			
		||||
// WriteCloser to which the data itself can be written and which MUST be closed
 | 
			
		||||
// on completion. The fileName is truncated to 255 bytes.
 | 
			
		||||
func SerializeLiteral(w io.WriteCloser, isBinary bool, fileName string, time uint32) (plaintext io.WriteCloser, err error) {
 | 
			
		||||
	var buf [4]byte
 | 
			
		||||
	buf[0] = 't'
 | 
			
		||||
	if isBinary {
 | 
			
		||||
		buf[0] = 'b'
 | 
			
		||||
	}
 | 
			
		||||
	if len(fileName) > 255 {
 | 
			
		||||
		fileName = fileName[:255]
 | 
			
		||||
	}
 | 
			
		||||
	buf[1] = byte(len(fileName))
 | 
			
		||||
 | 
			
		||||
	inner, err := serializeStreamHeader(w, packetTypeLiteralData)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, err = inner.Write(buf[:2])
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	_, err = inner.Write([]byte(fileName))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	binary.BigEndian.PutUint32(buf[:], time)
 | 
			
		||||
	_, err = inner.Write(buf[:])
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	plaintext = inner
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										137
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/ocfb.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										137
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/ocfb.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,137 @@
 | 
			
		||||
// Copyright 2010 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
// OpenPGP CFB Mode. http://tools.ietf.org/html/rfc4880#section-13.9
 | 
			
		||||
 | 
			
		||||
package packet
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/cipher"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type ocfbEncrypter struct {
 | 
			
		||||
	b       cipher.Block
 | 
			
		||||
	fre     []byte
 | 
			
		||||
	outUsed int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// An OCFBResyncOption determines if the "resynchronization step" of OCFB is
 | 
			
		||||
// performed.
 | 
			
		||||
type OCFBResyncOption bool
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	OCFBResync   OCFBResyncOption = true
 | 
			
		||||
	OCFBNoResync OCFBResyncOption = false
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// NewOCFBEncrypter returns a cipher.Stream which encrypts data with OpenPGP's
 | 
			
		||||
// cipher feedback mode using the given cipher.Block, and an initial amount of
 | 
			
		||||
// ciphertext.  randData must be random bytes and be the same length as the
 | 
			
		||||
// cipher.Block's block size. Resync determines if the "resynchronization step"
 | 
			
		||||
// from RFC 4880, 13.9 step 7 is performed. Different parts of OpenPGP vary on
 | 
			
		||||
// this point.
 | 
			
		||||
func NewOCFBEncrypter(block cipher.Block, randData []byte, resync OCFBResyncOption) (cipher.Stream, []byte) {
 | 
			
		||||
	blockSize := block.BlockSize()
 | 
			
		||||
	if len(randData) != blockSize {
 | 
			
		||||
		return nil, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	x := &ocfbEncrypter{
 | 
			
		||||
		b:       block,
 | 
			
		||||
		fre:     make([]byte, blockSize),
 | 
			
		||||
		outUsed: 0,
 | 
			
		||||
	}
 | 
			
		||||
	prefix := make([]byte, blockSize+2)
 | 
			
		||||
 | 
			
		||||
	block.Encrypt(x.fre, x.fre)
 | 
			
		||||
	for i := 0; i < blockSize; i++ {
 | 
			
		||||
		prefix[i] = randData[i] ^ x.fre[i]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	block.Encrypt(x.fre, prefix[:blockSize])
 | 
			
		||||
	prefix[blockSize] = x.fre[0] ^ randData[blockSize-2]
 | 
			
		||||
	prefix[blockSize+1] = x.fre[1] ^ randData[blockSize-1]
 | 
			
		||||
 | 
			
		||||
	if resync {
 | 
			
		||||
		block.Encrypt(x.fre, prefix[2:])
 | 
			
		||||
	} else {
 | 
			
		||||
		x.fre[0] = prefix[blockSize]
 | 
			
		||||
		x.fre[1] = prefix[blockSize+1]
 | 
			
		||||
		x.outUsed = 2
 | 
			
		||||
	}
 | 
			
		||||
	return x, prefix
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (x *ocfbEncrypter) XORKeyStream(dst, src []byte) {
 | 
			
		||||
	for i := 0; i < len(src); i++ {
 | 
			
		||||
		if x.outUsed == len(x.fre) {
 | 
			
		||||
			x.b.Encrypt(x.fre, x.fre)
 | 
			
		||||
			x.outUsed = 0
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		x.fre[x.outUsed] ^= src[i]
 | 
			
		||||
		dst[i] = x.fre[x.outUsed]
 | 
			
		||||
		x.outUsed++
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ocfbDecrypter struct {
 | 
			
		||||
	b       cipher.Block
 | 
			
		||||
	fre     []byte
 | 
			
		||||
	outUsed int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewOCFBDecrypter returns a cipher.Stream which decrypts data with OpenPGP's
 | 
			
		||||
// cipher feedback mode using the given cipher.Block. Prefix must be the first
 | 
			
		||||
// blockSize + 2 bytes of the ciphertext, where blockSize is the cipher.Block's
 | 
			
		||||
// block size. On successful exit, blockSize+2 bytes of decrypted data are written into
 | 
			
		||||
// prefix. Resync determines if the "resynchronization step" from RFC 4880,
 | 
			
		||||
// 13.9 step 7 is performed. Different parts of OpenPGP vary on this point.
 | 
			
		||||
func NewOCFBDecrypter(block cipher.Block, prefix []byte, resync OCFBResyncOption) cipher.Stream {
 | 
			
		||||
	blockSize := block.BlockSize()
 | 
			
		||||
	if len(prefix) != blockSize+2 {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	x := &ocfbDecrypter{
 | 
			
		||||
		b:       block,
 | 
			
		||||
		fre:     make([]byte, blockSize),
 | 
			
		||||
		outUsed: 0,
 | 
			
		||||
	}
 | 
			
		||||
	prefixCopy := make([]byte, len(prefix))
 | 
			
		||||
	copy(prefixCopy, prefix)
 | 
			
		||||
 | 
			
		||||
	block.Encrypt(x.fre, x.fre)
 | 
			
		||||
	for i := 0; i < blockSize; i++ {
 | 
			
		||||
		prefixCopy[i] ^= x.fre[i]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	block.Encrypt(x.fre, prefix[:blockSize])
 | 
			
		||||
	prefixCopy[blockSize] ^= x.fre[0]
 | 
			
		||||
	prefixCopy[blockSize+1] ^= x.fre[1]
 | 
			
		||||
 | 
			
		||||
	if resync {
 | 
			
		||||
		block.Encrypt(x.fre, prefix[2:])
 | 
			
		||||
	} else {
 | 
			
		||||
		x.fre[0] = prefix[blockSize]
 | 
			
		||||
		x.fre[1] = prefix[blockSize+1]
 | 
			
		||||
		x.outUsed = 2
 | 
			
		||||
	}
 | 
			
		||||
	copy(prefix, prefixCopy)
 | 
			
		||||
	return x
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (x *ocfbDecrypter) XORKeyStream(dst, src []byte) {
 | 
			
		||||
	for i := 0; i < len(src); i++ {
 | 
			
		||||
		if x.outUsed == len(x.fre) {
 | 
			
		||||
			x.b.Encrypt(x.fre, x.fre)
 | 
			
		||||
			x.outUsed = 0
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		c := src[i]
 | 
			
		||||
		dst[i] = x.fre[x.outUsed] ^ src[i]
 | 
			
		||||
		x.fre[x.outUsed] = c
 | 
			
		||||
		x.outUsed++
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										73
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/one_pass_signature.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/one_pass_signature.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,73 @@
 | 
			
		||||
// Copyright 2011 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package packet
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto"
 | 
			
		||||
	"encoding/binary"
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/openpgp/errors"
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/openpgp/s2k"
 | 
			
		||||
	"io"
 | 
			
		||||
	"strconv"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// OnePassSignature represents a one-pass signature packet. See RFC 4880,
 | 
			
		||||
// section 5.4.
 | 
			
		||||
type OnePassSignature struct {
 | 
			
		||||
	SigType    SignatureType
 | 
			
		||||
	Hash       crypto.Hash
 | 
			
		||||
	PubKeyAlgo PublicKeyAlgorithm
 | 
			
		||||
	KeyId      uint64
 | 
			
		||||
	IsLast     bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const onePassSignatureVersion = 3
 | 
			
		||||
 | 
			
		||||
func (ops *OnePassSignature) parse(r io.Reader) (err error) {
 | 
			
		||||
	var buf [13]byte
 | 
			
		||||
 | 
			
		||||
	_, err = readFull(r, buf[:])
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if buf[0] != onePassSignatureVersion {
 | 
			
		||||
		err = errors.UnsupportedError("one-pass-signature packet version " + strconv.Itoa(int(buf[0])))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var ok bool
 | 
			
		||||
	ops.Hash, ok = s2k.HashIdToHash(buf[2])
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return errors.UnsupportedError("hash function: " + strconv.Itoa(int(buf[2])))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ops.SigType = SignatureType(buf[1])
 | 
			
		||||
	ops.PubKeyAlgo = PublicKeyAlgorithm(buf[3])
 | 
			
		||||
	ops.KeyId = binary.BigEndian.Uint64(buf[4:12])
 | 
			
		||||
	ops.IsLast = buf[12] != 0
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Serialize marshals the given OnePassSignature to w.
 | 
			
		||||
func (ops *OnePassSignature) Serialize(w io.Writer) error {
 | 
			
		||||
	var buf [13]byte
 | 
			
		||||
	buf[0] = onePassSignatureVersion
 | 
			
		||||
	buf[1] = uint8(ops.SigType)
 | 
			
		||||
	var ok bool
 | 
			
		||||
	buf[2], ok = s2k.HashToHashId(ops.Hash)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return errors.UnsupportedError("hash type: " + strconv.Itoa(int(ops.Hash)))
 | 
			
		||||
	}
 | 
			
		||||
	buf[3] = uint8(ops.PubKeyAlgo)
 | 
			
		||||
	binary.BigEndian.PutUint64(buf[4:12], ops.KeyId)
 | 
			
		||||
	if ops.IsLast {
 | 
			
		||||
		buf[12] = 1
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := serializeHeader(w, packetTypeOnePassSignature, len(buf)); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	_, err := w.Write(buf[:])
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										162
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/opaque.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										162
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/opaque.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,162 @@
 | 
			
		||||
// Copyright 2012 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package packet
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"io"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/openpgp/errors"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// OpaquePacket represents an OpenPGP packet as raw, unparsed data. This is
 | 
			
		||||
// useful for splitting and storing the original packet contents separately,
 | 
			
		||||
// handling unsupported packet types or accessing parts of the packet not yet
 | 
			
		||||
// implemented by this package.
 | 
			
		||||
type OpaquePacket struct {
 | 
			
		||||
	// Packet type
 | 
			
		||||
	Tag uint8
 | 
			
		||||
	// Reason why the packet was parsed opaquely
 | 
			
		||||
	Reason error
 | 
			
		||||
	// Binary contents of the packet data
 | 
			
		||||
	Contents []byte
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (op *OpaquePacket) parse(r io.Reader) (err error) {
 | 
			
		||||
	op.Contents, err = ioutil.ReadAll(r)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Serialize marshals the packet to a writer in its original form, including
 | 
			
		||||
// the packet header.
 | 
			
		||||
func (op *OpaquePacket) Serialize(w io.Writer) (err error) {
 | 
			
		||||
	err = serializeHeader(w, packetType(op.Tag), len(op.Contents))
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		_, err = w.Write(op.Contents)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Parse attempts to parse the opaque contents into a structure supported by
 | 
			
		||||
// this package. If the packet is not known then the result will be another
 | 
			
		||||
// OpaquePacket.
 | 
			
		||||
func (op *OpaquePacket) Parse() (p Packet, err error) {
 | 
			
		||||
	hdr := bytes.NewBuffer(nil)
 | 
			
		||||
	err = serializeHeader(hdr, packetType(op.Tag), len(op.Contents))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		op.Reason = err
 | 
			
		||||
		return op, err
 | 
			
		||||
	}
 | 
			
		||||
	p, err = Read(io.MultiReader(hdr, bytes.NewBuffer(op.Contents)))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		op.Reason = err
 | 
			
		||||
		p = op
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// OpaqueReader reads OpaquePackets from an io.Reader.
 | 
			
		||||
type OpaqueReader struct {
 | 
			
		||||
	r io.Reader
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewOpaqueReader(r io.Reader) *OpaqueReader {
 | 
			
		||||
	return &OpaqueReader{r: r}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Read the next OpaquePacket.
 | 
			
		||||
func (or *OpaqueReader) Next() (op *OpaquePacket, err error) {
 | 
			
		||||
	tag, _, contents, err := readHeader(or.r)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	op = &OpaquePacket{Tag: uint8(tag), Reason: err}
 | 
			
		||||
	err = op.parse(contents)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		consumeAll(contents)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// OpaqueSubpacket represents an unparsed OpenPGP subpacket,
 | 
			
		||||
// as found in signature and user attribute packets.
 | 
			
		||||
type OpaqueSubpacket struct {
 | 
			
		||||
	SubType  uint8
 | 
			
		||||
	Contents []byte
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// OpaqueSubpackets extracts opaque, unparsed OpenPGP subpackets from
 | 
			
		||||
// their byte representation.
 | 
			
		||||
func OpaqueSubpackets(contents []byte) (result []*OpaqueSubpacket, err error) {
 | 
			
		||||
	var (
 | 
			
		||||
		subHeaderLen int
 | 
			
		||||
		subPacket    *OpaqueSubpacket
 | 
			
		||||
	)
 | 
			
		||||
	for len(contents) > 0 {
 | 
			
		||||
		subHeaderLen, subPacket, err = nextSubpacket(contents)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
		result = append(result, subPacket)
 | 
			
		||||
		contents = contents[subHeaderLen+len(subPacket.Contents):]
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func nextSubpacket(contents []byte) (subHeaderLen int, subPacket *OpaqueSubpacket, err error) {
 | 
			
		||||
	// RFC 4880, section 5.2.3.1
 | 
			
		||||
	var subLen uint32
 | 
			
		||||
	if len(contents) < 1 {
 | 
			
		||||
		goto Truncated
 | 
			
		||||
	}
 | 
			
		||||
	subPacket = &OpaqueSubpacket{}
 | 
			
		||||
	switch {
 | 
			
		||||
	case contents[0] < 192:
 | 
			
		||||
		subHeaderLen = 2 // 1 length byte, 1 subtype byte
 | 
			
		||||
		if len(contents) < subHeaderLen {
 | 
			
		||||
			goto Truncated
 | 
			
		||||
		}
 | 
			
		||||
		subLen = uint32(contents[0])
 | 
			
		||||
		contents = contents[1:]
 | 
			
		||||
	case contents[0] < 255:
 | 
			
		||||
		subHeaderLen = 3 // 2 length bytes, 1 subtype
 | 
			
		||||
		if len(contents) < subHeaderLen {
 | 
			
		||||
			goto Truncated
 | 
			
		||||
		}
 | 
			
		||||
		subLen = uint32(contents[0]-192)<<8 + uint32(contents[1]) + 192
 | 
			
		||||
		contents = contents[2:]
 | 
			
		||||
	default:
 | 
			
		||||
		subHeaderLen = 6 // 5 length bytes, 1 subtype
 | 
			
		||||
		if len(contents) < subHeaderLen {
 | 
			
		||||
			goto Truncated
 | 
			
		||||
		}
 | 
			
		||||
		subLen = uint32(contents[1])<<24 |
 | 
			
		||||
			uint32(contents[2])<<16 |
 | 
			
		||||
			uint32(contents[3])<<8 |
 | 
			
		||||
			uint32(contents[4])
 | 
			
		||||
		contents = contents[5:]
 | 
			
		||||
	}
 | 
			
		||||
	if subLen > uint32(len(contents)) || subLen == 0 {
 | 
			
		||||
		goto Truncated
 | 
			
		||||
	}
 | 
			
		||||
	subPacket.SubType = contents[0]
 | 
			
		||||
	subPacket.Contents = contents[1:subLen]
 | 
			
		||||
	return
 | 
			
		||||
Truncated:
 | 
			
		||||
	err = errors.StructuralError("subpacket truncated")
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (osp *OpaqueSubpacket) Serialize(w io.Writer) (err error) {
 | 
			
		||||
	buf := make([]byte, 6)
 | 
			
		||||
	n := serializeSubpacketLength(buf, len(osp.Contents)+1)
 | 
			
		||||
	buf[n] = osp.SubType
 | 
			
		||||
	if _, err = w.Write(buf[:n+1]); err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	_, err = w.Write(osp.Contents)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										539
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/packet.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										539
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/packet.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,539 @@
 | 
			
		||||
// Copyright 2011 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
// Package packet implements parsing and serialization of OpenPGP packets, as
 | 
			
		||||
// specified in RFC 4880.
 | 
			
		||||
package packet // import "github.com/ProtonMail/go-crypto/openpgp/packet"
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"crypto/cipher"
 | 
			
		||||
	"crypto/rsa"
 | 
			
		||||
	"io"
 | 
			
		||||
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/openpgp/errors"
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/openpgp/internal/algorithm"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// readFull is the same as io.ReadFull except that reading zero bytes returns
 | 
			
		||||
// ErrUnexpectedEOF rather than EOF.
 | 
			
		||||
func readFull(r io.Reader, buf []byte) (n int, err error) {
 | 
			
		||||
	n, err = io.ReadFull(r, buf)
 | 
			
		||||
	if err == io.EOF {
 | 
			
		||||
		err = io.ErrUnexpectedEOF
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// readLength reads an OpenPGP length from r. See RFC 4880, section 4.2.2.
 | 
			
		||||
func readLength(r io.Reader) (length int64, isPartial bool, err error) {
 | 
			
		||||
	var buf [4]byte
 | 
			
		||||
	_, err = readFull(r, buf[:1])
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	switch {
 | 
			
		||||
	case buf[0] < 192:
 | 
			
		||||
		length = int64(buf[0])
 | 
			
		||||
	case buf[0] < 224:
 | 
			
		||||
		length = int64(buf[0]-192) << 8
 | 
			
		||||
		_, err = readFull(r, buf[0:1])
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		length += int64(buf[0]) + 192
 | 
			
		||||
	case buf[0] < 255:
 | 
			
		||||
		length = int64(1) << (buf[0] & 0x1f)
 | 
			
		||||
		isPartial = true
 | 
			
		||||
	default:
 | 
			
		||||
		_, err = readFull(r, buf[0:4])
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		length = int64(buf[0])<<24 |
 | 
			
		||||
			int64(buf[1])<<16 |
 | 
			
		||||
			int64(buf[2])<<8 |
 | 
			
		||||
			int64(buf[3])
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// partialLengthReader wraps an io.Reader and handles OpenPGP partial lengths.
 | 
			
		||||
// The continuation lengths are parsed and removed from the stream and EOF is
 | 
			
		||||
// returned at the end of the packet. See RFC 4880, section 4.2.2.4.
 | 
			
		||||
type partialLengthReader struct {
 | 
			
		||||
	r         io.Reader
 | 
			
		||||
	remaining int64
 | 
			
		||||
	isPartial bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *partialLengthReader) Read(p []byte) (n int, err error) {
 | 
			
		||||
	for r.remaining == 0 {
 | 
			
		||||
		if !r.isPartial {
 | 
			
		||||
			return 0, io.EOF
 | 
			
		||||
		}
 | 
			
		||||
		r.remaining, r.isPartial, err = readLength(r.r)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return 0, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	toRead := int64(len(p))
 | 
			
		||||
	if toRead > r.remaining {
 | 
			
		||||
		toRead = r.remaining
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	n, err = r.r.Read(p[:int(toRead)])
 | 
			
		||||
	r.remaining -= int64(n)
 | 
			
		||||
	if n < int(toRead) && err == io.EOF {
 | 
			
		||||
		err = io.ErrUnexpectedEOF
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// partialLengthWriter writes a stream of data using OpenPGP partial lengths.
 | 
			
		||||
// See RFC 4880, section 4.2.2.4.
 | 
			
		||||
type partialLengthWriter struct {
 | 
			
		||||
	w          io.WriteCloser
 | 
			
		||||
	buf        bytes.Buffer
 | 
			
		||||
	lengthByte [1]byte
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *partialLengthWriter) Write(p []byte) (n int, err error) {
 | 
			
		||||
	bufLen := w.buf.Len()
 | 
			
		||||
	if bufLen > 512 {
 | 
			
		||||
		for power := uint(30); ; power-- {
 | 
			
		||||
			l := 1 << power
 | 
			
		||||
			if bufLen >= l {
 | 
			
		||||
				w.lengthByte[0] = 224 + uint8(power)
 | 
			
		||||
				_, err = w.w.Write(w.lengthByte[:])
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return
 | 
			
		||||
				}
 | 
			
		||||
				var m int
 | 
			
		||||
				m, err = w.w.Write(w.buf.Next(l))
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return
 | 
			
		||||
				}
 | 
			
		||||
				if m != l {
 | 
			
		||||
					return 0, io.ErrShortWrite
 | 
			
		||||
				}
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return w.buf.Write(p)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *partialLengthWriter) Close() (err error) {
 | 
			
		||||
	len := w.buf.Len()
 | 
			
		||||
	err = serializeLength(w.w, len)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	_, err = w.buf.WriteTo(w.w)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	return w.w.Close()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A spanReader is an io.LimitReader, but it returns ErrUnexpectedEOF if the
 | 
			
		||||
// underlying Reader returns EOF before the limit has been reached.
 | 
			
		||||
type spanReader struct {
 | 
			
		||||
	r io.Reader
 | 
			
		||||
	n int64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *spanReader) Read(p []byte) (n int, err error) {
 | 
			
		||||
	if l.n <= 0 {
 | 
			
		||||
		return 0, io.EOF
 | 
			
		||||
	}
 | 
			
		||||
	if int64(len(p)) > l.n {
 | 
			
		||||
		p = p[0:l.n]
 | 
			
		||||
	}
 | 
			
		||||
	n, err = l.r.Read(p)
 | 
			
		||||
	l.n -= int64(n)
 | 
			
		||||
	if l.n > 0 && err == io.EOF {
 | 
			
		||||
		err = io.ErrUnexpectedEOF
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// readHeader parses a packet header and returns an io.Reader which will return
 | 
			
		||||
// the contents of the packet. See RFC 4880, section 4.2.
 | 
			
		||||
func readHeader(r io.Reader) (tag packetType, length int64, contents io.Reader, err error) {
 | 
			
		||||
	var buf [4]byte
 | 
			
		||||
	_, err = io.ReadFull(r, buf[:1])
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if buf[0]&0x80 == 0 {
 | 
			
		||||
		err = errors.StructuralError("tag byte does not have MSB set")
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if buf[0]&0x40 == 0 {
 | 
			
		||||
		// Old format packet
 | 
			
		||||
		tag = packetType((buf[0] & 0x3f) >> 2)
 | 
			
		||||
		lengthType := buf[0] & 3
 | 
			
		||||
		if lengthType == 3 {
 | 
			
		||||
			length = -1
 | 
			
		||||
			contents = r
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		lengthBytes := 1 << lengthType
 | 
			
		||||
		_, err = readFull(r, buf[0:lengthBytes])
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		for i := 0; i < lengthBytes; i++ {
 | 
			
		||||
			length <<= 8
 | 
			
		||||
			length |= int64(buf[i])
 | 
			
		||||
		}
 | 
			
		||||
		contents = &spanReader{r, length}
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// New format packet
 | 
			
		||||
	tag = packetType(buf[0] & 0x3f)
 | 
			
		||||
	length, isPartial, err := readLength(r)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if isPartial {
 | 
			
		||||
		contents = &partialLengthReader{
 | 
			
		||||
			remaining: length,
 | 
			
		||||
			isPartial: true,
 | 
			
		||||
			r:         r,
 | 
			
		||||
		}
 | 
			
		||||
		length = -1
 | 
			
		||||
	} else {
 | 
			
		||||
		contents = &spanReader{r, length}
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// serializeHeader writes an OpenPGP packet header to w. See RFC 4880, section
 | 
			
		||||
// 4.2.
 | 
			
		||||
func serializeHeader(w io.Writer, ptype packetType, length int) (err error) {
 | 
			
		||||
	err = serializeType(w, ptype)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	return serializeLength(w, length)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// serializeType writes an OpenPGP packet type to w. See RFC 4880, section
 | 
			
		||||
// 4.2.
 | 
			
		||||
func serializeType(w io.Writer, ptype packetType) (err error) {
 | 
			
		||||
	var buf [1]byte
 | 
			
		||||
	buf[0] = 0x80 | 0x40 | byte(ptype)
 | 
			
		||||
	_, err = w.Write(buf[:])
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// serializeLength writes an OpenPGP packet length to w. See RFC 4880, section
 | 
			
		||||
// 4.2.2.
 | 
			
		||||
func serializeLength(w io.Writer, length int) (err error) {
 | 
			
		||||
	var buf [5]byte
 | 
			
		||||
	var n int
 | 
			
		||||
 | 
			
		||||
	if length < 192 {
 | 
			
		||||
		buf[0] = byte(length)
 | 
			
		||||
		n = 1
 | 
			
		||||
	} else if length < 8384 {
 | 
			
		||||
		length -= 192
 | 
			
		||||
		buf[0] = 192 + byte(length>>8)
 | 
			
		||||
		buf[1] = byte(length)
 | 
			
		||||
		n = 2
 | 
			
		||||
	} else {
 | 
			
		||||
		buf[0] = 255
 | 
			
		||||
		buf[1] = byte(length >> 24)
 | 
			
		||||
		buf[2] = byte(length >> 16)
 | 
			
		||||
		buf[3] = byte(length >> 8)
 | 
			
		||||
		buf[4] = byte(length)
 | 
			
		||||
		n = 5
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, err = w.Write(buf[:n])
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// serializeStreamHeader writes an OpenPGP packet header to w where the
 | 
			
		||||
// length of the packet is unknown. It returns a io.WriteCloser which can be
 | 
			
		||||
// used to write the contents of the packet. See RFC 4880, section 4.2.
 | 
			
		||||
func serializeStreamHeader(w io.WriteCloser, ptype packetType) (out io.WriteCloser, err error) {
 | 
			
		||||
	err = serializeType(w, ptype)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	out = &partialLengthWriter{w: w}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Packet represents an OpenPGP packet. Users are expected to try casting
 | 
			
		||||
// instances of this interface to specific packet types.
 | 
			
		||||
type Packet interface {
 | 
			
		||||
	parse(io.Reader) error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// consumeAll reads from the given Reader until error, returning the number of
 | 
			
		||||
// bytes read.
 | 
			
		||||
func consumeAll(r io.Reader) (n int64, err error) {
 | 
			
		||||
	var m int
 | 
			
		||||
	var buf [1024]byte
 | 
			
		||||
 | 
			
		||||
	for {
 | 
			
		||||
		m, err = r.Read(buf[:])
 | 
			
		||||
		n += int64(m)
 | 
			
		||||
		if err == io.EOF {
 | 
			
		||||
			err = nil
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// packetType represents the numeric ids of the different OpenPGP packet types. See
 | 
			
		||||
// http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-2
 | 
			
		||||
type packetType uint8
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	packetTypeEncryptedKey              packetType = 1
 | 
			
		||||
	packetTypeSignature                 packetType = 2
 | 
			
		||||
	packetTypeSymmetricKeyEncrypted     packetType = 3
 | 
			
		||||
	packetTypeOnePassSignature          packetType = 4
 | 
			
		||||
	packetTypePrivateKey                packetType = 5
 | 
			
		||||
	packetTypePublicKey                 packetType = 6
 | 
			
		||||
	packetTypePrivateSubkey             packetType = 7
 | 
			
		||||
	packetTypeCompressed                packetType = 8
 | 
			
		||||
	packetTypeSymmetricallyEncrypted    packetType = 9
 | 
			
		||||
	packetTypeLiteralData               packetType = 11
 | 
			
		||||
	packetTypeUserId                    packetType = 13
 | 
			
		||||
	packetTypePublicSubkey              packetType = 14
 | 
			
		||||
	packetTypeUserAttribute             packetType = 17
 | 
			
		||||
	packetTypeSymmetricallyEncryptedMDC packetType = 18
 | 
			
		||||
	packetTypeAEADEncrypted             packetType = 20
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// EncryptedDataPacket holds encrypted data. It is currently implemented by
 | 
			
		||||
// SymmetricallyEncrypted and AEADEncrypted.
 | 
			
		||||
type EncryptedDataPacket interface {
 | 
			
		||||
	Decrypt(CipherFunction, []byte) (io.ReadCloser, error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Read reads a single OpenPGP packet from the given io.Reader. If there is an
 | 
			
		||||
// error parsing a packet, the whole packet is consumed from the input.
 | 
			
		||||
func Read(r io.Reader) (p Packet, err error) {
 | 
			
		||||
	tag, _, contents, err := readHeader(r)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch tag {
 | 
			
		||||
	case packetTypeEncryptedKey:
 | 
			
		||||
		p = new(EncryptedKey)
 | 
			
		||||
	case packetTypeSignature:
 | 
			
		||||
		p = new(Signature)
 | 
			
		||||
	case packetTypeSymmetricKeyEncrypted:
 | 
			
		||||
		p = new(SymmetricKeyEncrypted)
 | 
			
		||||
	case packetTypeOnePassSignature:
 | 
			
		||||
		p = new(OnePassSignature)
 | 
			
		||||
	case packetTypePrivateKey, packetTypePrivateSubkey:
 | 
			
		||||
		pk := new(PrivateKey)
 | 
			
		||||
		if tag == packetTypePrivateSubkey {
 | 
			
		||||
			pk.IsSubkey = true
 | 
			
		||||
		}
 | 
			
		||||
		p = pk
 | 
			
		||||
	case packetTypePublicKey, packetTypePublicSubkey:
 | 
			
		||||
		isSubkey := tag == packetTypePublicSubkey
 | 
			
		||||
		p = &PublicKey{IsSubkey: isSubkey}
 | 
			
		||||
	case packetTypeCompressed:
 | 
			
		||||
		p = new(Compressed)
 | 
			
		||||
	case packetTypeSymmetricallyEncrypted:
 | 
			
		||||
		p = new(SymmetricallyEncrypted)
 | 
			
		||||
	case packetTypeLiteralData:
 | 
			
		||||
		p = new(LiteralData)
 | 
			
		||||
	case packetTypeUserId:
 | 
			
		||||
		p = new(UserId)
 | 
			
		||||
	case packetTypeUserAttribute:
 | 
			
		||||
		p = new(UserAttribute)
 | 
			
		||||
	case packetTypeSymmetricallyEncryptedMDC:
 | 
			
		||||
		se := new(SymmetricallyEncrypted)
 | 
			
		||||
		se.MDC = true
 | 
			
		||||
		p = se
 | 
			
		||||
	case packetTypeAEADEncrypted:
 | 
			
		||||
		p = new(AEADEncrypted)
 | 
			
		||||
	default:
 | 
			
		||||
		err = errors.UnknownPacketTypeError(tag)
 | 
			
		||||
	}
 | 
			
		||||
	if p != nil {
 | 
			
		||||
		err = p.parse(contents)
 | 
			
		||||
	}
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		consumeAll(contents)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SignatureType represents the different semantic meanings of an OpenPGP
 | 
			
		||||
// signature. See RFC 4880, section 5.2.1.
 | 
			
		||||
type SignatureType uint8
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	SigTypeBinary            SignatureType = 0x00
 | 
			
		||||
	SigTypeText                            = 0x01
 | 
			
		||||
	SigTypeGenericCert                     = 0x10
 | 
			
		||||
	SigTypePersonaCert                     = 0x11
 | 
			
		||||
	SigTypeCasualCert                      = 0x12
 | 
			
		||||
	SigTypePositiveCert                    = 0x13
 | 
			
		||||
	SigTypeSubkeyBinding                   = 0x18
 | 
			
		||||
	SigTypePrimaryKeyBinding               = 0x19
 | 
			
		||||
	SigTypeDirectSignature                 = 0x1F
 | 
			
		||||
	SigTypeKeyRevocation                   = 0x20
 | 
			
		||||
	SigTypeSubkeyRevocation                = 0x28
 | 
			
		||||
	SigTypeCertificationRevocation         = 0x30
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// PublicKeyAlgorithm represents the different public key system specified for
 | 
			
		||||
// OpenPGP. See
 | 
			
		||||
// http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-12
 | 
			
		||||
type PublicKeyAlgorithm uint8
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	PubKeyAlgoRSA     PublicKeyAlgorithm = 1
 | 
			
		||||
	PubKeyAlgoElGamal PublicKeyAlgorithm = 16
 | 
			
		||||
	PubKeyAlgoDSA     PublicKeyAlgorithm = 17
 | 
			
		||||
	// RFC 6637, Section 5.
 | 
			
		||||
	PubKeyAlgoECDH  PublicKeyAlgorithm = 18
 | 
			
		||||
	PubKeyAlgoECDSA PublicKeyAlgorithm = 19
 | 
			
		||||
	// https://www.ietf.org/archive/id/draft-koch-eddsa-for-openpgp-04.txt
 | 
			
		||||
	PubKeyAlgoEdDSA PublicKeyAlgorithm = 22
 | 
			
		||||
 | 
			
		||||
	// Deprecated in RFC 4880, Section 13.5. Use key flags instead.
 | 
			
		||||
	PubKeyAlgoRSAEncryptOnly PublicKeyAlgorithm = 2
 | 
			
		||||
	PubKeyAlgoRSASignOnly    PublicKeyAlgorithm = 3
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// CanEncrypt returns true if it's possible to encrypt a message to a public
 | 
			
		||||
// key of the given type.
 | 
			
		||||
func (pka PublicKeyAlgorithm) CanEncrypt() bool {
 | 
			
		||||
	switch pka {
 | 
			
		||||
	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoElGamal, PubKeyAlgoECDH:
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CanSign returns true if it's possible for a public key of the given type to
 | 
			
		||||
// sign a message.
 | 
			
		||||
func (pka PublicKeyAlgorithm) CanSign() bool {
 | 
			
		||||
	switch pka {
 | 
			
		||||
	case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA, PubKeyAlgoECDSA, PubKeyAlgoEdDSA:
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CipherFunction represents the different block ciphers specified for OpenPGP. See
 | 
			
		||||
// http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-13
 | 
			
		||||
type CipherFunction algorithm.CipherFunction
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	Cipher3DES   CipherFunction = 2
 | 
			
		||||
	CipherCAST5  CipherFunction = 3
 | 
			
		||||
	CipherAES128 CipherFunction = 7
 | 
			
		||||
	CipherAES192 CipherFunction = 8
 | 
			
		||||
	CipherAES256 CipherFunction = 9
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// KeySize returns the key size, in bytes, of cipher.
 | 
			
		||||
func (cipher CipherFunction) KeySize() int {
 | 
			
		||||
	return algorithm.CipherFunction(cipher).KeySize()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// blockSize returns the block size, in bytes, of cipher.
 | 
			
		||||
func (cipher CipherFunction) blockSize() int {
 | 
			
		||||
	return algorithm.CipherFunction(cipher).BlockSize()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// new returns a fresh instance of the given cipher.
 | 
			
		||||
func (cipher CipherFunction) new(key []byte) (block cipher.Block) {
 | 
			
		||||
	return algorithm.CipherFunction(cipher).New(key)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// padToKeySize left-pads a MPI with zeroes to match the length of the
 | 
			
		||||
// specified RSA public.
 | 
			
		||||
func padToKeySize(pub *rsa.PublicKey, b []byte) []byte {
 | 
			
		||||
	k := (pub.N.BitLen() + 7) / 8
 | 
			
		||||
	if len(b) >= k {
 | 
			
		||||
		return b
 | 
			
		||||
	}
 | 
			
		||||
	bb := make([]byte, k)
 | 
			
		||||
	copy(bb[len(bb)-len(b):], b)
 | 
			
		||||
	return bb
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CompressionAlgo Represents the different compression algorithms
 | 
			
		||||
// supported by OpenPGP (except for BZIP2, which is not currently
 | 
			
		||||
// supported). See Section 9.3 of RFC 4880.
 | 
			
		||||
type CompressionAlgo uint8
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	CompressionNone CompressionAlgo = 0
 | 
			
		||||
	CompressionZIP  CompressionAlgo = 1
 | 
			
		||||
	CompressionZLIB CompressionAlgo = 2
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// AEADMode represents the different Authenticated Encryption with Associated
 | 
			
		||||
// Data specified for OpenPGP.
 | 
			
		||||
type AEADMode algorithm.AEADMode
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	AEADModeEAX             AEADMode = 1
 | 
			
		||||
	AEADModeOCB             AEADMode = 2
 | 
			
		||||
	AEADModeExperimentalGCM AEADMode = 100
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (mode AEADMode) NonceLength() int {
 | 
			
		||||
	return algorithm.AEADMode(mode).NonceLength()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (mode AEADMode) TagLength() int {
 | 
			
		||||
	return algorithm.AEADMode(mode).TagLength()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// new returns a fresh instance of the given mode.
 | 
			
		||||
func (mode AEADMode) new(block cipher.Block) cipher.AEAD {
 | 
			
		||||
	return algorithm.AEADMode(mode).New(block)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ReasonForRevocation represents a revocation reason code as per RFC4880
 | 
			
		||||
// section 5.2.3.23.
 | 
			
		||||
type ReasonForRevocation uint8
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	NoReason       ReasonForRevocation = 0
 | 
			
		||||
	KeySuperseded  ReasonForRevocation = 1
 | 
			
		||||
	KeyCompromised ReasonForRevocation = 2
 | 
			
		||||
	KeyRetired     ReasonForRevocation = 3
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Curve is a mapping to supported ECC curves for key generation.
 | 
			
		||||
// See https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-06.html#name-curve-specific-wire-formats
 | 
			
		||||
type Curve string
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	Curve25519 Curve = "Curve25519"
 | 
			
		||||
	Curve448 Curve = "Curve448"
 | 
			
		||||
	CurveNistP256 Curve = "P256"
 | 
			
		||||
	CurveNistP384 Curve = "P384"
 | 
			
		||||
	CurveNistP521 Curve = "P521"
 | 
			
		||||
	CurveSecP256k1 Curve = "SecP256k1"
 | 
			
		||||
	CurveBrainpoolP256 Curve = "BrainpoolP256"
 | 
			
		||||
	CurveBrainpoolP384 Curve = "BrainpoolP384"
 | 
			
		||||
	CurveBrainpoolP512 Curve = "BrainpoolP512"
 | 
			
		||||
)
 | 
			
		||||
							
								
								
									
										736
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/private_key.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										736
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/private_key.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,736 @@
 | 
			
		||||
// 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/rand"
 | 
			
		||||
	"crypto/rsa"
 | 
			
		||||
	"crypto/sha1"
 | 
			
		||||
	"io"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"math/big"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/openpgp/ecdh"
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/openpgp/ecdsa"
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/openpgp/eddsa"
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/openpgp/elgamal"
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/openpgp/errors"
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/openpgp/internal/encoding"
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/openpgp/s2k"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// 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 *eddsa.PrivateKey) *PrivateKey {
 | 
			
		||||
	pk := new(PrivateKey)
 | 
			
		||||
	pk.PublicKey = *NewEdDSAPublicKey(creationTime, &priv.PublicKey)
 | 
			
		||||
	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 interface{}) *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.(type) {
 | 
			
		||||
	case *rsa.PrivateKey:
 | 
			
		||||
		pk.PublicKey = *NewRSAPublicKey(creationTime, &pubkey.PublicKey)
 | 
			
		||||
	case rsa.PrivateKey:
 | 
			
		||||
		pk.PublicKey = *NewRSAPublicKey(creationTime, &pubkey.PublicKey)
 | 
			
		||||
	case *ecdsa.PrivateKey:
 | 
			
		||||
		pk.PublicKey = *NewECDSAPublicKey(creationTime, &pubkey.PublicKey)
 | 
			
		||||
	case ecdsa.PrivateKey:
 | 
			
		||||
		pk.PublicKey = *NewECDSAPublicKey(creationTime, &pubkey.PublicKey)
 | 
			
		||||
	case *eddsa.PrivateKey:
 | 
			
		||||
		pk.PublicKey = *NewEdDSAPublicKey(creationTime, &pubkey.PublicKey)
 | 
			
		||||
	case eddsa.PrivateKey:
 | 
			
		||||
		pk.PublicKey = *NewEdDSAPublicKey(creationTime, &pubkey.PublicKey)
 | 
			
		||||
	default:
 | 
			
		||||
		panic("openpgp: unknown 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 {
 | 
			
		||||
		if len(privateKeyData) < 2 {
 | 
			
		||||
			return errors.StructuralError("truncated private key data")
 | 
			
		||||
		}
 | 
			
		||||
		var sum uint16
 | 
			
		||||
		for i := 0; i < len(privateKeyData)-2; i++ {
 | 
			
		||||
			sum += uint16(privateKeyData[i])
 | 
			
		||||
		}
 | 
			
		||||
		if privateKeyData[len(privateKeyData)-2] != uint8(sum>>8) ||
 | 
			
		||||
			privateKeyData[len(privateKeyData)-1] != uint8(sum) {
 | 
			
		||||
			return errors.StructuralError("private key checksum failure")
 | 
			
		||||
		}
 | 
			
		||||
		privateKeyData = privateKeyData[:len(privateKeyData)-2]
 | 
			
		||||
		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()
 | 
			
		||||
			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(encoding.NewMPI(priv.MarshalIntegerSecret()).EncodedBytes())
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func serializeEdDSAPrivateKey(w io.Writer, priv *eddsa.PrivateKey) error {
 | 
			
		||||
	_, err := w.Write(encoding.NewMPI(priv.MarshalByteSecret()).EncodedBytes())
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func serializeECDHPrivateKey(w io.Writer, priv *ecdh.PrivateKey) error {
 | 
			
		||||
	_, err := w.Write(encoding.NewMPI(priv.MarshalByteSecret()).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 *eddsa.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 := ecdsa.NewPrivateKey(*ecdsaPub)
 | 
			
		||||
 | 
			
		||||
	buf := bytes.NewBuffer(data)
 | 
			
		||||
	d := new(encoding.MPI)
 | 
			
		||||
	if _, err := d.ReadFrom(buf); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := ecdsaPriv.UnmarshalIntegerSecret(d.Bytes()); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if err := ecdsa.Validate(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 := ecdh.NewPrivateKey(*ecdhPub)
 | 
			
		||||
 | 
			
		||||
	buf := bytes.NewBuffer(data)
 | 
			
		||||
	d := new(encoding.MPI)
 | 
			
		||||
	if _, err := d.ReadFrom(buf); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := ecdhPriv.UnmarshalByteSecret(d.Bytes()); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := ecdh.Validate(ecdhPriv); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pk.PrivateKey = ecdhPriv
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (pk *PrivateKey) parseEdDSAPrivateKey(data []byte) (err error) {
 | 
			
		||||
	eddsaPub := pk.PublicKey.PublicKey.(*eddsa.PublicKey)
 | 
			
		||||
	eddsaPriv := eddsa.NewPrivateKey(*eddsaPub)
 | 
			
		||||
	eddsaPriv.PublicKey = *eddsaPub
 | 
			
		||||
 | 
			
		||||
	buf := bytes.NewBuffer(data)
 | 
			
		||||
	d := new(encoding.MPI)
 | 
			
		||||
	if _, err := d.ReadFrom(buf); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err = eddsaPriv.UnmarshalByteSecret(d.Bytes()); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := eddsa.Validate(eddsaPriv); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pk.PrivateKey = eddsaPriv
 | 
			
		||||
 | 
			
		||||
	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"
 | 
			
		||||
							
								
								
									
										802
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/public_key.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										802
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/public_key.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,802 @@
 | 
			
		||||
// 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/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/ecdsa"
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/openpgp/eddsa"
 | 
			
		||||
	"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"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
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(pub.MarshalPoint()),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	curveInfo := ecc.FindByCurve(pub.GetCurve())
 | 
			
		||||
	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 kdf = encoding.NewOID([]byte{0x1, pub.Hash.Id(), pub.Cipher.Id()})
 | 
			
		||||
	pk = &PublicKey{
 | 
			
		||||
		Version:      4,
 | 
			
		||||
		CreationTime: creationTime,
 | 
			
		||||
		PubKeyAlgo:   PubKeyAlgoECDH,
 | 
			
		||||
		PublicKey:    pub,
 | 
			
		||||
		p:            encoding.NewMPI(pub.MarshalPoint()),
 | 
			
		||||
		kdf:          kdf,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	curveInfo := ecc.FindByCurve(pub.GetCurve())
 | 
			
		||||
 | 
			
		||||
	if curveInfo == nil {
 | 
			
		||||
		panic("unknown elliptic curve")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pk.oid = curveInfo.Oid
 | 
			
		||||
	pk.setFingerprintAndKeyId()
 | 
			
		||||
	return pk
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewEdDSAPublicKey(creationTime time.Time, pub *eddsa.PublicKey) *PublicKey {
 | 
			
		||||
	curveInfo := ecc.FindByCurve(pub.GetCurve())
 | 
			
		||||
	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(pub.MarshalPoint()),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	curveInfo := ecc.FindByOid(pk.oid)
 | 
			
		||||
	if curveInfo == nil {
 | 
			
		||||
		return errors.UnsupportedError(fmt.Sprintf("unknown oid: %x", pk.oid))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c, ok := curveInfo.Curve.(ecc.ECDSACurve)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return errors.UnsupportedError(fmt.Sprintf("unsupported oid: %x", pk.oid))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ecdsaKey := ecdsa.NewPublicKey(c)
 | 
			
		||||
	err = ecdsaKey.UnmarshalPoint(pk.p.Bytes())
 | 
			
		||||
	pk.PublicKey = ecdsaKey
 | 
			
		||||
 | 
			
		||||
	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("unknown oid: %x", pk.oid))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c, ok := curveInfo.Curve.(ecc.ECDHCurve)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return errors.UnsupportedError(fmt.Sprintf("unsupported oid: %x", pk.oid))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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])))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ecdhKey := ecdh.NewPublicKey(c, kdfHash, kdfCipher)
 | 
			
		||||
	err = ecdhKey.UnmarshalPoint(pk.p.Bytes())
 | 
			
		||||
	pk.PublicKey = ecdhKey
 | 
			
		||||
 | 
			
		||||
	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 {
 | 
			
		||||
		return errors.UnsupportedError(fmt.Sprintf("unknown oid: %x", pk.oid))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c, ok := curveInfo.Curve.(ecc.EdDSACurve)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return errors.UnsupportedError(fmt.Sprintf("unsupported oid: %x", pk.oid))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pk.p = new(encoding.MPI)
 | 
			
		||||
	if _, err = pk.p.ReadFrom(r); err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pub := eddsa.NewPublicKey(c)
 | 
			
		||||
 | 
			
		||||
	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:
 | 
			
		||||
		err = pub.UnmarshalPoint(pk.p.Bytes())
 | 
			
		||||
	default:
 | 
			
		||||
		return errors.UnsupportedError("unsupported EdDSA compression: " + strconv.Itoa(int(flag)))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pk.PublicKey = pub
 | 
			
		||||
	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.(*eddsa.PublicKey)
 | 
			
		||||
		if !eddsa.Verify(eddsaPublicKey, hashBytes, sig.EdDSASigR.Bytes(), sig.EdDSASigS.Bytes()) {
 | 
			
		||||
			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 this public key, of signed.
 | 
			
		||||
func (pk *PublicKey) VerifySubkeyRevocationSignature(sig *Signature, signed *PublicKey) (err error) {
 | 
			
		||||
	h, err := keySignatureHash(pk, signed, sig.Hash)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	return pk.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`
 | 
			
		||||
							
								
								
									
										86
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/reader.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/reader.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,86 @@
 | 
			
		||||
// Copyright 2011 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package packet
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"io"
 | 
			
		||||
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/openpgp/errors"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Reader reads packets from an io.Reader and allows packets to be 'unread' so
 | 
			
		||||
// that they result from the next call to Next.
 | 
			
		||||
type Reader struct {
 | 
			
		||||
	q       []Packet
 | 
			
		||||
	readers []io.Reader
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New io.Readers are pushed when a compressed or encrypted packet is processed
 | 
			
		||||
// and recursively treated as a new source of packets. However, a carefully
 | 
			
		||||
// crafted packet can trigger an infinite recursive sequence of packets. See
 | 
			
		||||
// http://mumble.net/~campbell/misc/pgp-quine
 | 
			
		||||
// https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2013-4402
 | 
			
		||||
// This constant limits the number of recursive packets that may be pushed.
 | 
			
		||||
const maxReaders = 32
 | 
			
		||||
 | 
			
		||||
// Next returns the most recently unread Packet, or reads another packet from
 | 
			
		||||
// the top-most io.Reader. Unknown packet types are skipped.
 | 
			
		||||
func (r *Reader) Next() (p Packet, err error) {
 | 
			
		||||
	if len(r.q) > 0 {
 | 
			
		||||
		p = r.q[len(r.q)-1]
 | 
			
		||||
		r.q = r.q[:len(r.q)-1]
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for len(r.readers) > 0 {
 | 
			
		||||
		p, err = Read(r.readers[len(r.readers)-1])
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		if err == io.EOF {
 | 
			
		||||
			r.readers = r.readers[:len(r.readers)-1]
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		// TODO: Add strict mode that rejects unknown packets, instead of ignoring them.
 | 
			
		||||
		if _, ok := err.(errors.UnknownPacketTypeError); ok {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if _, ok := err.(errors.UnsupportedError); ok {
 | 
			
		||||
			switch p.(type) {
 | 
			
		||||
			case *SymmetricallyEncrypted, *AEADEncrypted, *Compressed, *LiteralData:
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil, io.EOF
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Push causes the Reader to start reading from a new io.Reader. When an EOF
 | 
			
		||||
// error is seen from the new io.Reader, it is popped and the Reader continues
 | 
			
		||||
// to read from the next most recent io.Reader. Push returns a StructuralError
 | 
			
		||||
// if pushing the reader would exceed the maximum recursion level, otherwise it
 | 
			
		||||
// returns nil.
 | 
			
		||||
func (r *Reader) Push(reader io.Reader) (err error) {
 | 
			
		||||
	if len(r.readers) >= maxReaders {
 | 
			
		||||
		return errors.StructuralError("too many layers of packets")
 | 
			
		||||
	}
 | 
			
		||||
	r.readers = append(r.readers, reader)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Unread causes the given Packet to be returned from the next call to Next.
 | 
			
		||||
func (r *Reader) Unread(p Packet) {
 | 
			
		||||
	r.q = append(r.q, p)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewReader(r io.Reader) *Reader {
 | 
			
		||||
	return &Reader{
 | 
			
		||||
		q:       nil,
 | 
			
		||||
		readers: []io.Reader{r},
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1000
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/signature.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1000
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/signature.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										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 octet 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
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										292
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/symmetrically_encrypted.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										292
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/symmetrically_encrypted.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,292 @@
 | 
			
		||||
// Copyright 2011 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package packet
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/cipher"
 | 
			
		||||
	"crypto/sha1"
 | 
			
		||||
	"crypto/subtle"
 | 
			
		||||
	"hash"
 | 
			
		||||
	"io"
 | 
			
		||||
	"strconv"
 | 
			
		||||
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/openpgp/errors"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// SymmetricallyEncrypted represents a symmetrically encrypted byte string. The
 | 
			
		||||
// encrypted Contents will consist of more OpenPGP packets. See RFC 4880,
 | 
			
		||||
// sections 5.7 and 5.13.
 | 
			
		||||
type SymmetricallyEncrypted struct {
 | 
			
		||||
	MDC      bool // true iff this is a type 18 packet and thus has an embedded MAC.
 | 
			
		||||
	Contents io.Reader
 | 
			
		||||
	prefix   []byte
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const symmetricallyEncryptedVersion = 1
 | 
			
		||||
 | 
			
		||||
func (se *SymmetricallyEncrypted) parse(r io.Reader) error {
 | 
			
		||||
	if se.MDC {
 | 
			
		||||
		// See RFC 4880, section 5.13.
 | 
			
		||||
		var buf [1]byte
 | 
			
		||||
		_, err := readFull(r, buf[:])
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		if buf[0] != symmetricallyEncryptedVersion {
 | 
			
		||||
			return errors.UnsupportedError("unknown SymmetricallyEncrypted version")
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		return errors.UnsupportedError("Symmetrically encrypted packets without MDC are not supported")
 | 
			
		||||
	}
 | 
			
		||||
	se.Contents = r
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Decrypt returns a ReadCloser, from which the decrypted Contents of the
 | 
			
		||||
// packet can be read. An incorrect key will only be detected after trying
 | 
			
		||||
// to decrypt the entire data.
 | 
			
		||||
func (se *SymmetricallyEncrypted) Decrypt(c CipherFunction, key []byte) (io.ReadCloser, error) {
 | 
			
		||||
	keySize := c.KeySize()
 | 
			
		||||
	if keySize == 0 {
 | 
			
		||||
		return nil, errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(c)))
 | 
			
		||||
	}
 | 
			
		||||
	if len(key) != keySize {
 | 
			
		||||
		return nil, errors.InvalidArgumentError("SymmetricallyEncrypted: incorrect key length")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if se.prefix == nil {
 | 
			
		||||
		se.prefix = make([]byte, c.blockSize()+2)
 | 
			
		||||
		_, err := readFull(se.Contents, se.prefix)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
	} else if len(se.prefix) != c.blockSize()+2 {
 | 
			
		||||
		return nil, errors.InvalidArgumentError("can't try ciphers with different block lengths")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ocfbResync := OCFBResync
 | 
			
		||||
	if se.MDC {
 | 
			
		||||
		// MDC packets use a different form of OCFB mode.
 | 
			
		||||
		ocfbResync = OCFBNoResync
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	s := NewOCFBDecrypter(c.new(key), se.prefix, ocfbResync)
 | 
			
		||||
 | 
			
		||||
	plaintext := cipher.StreamReader{S: s, R: se.Contents}
 | 
			
		||||
 | 
			
		||||
	if se.MDC {
 | 
			
		||||
		// MDC packets have an embedded hash that we need to check.
 | 
			
		||||
		h := sha1.New()
 | 
			
		||||
		h.Write(se.prefix)
 | 
			
		||||
		return &seMDCReader{in: plaintext, h: h}, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Otherwise, we just need to wrap plaintext so that it's a valid ReadCloser.
 | 
			
		||||
	return seReader{plaintext}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// seReader wraps an io.Reader with a no-op Close method.
 | 
			
		||||
type seReader struct {
 | 
			
		||||
	in io.Reader
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (ser seReader) Read(buf []byte) (int, error) {
 | 
			
		||||
	return ser.in.Read(buf)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (ser seReader) Close() error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const mdcTrailerSize = 1 /* tag byte */ + 1 /* length byte */ + sha1.Size
 | 
			
		||||
 | 
			
		||||
// An seMDCReader wraps an io.Reader, maintains a running hash and keeps hold
 | 
			
		||||
// of the most recent 22 bytes (mdcTrailerSize). Upon EOF, those bytes form an
 | 
			
		||||
// MDC packet containing a hash of the previous Contents which is checked
 | 
			
		||||
// against the running hash. See RFC 4880, section 5.13.
 | 
			
		||||
type seMDCReader struct {
 | 
			
		||||
	in          io.Reader
 | 
			
		||||
	h           hash.Hash
 | 
			
		||||
	trailer     [mdcTrailerSize]byte
 | 
			
		||||
	scratch     [mdcTrailerSize]byte
 | 
			
		||||
	trailerUsed int
 | 
			
		||||
	error       bool
 | 
			
		||||
	eof         bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (ser *seMDCReader) Read(buf []byte) (n int, err error) {
 | 
			
		||||
	if ser.error {
 | 
			
		||||
		err = io.ErrUnexpectedEOF
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if ser.eof {
 | 
			
		||||
		err = io.EOF
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// If we haven't yet filled the trailer buffer then we must do that
 | 
			
		||||
	// first.
 | 
			
		||||
	for ser.trailerUsed < mdcTrailerSize {
 | 
			
		||||
		n, err = ser.in.Read(ser.trailer[ser.trailerUsed:])
 | 
			
		||||
		ser.trailerUsed += n
 | 
			
		||||
		if err == io.EOF {
 | 
			
		||||
			if ser.trailerUsed != mdcTrailerSize {
 | 
			
		||||
				n = 0
 | 
			
		||||
				err = io.ErrUnexpectedEOF
 | 
			
		||||
				ser.error = true
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
			ser.eof = true
 | 
			
		||||
			n = 0
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			n = 0
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// If it's a short read then we read into a temporary buffer and shift
 | 
			
		||||
	// the data into the caller's buffer.
 | 
			
		||||
	if len(buf) <= mdcTrailerSize {
 | 
			
		||||
		n, err = readFull(ser.in, ser.scratch[:len(buf)])
 | 
			
		||||
		copy(buf, ser.trailer[:n])
 | 
			
		||||
		ser.h.Write(buf[:n])
 | 
			
		||||
		copy(ser.trailer[:], ser.trailer[n:])
 | 
			
		||||
		copy(ser.trailer[mdcTrailerSize-n:], ser.scratch[:])
 | 
			
		||||
		if n < len(buf) {
 | 
			
		||||
			ser.eof = true
 | 
			
		||||
			err = io.EOF
 | 
			
		||||
		}
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	n, err = ser.in.Read(buf[mdcTrailerSize:])
 | 
			
		||||
	copy(buf, ser.trailer[:])
 | 
			
		||||
	ser.h.Write(buf[:n])
 | 
			
		||||
	copy(ser.trailer[:], buf[n:])
 | 
			
		||||
 | 
			
		||||
	if err == io.EOF {
 | 
			
		||||
		ser.eof = true
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// This is a new-format packet tag byte for a type 19 (MDC) packet.
 | 
			
		||||
const mdcPacketTagByte = byte(0x80) | 0x40 | 19
 | 
			
		||||
 | 
			
		||||
func (ser *seMDCReader) Close() error {
 | 
			
		||||
	if ser.error {
 | 
			
		||||
		return errors.ErrMDCMissing
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for !ser.eof {
 | 
			
		||||
		// We haven't seen EOF so we need to read to the end
 | 
			
		||||
		var buf [1024]byte
 | 
			
		||||
		_, err := ser.Read(buf[:])
 | 
			
		||||
		if err == io.EOF {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return errors.ErrMDCMissing
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ser.h.Write(ser.trailer[:2])
 | 
			
		||||
 | 
			
		||||
	final := ser.h.Sum(nil)
 | 
			
		||||
	if subtle.ConstantTimeCompare(final, ser.trailer[2:]) != 1 {
 | 
			
		||||
		return errors.ErrMDCHashMismatch
 | 
			
		||||
	}
 | 
			
		||||
	// The hash already includes the MDC header, but we still check its value
 | 
			
		||||
	// to confirm encryption correctness
 | 
			
		||||
	if ser.trailer[0] != mdcPacketTagByte || ser.trailer[1] != sha1.Size {
 | 
			
		||||
		return errors.ErrMDCMissing
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// An seMDCWriter writes through to an io.WriteCloser while maintains a running
 | 
			
		||||
// hash of the data written. On close, it emits an MDC packet containing the
 | 
			
		||||
// running hash.
 | 
			
		||||
type seMDCWriter struct {
 | 
			
		||||
	w io.WriteCloser
 | 
			
		||||
	h hash.Hash
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *seMDCWriter) Write(buf []byte) (n int, err error) {
 | 
			
		||||
	w.h.Write(buf)
 | 
			
		||||
	return w.w.Write(buf)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *seMDCWriter) Close() (err error) {
 | 
			
		||||
	var buf [mdcTrailerSize]byte
 | 
			
		||||
 | 
			
		||||
	buf[0] = mdcPacketTagByte
 | 
			
		||||
	buf[1] = sha1.Size
 | 
			
		||||
	w.h.Write(buf[:2])
 | 
			
		||||
	digest := w.h.Sum(nil)
 | 
			
		||||
	copy(buf[2:], digest)
 | 
			
		||||
 | 
			
		||||
	_, err = w.w.Write(buf[:])
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	return w.w.Close()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// noOpCloser is like an ioutil.NopCloser, but for an io.Writer.
 | 
			
		||||
type noOpCloser struct {
 | 
			
		||||
	w io.Writer
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c noOpCloser) Write(data []byte) (n int, err error) {
 | 
			
		||||
	return c.w.Write(data)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c noOpCloser) Close() error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SerializeSymmetricallyEncrypted serializes a symmetrically encrypted packet
 | 
			
		||||
// to w and returns a WriteCloser to which the to-be-encrypted packets can be
 | 
			
		||||
// written.
 | 
			
		||||
// If config is nil, sensible defaults will be used.
 | 
			
		||||
func SerializeSymmetricallyEncrypted(w io.Writer, c CipherFunction, key []byte, config *Config) (Contents io.WriteCloser, err error) {
 | 
			
		||||
	if c.KeySize() != len(key) {
 | 
			
		||||
		return nil, errors.InvalidArgumentError("SymmetricallyEncrypted.Serialize: bad key length")
 | 
			
		||||
	}
 | 
			
		||||
	writeCloser := noOpCloser{w}
 | 
			
		||||
	ciphertext, err := serializeStreamHeader(writeCloser, packetTypeSymmetricallyEncryptedMDC)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, err = ciphertext.Write([]byte{symmetricallyEncryptedVersion})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	block := c.new(key)
 | 
			
		||||
	blockSize := block.BlockSize()
 | 
			
		||||
	iv := make([]byte, blockSize)
 | 
			
		||||
	_, err = config.Random().Read(iv)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	s, prefix := NewOCFBEncrypter(block, iv, OCFBNoResync)
 | 
			
		||||
	_, err = ciphertext.Write(prefix)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	plaintext := cipher.StreamWriter{S: s, W: ciphertext}
 | 
			
		||||
 | 
			
		||||
	h := sha1.New()
 | 
			
		||||
	h.Write(iv)
 | 
			
		||||
	h.Write(iv[blockSize-2:])
 | 
			
		||||
	Contents = &seMDCWriter{w: plaintext, h: h}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										94
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/userattribute.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/userattribute.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,94 @@
 | 
			
		||||
// Copyright 2013 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package packet
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"image"
 | 
			
		||||
	"image/jpeg"
 | 
			
		||||
	"io"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const UserAttrImageSubpacket = 1
 | 
			
		||||
 | 
			
		||||
// UserAttribute is capable of storing other types of data about a user
 | 
			
		||||
// beyond name, email and a text comment. In practice, user attributes are typically used
 | 
			
		||||
// to store a signed thumbnail photo JPEG image of the user.
 | 
			
		||||
// See RFC 4880, section 5.12.
 | 
			
		||||
type UserAttribute struct {
 | 
			
		||||
	Contents []*OpaqueSubpacket
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewUserAttributePhoto creates a user attribute packet
 | 
			
		||||
// containing the given images.
 | 
			
		||||
func NewUserAttributePhoto(photos ...image.Image) (uat *UserAttribute, err error) {
 | 
			
		||||
	uat = new(UserAttribute)
 | 
			
		||||
	for _, photo := range photos {
 | 
			
		||||
		var buf bytes.Buffer
 | 
			
		||||
		// RFC 4880, Section 5.12.1.
 | 
			
		||||
		data := []byte{
 | 
			
		||||
			0x10, 0x00, // Little-endian image header length (16 bytes)
 | 
			
		||||
			0x01,       // Image header version 1
 | 
			
		||||
			0x01,       // JPEG
 | 
			
		||||
			0, 0, 0, 0, // 12 reserved octets, must be all zero.
 | 
			
		||||
			0, 0, 0, 0,
 | 
			
		||||
			0, 0, 0, 0}
 | 
			
		||||
		if _, err = buf.Write(data); err != nil {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		if err = jpeg.Encode(&buf, photo, nil); err != nil {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		uat.Contents = append(uat.Contents, &OpaqueSubpacket{
 | 
			
		||||
			SubType:  UserAttrImageSubpacket,
 | 
			
		||||
			Contents: buf.Bytes()})
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewUserAttribute creates a new user attribute packet containing the given subpackets.
 | 
			
		||||
func NewUserAttribute(contents ...*OpaqueSubpacket) *UserAttribute {
 | 
			
		||||
	return &UserAttribute{Contents: contents}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (uat *UserAttribute) parse(r io.Reader) (err error) {
 | 
			
		||||
	// RFC 4880, section 5.13
 | 
			
		||||
	b, err := ioutil.ReadAll(r)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	uat.Contents, err = OpaqueSubpackets(b)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Serialize marshals the user attribute to w in the form of an OpenPGP packet, including
 | 
			
		||||
// header.
 | 
			
		||||
func (uat *UserAttribute) Serialize(w io.Writer) (err error) {
 | 
			
		||||
	var buf bytes.Buffer
 | 
			
		||||
	for _, sp := range uat.Contents {
 | 
			
		||||
		err = sp.Serialize(&buf)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if err = serializeHeader(w, packetTypeUserAttribute, buf.Len()); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	_, err = w.Write(buf.Bytes())
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ImageData returns zero or more byte slices, each containing
 | 
			
		||||
// JPEG File Interchange Format (JFIF), for each photo in the
 | 
			
		||||
// user attribute packet.
 | 
			
		||||
func (uat *UserAttribute) ImageData() (imageData [][]byte) {
 | 
			
		||||
	for _, sp := range uat.Contents {
 | 
			
		||||
		if sp.SubType == UserAttrImageSubpacket && len(sp.Contents) > 16 {
 | 
			
		||||
			imageData = append(imageData, sp.Contents[16:])
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										167
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/userid.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										167
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/userid.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,167 @@
 | 
			
		||||
// Copyright 2011 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package packet
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"io"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// UserId contains text that is intended to represent the name and email
 | 
			
		||||
// address of the key holder. See RFC 4880, section 5.11. By convention, this
 | 
			
		||||
// takes the form "Full Name (Comment) <email@example.com>"
 | 
			
		||||
type UserId struct {
 | 
			
		||||
	Id string // By convention, this takes the form "Full Name (Comment) <email@example.com>" which is split out in the fields below.
 | 
			
		||||
 | 
			
		||||
	Name, Comment, Email string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func hasInvalidCharacters(s string) bool {
 | 
			
		||||
	for _, c := range s {
 | 
			
		||||
		switch c {
 | 
			
		||||
		case '(', ')', '<', '>', 0:
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewUserId returns a UserId or nil if any of the arguments contain invalid
 | 
			
		||||
// characters. The invalid characters are '\x00', '(', ')', '<' and '>'
 | 
			
		||||
func NewUserId(name, comment, email string) *UserId {
 | 
			
		||||
	// RFC 4880 doesn't deal with the structure of userid strings; the
 | 
			
		||||
	// name, comment and email form is just a convention. However, there's
 | 
			
		||||
	// no convention about escaping the metacharacters and GPG just refuses
 | 
			
		||||
	// to create user ids where, say, the name contains a '('. We mirror
 | 
			
		||||
	// this behaviour.
 | 
			
		||||
 | 
			
		||||
	if hasInvalidCharacters(name) || hasInvalidCharacters(comment) || hasInvalidCharacters(email) {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uid := new(UserId)
 | 
			
		||||
	uid.Name, uid.Comment, uid.Email = name, comment, email
 | 
			
		||||
	uid.Id = name
 | 
			
		||||
	if len(comment) > 0 {
 | 
			
		||||
		if len(uid.Id) > 0 {
 | 
			
		||||
			uid.Id += " "
 | 
			
		||||
		}
 | 
			
		||||
		uid.Id += "("
 | 
			
		||||
		uid.Id += comment
 | 
			
		||||
		uid.Id += ")"
 | 
			
		||||
	}
 | 
			
		||||
	if len(email) > 0 {
 | 
			
		||||
		if len(uid.Id) > 0 {
 | 
			
		||||
			uid.Id += " "
 | 
			
		||||
		}
 | 
			
		||||
		uid.Id += "<"
 | 
			
		||||
		uid.Id += email
 | 
			
		||||
		uid.Id += ">"
 | 
			
		||||
	}
 | 
			
		||||
	return uid
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (uid *UserId) parse(r io.Reader) (err error) {
 | 
			
		||||
	// RFC 4880, section 5.11
 | 
			
		||||
	b, err := ioutil.ReadAll(r)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	uid.Id = string(b)
 | 
			
		||||
	uid.Name, uid.Comment, uid.Email = parseUserId(uid.Id)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Serialize marshals uid to w in the form of an OpenPGP packet, including
 | 
			
		||||
// header.
 | 
			
		||||
func (uid *UserId) Serialize(w io.Writer) error {
 | 
			
		||||
	err := serializeHeader(w, packetTypeUserId, len(uid.Id))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	_, err = w.Write([]byte(uid.Id))
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// parseUserId extracts the name, comment and email from a user id string that
 | 
			
		||||
// is formatted as "Full Name (Comment) <email@example.com>".
 | 
			
		||||
func parseUserId(id string) (name, comment, email string) {
 | 
			
		||||
	var n, c, e struct {
 | 
			
		||||
		start, end int
 | 
			
		||||
	}
 | 
			
		||||
	var state int
 | 
			
		||||
 | 
			
		||||
	for offset, rune := range id {
 | 
			
		||||
		switch state {
 | 
			
		||||
		case 0:
 | 
			
		||||
			// Entering name
 | 
			
		||||
			n.start = offset
 | 
			
		||||
			state = 1
 | 
			
		||||
			fallthrough
 | 
			
		||||
		case 1:
 | 
			
		||||
			// In name
 | 
			
		||||
			if rune == '(' {
 | 
			
		||||
				state = 2
 | 
			
		||||
				n.end = offset
 | 
			
		||||
			} else if rune == '<' {
 | 
			
		||||
				state = 5
 | 
			
		||||
				n.end = offset
 | 
			
		||||
			}
 | 
			
		||||
		case 2:
 | 
			
		||||
			// Entering comment
 | 
			
		||||
			c.start = offset
 | 
			
		||||
			state = 3
 | 
			
		||||
			fallthrough
 | 
			
		||||
		case 3:
 | 
			
		||||
			// In comment
 | 
			
		||||
			if rune == ')' {
 | 
			
		||||
				state = 4
 | 
			
		||||
				c.end = offset
 | 
			
		||||
			}
 | 
			
		||||
		case 4:
 | 
			
		||||
			// Between comment and email
 | 
			
		||||
			if rune == '<' {
 | 
			
		||||
				state = 5
 | 
			
		||||
			}
 | 
			
		||||
		case 5:
 | 
			
		||||
			// Entering email
 | 
			
		||||
			e.start = offset
 | 
			
		||||
			state = 6
 | 
			
		||||
			fallthrough
 | 
			
		||||
		case 6:
 | 
			
		||||
			// In email
 | 
			
		||||
			if rune == '>' {
 | 
			
		||||
				state = 7
 | 
			
		||||
				e.end = offset
 | 
			
		||||
			}
 | 
			
		||||
		default:
 | 
			
		||||
			// After email
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	switch state {
 | 
			
		||||
	case 1:
 | 
			
		||||
		// ended in the name
 | 
			
		||||
		n.end = len(id)
 | 
			
		||||
	case 3:
 | 
			
		||||
		// ended in comment
 | 
			
		||||
		c.end = len(id)
 | 
			
		||||
	case 6:
 | 
			
		||||
		// ended in email
 | 
			
		||||
		e.end = len(id)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	name = strings.TrimSpace(id[n.start:n.end])
 | 
			
		||||
	comment = strings.TrimSpace(id[c.start:c.end])
 | 
			
		||||
	email = strings.TrimSpace(id[e.start:e.end])
 | 
			
		||||
 | 
			
		||||
	// RFC 2822 3.4: alternate simple form of a mailbox
 | 
			
		||||
	if email == "" && strings.ContainsRune(name, '@') {
 | 
			
		||||
		email = name
 | 
			
		||||
		name = ""
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										532
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/read.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										532
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/read.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,532 @@
 | 
			
		||||
// Copyright 2011 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
// Package openpgp implements high level operations on OpenPGP messages.
 | 
			
		||||
package openpgp // import "github.com/ProtonMail/go-crypto/openpgp"
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto"
 | 
			
		||||
	_ "crypto/sha256"
 | 
			
		||||
	"hash"
 | 
			
		||||
	"io"
 | 
			
		||||
	"strconv"
 | 
			
		||||
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/openpgp/armor"
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/openpgp/errors"
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/openpgp/packet"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// SignatureType is the armor type for a PGP signature.
 | 
			
		||||
var SignatureType = "PGP SIGNATURE"
 | 
			
		||||
 | 
			
		||||
// readArmored reads an armored block with the given type.
 | 
			
		||||
func readArmored(r io.Reader, expectedType string) (body io.Reader, err error) {
 | 
			
		||||
	block, err := armor.Decode(r)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if block.Type != expectedType {
 | 
			
		||||
		return nil, errors.InvalidArgumentError("expected '" + expectedType + "', got: " + block.Type)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return block.Body, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MessageDetails contains the result of parsing an OpenPGP encrypted and/or
 | 
			
		||||
// signed message.
 | 
			
		||||
type MessageDetails struct {
 | 
			
		||||
	IsEncrypted              bool                // true if the message was encrypted.
 | 
			
		||||
	EncryptedToKeyIds        []uint64            // the list of recipient key ids.
 | 
			
		||||
	IsSymmetricallyEncrypted bool                // true if a passphrase could have decrypted the message.
 | 
			
		||||
	DecryptedWith            Key                 // the private key used to decrypt the message, if any.
 | 
			
		||||
	IsSigned                 bool                // true if the message is signed.
 | 
			
		||||
	SignedByKeyId            uint64              // the key id of the signer, if any.
 | 
			
		||||
	SignedBy                 *Key                // the key of the signer, if available.
 | 
			
		||||
	LiteralData              *packet.LiteralData // the metadata of the contents
 | 
			
		||||
	UnverifiedBody           io.Reader           // the contents of the message.
 | 
			
		||||
 | 
			
		||||
	// If IsSigned is true and SignedBy is non-zero then the signature will
 | 
			
		||||
	// be verified as UnverifiedBody is read. The signature cannot be
 | 
			
		||||
	// checked until the whole of UnverifiedBody is read so UnverifiedBody
 | 
			
		||||
	// must be consumed until EOF before the data can be trusted. Even if a
 | 
			
		||||
	// message isn't signed (or the signer is unknown) the data may contain
 | 
			
		||||
	// an authentication code that is only checked once UnverifiedBody has
 | 
			
		||||
	// been consumed. Once EOF has been seen, the following fields are
 | 
			
		||||
	// valid. (An authentication code failure is reported as a
 | 
			
		||||
	// SignatureError error when reading from UnverifiedBody.)
 | 
			
		||||
	Signature            *packet.Signature   // the signature packet itself.
 | 
			
		||||
	SignatureError       error               // nil if the signature is good.
 | 
			
		||||
	UnverifiedSignatures []*packet.Signature // all other unverified signature packets.
 | 
			
		||||
 | 
			
		||||
	decrypted io.ReadCloser
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A PromptFunction is used as a callback by functions that may need to decrypt
 | 
			
		||||
// a private key, or prompt for a passphrase. It is called with a list of
 | 
			
		||||
// acceptable, encrypted private keys and a boolean that indicates whether a
 | 
			
		||||
// passphrase is usable. It should either decrypt a private key or return a
 | 
			
		||||
// passphrase to try. If the decrypted private key or given passphrase isn't
 | 
			
		||||
// correct, the function will be called again, forever. Any error returned will
 | 
			
		||||
// be passed up.
 | 
			
		||||
type PromptFunction func(keys []Key, symmetric bool) ([]byte, error)
 | 
			
		||||
 | 
			
		||||
// A keyEnvelopePair is used to store a private key with the envelope that
 | 
			
		||||
// contains a symmetric key, encrypted with that key.
 | 
			
		||||
type keyEnvelopePair struct {
 | 
			
		||||
	key          Key
 | 
			
		||||
	encryptedKey *packet.EncryptedKey
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ReadMessage parses an OpenPGP message that may be signed and/or encrypted.
 | 
			
		||||
// The given KeyRing should contain both public keys (for signature
 | 
			
		||||
// verification) and, possibly encrypted, private keys for decrypting.
 | 
			
		||||
// If config is nil, sensible defaults will be used.
 | 
			
		||||
func ReadMessage(r io.Reader, keyring KeyRing, prompt PromptFunction, config *packet.Config) (md *MessageDetails, err error) {
 | 
			
		||||
	var p packet.Packet
 | 
			
		||||
 | 
			
		||||
	var symKeys []*packet.SymmetricKeyEncrypted
 | 
			
		||||
	var pubKeys []keyEnvelopePair
 | 
			
		||||
	// Integrity protected encrypted packet: SymmetricallyEncrypted or AEADEncrypted
 | 
			
		||||
	var edp packet.EncryptedDataPacket
 | 
			
		||||
 | 
			
		||||
	packets := packet.NewReader(r)
 | 
			
		||||
	md = new(MessageDetails)
 | 
			
		||||
	md.IsEncrypted = true
 | 
			
		||||
 | 
			
		||||
	// The message, if encrypted, starts with a number of packets
 | 
			
		||||
	// containing an encrypted decryption key. The decryption key is either
 | 
			
		||||
	// encrypted to a public key, or with a passphrase. This loop
 | 
			
		||||
	// collects these packets.
 | 
			
		||||
ParsePackets:
 | 
			
		||||
	for {
 | 
			
		||||
		p, err = packets.Next()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		switch p := p.(type) {
 | 
			
		||||
		case *packet.SymmetricKeyEncrypted:
 | 
			
		||||
			// This packet contains the decryption key encrypted with a passphrase.
 | 
			
		||||
			md.IsSymmetricallyEncrypted = true
 | 
			
		||||
			symKeys = append(symKeys, p)
 | 
			
		||||
		case *packet.EncryptedKey:
 | 
			
		||||
			// This packet contains the decryption key encrypted to a public key.
 | 
			
		||||
			md.EncryptedToKeyIds = append(md.EncryptedToKeyIds, p.KeyId)
 | 
			
		||||
			switch p.Algo {
 | 
			
		||||
			case packet.PubKeyAlgoRSA, packet.PubKeyAlgoRSAEncryptOnly, packet.PubKeyAlgoElGamal, packet.PubKeyAlgoECDH:
 | 
			
		||||
				break
 | 
			
		||||
			default:
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			if keyring != nil {
 | 
			
		||||
				var keys []Key
 | 
			
		||||
				if p.KeyId == 0 {
 | 
			
		||||
					keys = keyring.DecryptionKeys()
 | 
			
		||||
				} else {
 | 
			
		||||
					keys = keyring.KeysById(p.KeyId)
 | 
			
		||||
				}
 | 
			
		||||
				for _, k := range keys {
 | 
			
		||||
					pubKeys = append(pubKeys, keyEnvelopePair{k, p})
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		case *packet.SymmetricallyEncrypted, *packet.AEADEncrypted:
 | 
			
		||||
			edp = p.(packet.EncryptedDataPacket)
 | 
			
		||||
			break ParsePackets
 | 
			
		||||
		case *packet.Compressed, *packet.LiteralData, *packet.OnePassSignature:
 | 
			
		||||
			// This message isn't encrypted.
 | 
			
		||||
			if len(symKeys) != 0 || len(pubKeys) != 0 {
 | 
			
		||||
				return nil, errors.StructuralError("key material not followed by encrypted message")
 | 
			
		||||
			}
 | 
			
		||||
			packets.Unread(p)
 | 
			
		||||
			return readSignedMessage(packets, nil, keyring, config)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var candidates []Key
 | 
			
		||||
	var decrypted io.ReadCloser
 | 
			
		||||
 | 
			
		||||
	// Now that we have the list of encrypted keys we need to decrypt at
 | 
			
		||||
	// least one of them or, if we cannot, we need to call the prompt
 | 
			
		||||
	// function so that it can decrypt a key or give us a passphrase.
 | 
			
		||||
FindKey:
 | 
			
		||||
	for {
 | 
			
		||||
		// See if any of the keys already have a private key available
 | 
			
		||||
		candidates = candidates[:0]
 | 
			
		||||
		candidateFingerprints := make(map[string]bool)
 | 
			
		||||
 | 
			
		||||
		for _, pk := range pubKeys {
 | 
			
		||||
			if pk.key.PrivateKey == nil {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			if !pk.key.PrivateKey.Encrypted {
 | 
			
		||||
				if len(pk.encryptedKey.Key) == 0 {
 | 
			
		||||
					errDec := pk.encryptedKey.Decrypt(pk.key.PrivateKey, config)
 | 
			
		||||
					if errDec != nil {
 | 
			
		||||
						continue
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				// Try to decrypt symmetrically encrypted
 | 
			
		||||
				decrypted, err = edp.Decrypt(pk.encryptedKey.CipherFunc, pk.encryptedKey.Key)
 | 
			
		||||
				if err != nil && err != errors.ErrKeyIncorrect {
 | 
			
		||||
					return nil, err
 | 
			
		||||
				}
 | 
			
		||||
				if decrypted != nil {
 | 
			
		||||
					md.DecryptedWith = pk.key
 | 
			
		||||
					break FindKey
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				fpr := string(pk.key.PublicKey.Fingerprint[:])
 | 
			
		||||
				if v := candidateFingerprints[fpr]; v {
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
				candidates = append(candidates, pk.key)
 | 
			
		||||
				candidateFingerprints[fpr] = true
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if len(candidates) == 0 && len(symKeys) == 0 {
 | 
			
		||||
			return nil, errors.ErrKeyIncorrect
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if prompt == nil {
 | 
			
		||||
			return nil, errors.ErrKeyIncorrect
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		passphrase, err := prompt(candidates, len(symKeys) != 0)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Try the symmetric passphrase first
 | 
			
		||||
		if len(symKeys) != 0 && passphrase != nil {
 | 
			
		||||
			for _, s := range symKeys {
 | 
			
		||||
				key, cipherFunc, err := s.Decrypt(passphrase)
 | 
			
		||||
				// On wrong passphrase, session key decryption is very likely to result in an invalid cipherFunc:
 | 
			
		||||
				// only for < 5% of cases we will proceed to decrypt the data
 | 
			
		||||
				if err == nil {
 | 
			
		||||
					decrypted, err = edp.Decrypt(cipherFunc, key)
 | 
			
		||||
					// TODO: ErrKeyIncorrect is no longer thrown on SEIP decryption,
 | 
			
		||||
					// but it might still be relevant for when we implement AEAD decryption (otherwise, remove?)
 | 
			
		||||
					if err != nil && err != errors.ErrKeyIncorrect {
 | 
			
		||||
						return nil, err
 | 
			
		||||
					}
 | 
			
		||||
					if decrypted != nil {
 | 
			
		||||
						break FindKey
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	md.decrypted = decrypted
 | 
			
		||||
	if err := packets.Push(decrypted); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	mdFinal, sensitiveParsingErr := readSignedMessage(packets, md, keyring, config)
 | 
			
		||||
	if sensitiveParsingErr != nil {
 | 
			
		||||
		return nil, errors.StructuralError("parsing error")
 | 
			
		||||
	}
 | 
			
		||||
	return mdFinal, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// readSignedMessage reads a possibly signed message if mdin is non-zero then
 | 
			
		||||
// that structure is updated and returned. Otherwise a fresh MessageDetails is
 | 
			
		||||
// used.
 | 
			
		||||
func readSignedMessage(packets *packet.Reader, mdin *MessageDetails, keyring KeyRing, config *packet.Config) (md *MessageDetails, err error) {
 | 
			
		||||
	if mdin == nil {
 | 
			
		||||
		mdin = new(MessageDetails)
 | 
			
		||||
	}
 | 
			
		||||
	md = mdin
 | 
			
		||||
 | 
			
		||||
	var p packet.Packet
 | 
			
		||||
	var h hash.Hash
 | 
			
		||||
	var wrappedHash hash.Hash
 | 
			
		||||
	var prevLast bool
 | 
			
		||||
FindLiteralData:
 | 
			
		||||
	for {
 | 
			
		||||
		p, err = packets.Next()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		switch p := p.(type) {
 | 
			
		||||
		case *packet.Compressed:
 | 
			
		||||
			if err := packets.Push(p.Body); err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
		case *packet.OnePassSignature:
 | 
			
		||||
			if prevLast {
 | 
			
		||||
				return nil, errors.UnsupportedError("nested signature packets")
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if p.IsLast {
 | 
			
		||||
				prevLast = true
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			h, wrappedHash, err = hashForSignature(p.Hash, p.SigType)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				md.SignatureError = err
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			md.IsSigned = true
 | 
			
		||||
			md.SignedByKeyId = p.KeyId
 | 
			
		||||
			if keyring != nil {
 | 
			
		||||
				keys := keyring.KeysByIdUsage(p.KeyId, packet.KeyFlagSign)
 | 
			
		||||
				if len(keys) > 0 {
 | 
			
		||||
					md.SignedBy = &keys[0]
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		case *packet.LiteralData:
 | 
			
		||||
			md.LiteralData = p
 | 
			
		||||
			break FindLiteralData
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if md.IsSigned && md.SignatureError == nil {
 | 
			
		||||
		md.UnverifiedBody = &signatureCheckReader{packets, h, wrappedHash, md, config}
 | 
			
		||||
	} else if md.decrypted != nil {
 | 
			
		||||
		md.UnverifiedBody = checkReader{md}
 | 
			
		||||
	} else {
 | 
			
		||||
		md.UnverifiedBody = md.LiteralData.Body
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return md, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// hashForSignature returns a pair of hashes that can be used to verify a
 | 
			
		||||
// signature. The signature may specify that the contents of the signed message
 | 
			
		||||
// should be preprocessed (i.e. to normalize line endings). Thus this function
 | 
			
		||||
// returns two hashes. The second should be used to hash the message itself and
 | 
			
		||||
// performs any needed preprocessing.
 | 
			
		||||
func hashForSignature(hashId crypto.Hash, sigType packet.SignatureType) (hash.Hash, hash.Hash, error) {
 | 
			
		||||
	if hashId == crypto.MD5 {
 | 
			
		||||
		return nil, nil, errors.UnsupportedError("insecure hash algorithm: MD5")
 | 
			
		||||
	}
 | 
			
		||||
	if !hashId.Available() {
 | 
			
		||||
		return nil, nil, errors.UnsupportedError("hash not available: " + strconv.Itoa(int(hashId)))
 | 
			
		||||
	}
 | 
			
		||||
	h := hashId.New()
 | 
			
		||||
 | 
			
		||||
	switch sigType {
 | 
			
		||||
	case packet.SigTypeBinary:
 | 
			
		||||
		return h, h, nil
 | 
			
		||||
	case packet.SigTypeText:
 | 
			
		||||
		return h, NewCanonicalTextHash(h), nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil, nil, errors.UnsupportedError("unsupported signature type: " + strconv.Itoa(int(sigType)))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// checkReader wraps an io.Reader from a LiteralData packet. When it sees EOF
 | 
			
		||||
// it closes the ReadCloser from any SymmetricallyEncrypted packet to trigger
 | 
			
		||||
// MDC checks.
 | 
			
		||||
type checkReader struct {
 | 
			
		||||
	md *MessageDetails
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (cr checkReader) Read(buf []byte) (int, error) {
 | 
			
		||||
	n, sensitiveParsingError := cr.md.LiteralData.Body.Read(buf)
 | 
			
		||||
	if sensitiveParsingError == io.EOF {
 | 
			
		||||
		mdcErr := cr.md.decrypted.Close()
 | 
			
		||||
		if mdcErr != nil {
 | 
			
		||||
			return n, mdcErr
 | 
			
		||||
		}
 | 
			
		||||
		return n, io.EOF
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if sensitiveParsingError != nil {
 | 
			
		||||
		return n, errors.StructuralError("parsing error")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return n, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// signatureCheckReader wraps an io.Reader from a LiteralData packet and hashes
 | 
			
		||||
// the data as it is read. When it sees an EOF from the underlying io.Reader
 | 
			
		||||
// it parses and checks a trailing Signature packet and triggers any MDC checks.
 | 
			
		||||
type signatureCheckReader struct {
 | 
			
		||||
	packets        *packet.Reader
 | 
			
		||||
	h, wrappedHash hash.Hash
 | 
			
		||||
	md             *MessageDetails
 | 
			
		||||
	config         *packet.Config
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (scr *signatureCheckReader) Read(buf []byte) (int, error) {
 | 
			
		||||
	n, sensitiveParsingError := scr.md.LiteralData.Body.Read(buf)
 | 
			
		||||
 | 
			
		||||
	// Hash only if required
 | 
			
		||||
	if scr.md.SignedBy != nil {
 | 
			
		||||
		scr.wrappedHash.Write(buf[:n])
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if sensitiveParsingError == io.EOF {
 | 
			
		||||
		var p packet.Packet
 | 
			
		||||
		var readError error
 | 
			
		||||
		var sig *packet.Signature
 | 
			
		||||
 | 
			
		||||
		p, readError = scr.packets.Next()
 | 
			
		||||
		for readError == nil {
 | 
			
		||||
			var ok bool
 | 
			
		||||
			if sig, ok = p.(*packet.Signature); ok {
 | 
			
		||||
				if sig.Version == 5 && (sig.SigType == 0x00 || sig.SigType == 0x01) {
 | 
			
		||||
					sig.Metadata = scr.md.LiteralData
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				// If signature KeyID matches
 | 
			
		||||
				if scr.md.SignedBy != nil && *sig.IssuerKeyId == scr.md.SignedByKeyId {
 | 
			
		||||
					key := scr.md.SignedBy
 | 
			
		||||
					signatureError := key.PublicKey.VerifySignature(scr.h, sig)
 | 
			
		||||
					if signatureError == nil {
 | 
			
		||||
						now := scr.config.Now()
 | 
			
		||||
						if key.Revoked(now) ||
 | 
			
		||||
							key.Entity.Revoked(now) || // primary key is revoked (redundant if key is the primary key)
 | 
			
		||||
							key.Entity.PrimaryIdentity().Revoked(now) {
 | 
			
		||||
							signatureError = errors.ErrKeyRevoked
 | 
			
		||||
						}
 | 
			
		||||
						if sig.SigExpired(now) {
 | 
			
		||||
							signatureError = errors.ErrSignatureExpired
 | 
			
		||||
						}
 | 
			
		||||
						if key.PublicKey.KeyExpired(key.SelfSignature, now) ||
 | 
			
		||||
							key.SelfSignature.SigExpired(now) {
 | 
			
		||||
							signatureError = errors.ErrKeyExpired
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
					scr.md.Signature = sig
 | 
			
		||||
					scr.md.SignatureError = signatureError
 | 
			
		||||
				} else {
 | 
			
		||||
					scr.md.UnverifiedSignatures = append(scr.md.UnverifiedSignatures, sig)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			p, readError = scr.packets.Next()
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if scr.md.SignedBy != nil && scr.md.Signature == nil {
 | 
			
		||||
			if scr.md.UnverifiedSignatures == nil {
 | 
			
		||||
				scr.md.SignatureError = errors.StructuralError("LiteralData not followed by signature")
 | 
			
		||||
			} else {
 | 
			
		||||
				scr.md.SignatureError = errors.StructuralError("No matching signature found")
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// The SymmetricallyEncrypted packet, if any, might have an
 | 
			
		||||
		// unsigned hash of its own. In order to check this we need to
 | 
			
		||||
		// close that Reader.
 | 
			
		||||
		if scr.md.decrypted != nil {
 | 
			
		||||
			mdcErr := scr.md.decrypted.Close()
 | 
			
		||||
			if mdcErr != nil {
 | 
			
		||||
				return n, mdcErr
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return n, io.EOF
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if sensitiveParsingError != nil {
 | 
			
		||||
		return n, errors.StructuralError("parsing error")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return n, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CheckDetachedSignature takes a signed file and a detached signature and
 | 
			
		||||
// returns the signer if the signature is valid. If the signer isn't known,
 | 
			
		||||
// ErrUnknownIssuer is returned.
 | 
			
		||||
func CheckDetachedSignature(keyring KeyRing, signed, signature io.Reader, config *packet.Config) (signer *Entity, err error) {
 | 
			
		||||
	var expectedHashes []crypto.Hash
 | 
			
		||||
	return CheckDetachedSignatureAndHash(keyring, signed, signature, expectedHashes, config)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CheckDetachedSignatureAndHash performs the same actions as
 | 
			
		||||
// CheckDetachedSignature and checks that the expected hash functions were used.
 | 
			
		||||
func CheckDetachedSignatureAndHash(keyring KeyRing, signed, signature io.Reader, expectedHashes []crypto.Hash, config *packet.Config) (signer *Entity, err error) {
 | 
			
		||||
	var issuerKeyId uint64
 | 
			
		||||
	var hashFunc crypto.Hash
 | 
			
		||||
	var sigType packet.SignatureType
 | 
			
		||||
	var keys []Key
 | 
			
		||||
	var p packet.Packet
 | 
			
		||||
 | 
			
		||||
	expectedHashesLen := len(expectedHashes)
 | 
			
		||||
	packets := packet.NewReader(signature)
 | 
			
		||||
	var sig *packet.Signature
 | 
			
		||||
	for {
 | 
			
		||||
		p, err = packets.Next()
 | 
			
		||||
		if err == io.EOF {
 | 
			
		||||
			return nil, errors.ErrUnknownIssuer
 | 
			
		||||
		}
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		var ok bool
 | 
			
		||||
		sig, ok = p.(*packet.Signature)
 | 
			
		||||
		if !ok {
 | 
			
		||||
			return nil, errors.StructuralError("non signature packet found")
 | 
			
		||||
		}
 | 
			
		||||
		if sig.IssuerKeyId == nil {
 | 
			
		||||
			return nil, errors.StructuralError("signature doesn't have an issuer")
 | 
			
		||||
		}
 | 
			
		||||
		issuerKeyId = *sig.IssuerKeyId
 | 
			
		||||
		hashFunc = sig.Hash
 | 
			
		||||
		sigType = sig.SigType
 | 
			
		||||
 | 
			
		||||
		for i, expectedHash := range expectedHashes {
 | 
			
		||||
			if hashFunc == expectedHash {
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
			if i+1 == expectedHashesLen {
 | 
			
		||||
				return nil, errors.StructuralError("hash algorithm mismatch with cleartext message headers")
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		keys = keyring.KeysByIdUsage(issuerKeyId, packet.KeyFlagSign)
 | 
			
		||||
		if len(keys) > 0 {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(keys) == 0 {
 | 
			
		||||
		panic("unreachable")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	h, wrappedHash, err := hashForSignature(hashFunc, sigType)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if _, err := io.Copy(wrappedHash, signed); err != nil && err != io.EOF {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, key := range keys {
 | 
			
		||||
		err = key.PublicKey.VerifySignature(h, sig)
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			now := config.Now()
 | 
			
		||||
			if key.Revoked(now) ||
 | 
			
		||||
				key.Entity.Revoked(now) || // primary key is revoked (redundant if key is the primary key)
 | 
			
		||||
				key.Entity.PrimaryIdentity().Revoked(now) {
 | 
			
		||||
				return key.Entity, errors.ErrKeyRevoked
 | 
			
		||||
			}
 | 
			
		||||
			if sig.SigExpired(now) {
 | 
			
		||||
				return key.Entity, errors.ErrSignatureExpired
 | 
			
		||||
			}
 | 
			
		||||
			if key.PublicKey.KeyExpired(key.SelfSignature, now) ||
 | 
			
		||||
				key.SelfSignature.SigExpired(now) {
 | 
			
		||||
				return key.Entity, errors.ErrKeyExpired
 | 
			
		||||
			}
 | 
			
		||||
			return key.Entity, nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CheckArmoredDetachedSignature performs the same actions as
 | 
			
		||||
// CheckDetachedSignature but expects the signature to be armored.
 | 
			
		||||
func CheckArmoredDetachedSignature(keyring KeyRing, signed, signature io.Reader, config *packet.Config) (signer *Entity, err error) {
 | 
			
		||||
	body, err := readArmored(signature, SignatureType)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return CheckDetachedSignature(keyring, signed, body, config)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										173
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/read_write_test_data.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										173
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/read_write_test_data.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										367
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/s2k/s2k.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										367
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/s2k/s2k.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,367 @@
 | 
			
		||||
// Copyright 2011 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
// Package s2k implements the various OpenPGP string-to-key transforms as
 | 
			
		||||
// specified in RFC 4800 section 3.7.1.
 | 
			
		||||
package s2k // import "github.com/ProtonMail/go-crypto/openpgp/s2k"
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto"
 | 
			
		||||
	"hash"
 | 
			
		||||
	"io"
 | 
			
		||||
	"strconv"
 | 
			
		||||
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/openpgp/errors"
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/openpgp/internal/algorithm"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Config collects configuration parameters for s2k key-stretching
 | 
			
		||||
// transformations. A nil *Config is valid and results in all default
 | 
			
		||||
// values. Currently, Config is used only by the Serialize function in
 | 
			
		||||
// this package.
 | 
			
		||||
type Config struct {
 | 
			
		||||
	// S2KMode is the mode of s2k function.
 | 
			
		||||
	// It can be 0 (simple), 1(salted), 3(iterated)
 | 
			
		||||
	// 2(reserved) 100-110(private/experimental).
 | 
			
		||||
	S2KMode uint8
 | 
			
		||||
	// Hash is the default hash function to be used. If
 | 
			
		||||
	// nil, SHA256 is used.
 | 
			
		||||
	Hash crypto.Hash
 | 
			
		||||
	// S2KCount is only used for symmetric encryption. It
 | 
			
		||||
	// determines the strength of the passphrase stretching when
 | 
			
		||||
	// the said passphrase is hashed to produce a key. S2KCount
 | 
			
		||||
	// should be between 65536 and 65011712, inclusive. If Config
 | 
			
		||||
	// is nil or S2KCount is 0, the value 16777216 used. Not all
 | 
			
		||||
	// values in the above range can be represented. S2KCount will
 | 
			
		||||
	// be rounded up to the next representable value if it cannot
 | 
			
		||||
	// be encoded exactly. See RFC 4880 Section 3.7.1.3.
 | 
			
		||||
	S2KCount int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Params contains all the parameters of the s2k packet
 | 
			
		||||
type Params struct {
 | 
			
		||||
	// mode is the mode of s2k function.
 | 
			
		||||
	// It can be 0 (simple), 1(salted), 3(iterated)
 | 
			
		||||
	// 2(reserved) 100-110(private/experimental).
 | 
			
		||||
	mode uint8
 | 
			
		||||
	// hashId is the ID of the hash function used in any of the modes
 | 
			
		||||
	hashId byte
 | 
			
		||||
	// salt is a byte array to use as a salt in hashing process
 | 
			
		||||
	salt []byte
 | 
			
		||||
	// countByte is used to determine how many rounds of hashing are to
 | 
			
		||||
	// be performed in s2k mode 3. See RFC 4880 Section 3.7.1.3.
 | 
			
		||||
	countByte byte
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Config) hash() crypto.Hash {
 | 
			
		||||
	if c == nil || uint(c.Hash) == 0 {
 | 
			
		||||
		return crypto.SHA256
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return c.Hash
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// EncodedCount get encoded count
 | 
			
		||||
func (c *Config) EncodedCount() uint8 {
 | 
			
		||||
	if c == nil || c.S2KCount == 0 {
 | 
			
		||||
		return 224 // The common case. Corresponding to 16777216
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	i := c.S2KCount
 | 
			
		||||
 | 
			
		||||
	switch {
 | 
			
		||||
	case i < 65536:
 | 
			
		||||
		i = 65536
 | 
			
		||||
	case i > 65011712:
 | 
			
		||||
		i = 65011712
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return encodeCount(i)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// encodeCount converts an iterative "count" in the range 1024 to
 | 
			
		||||
// 65011712, inclusive, to an encoded count. The return value is the
 | 
			
		||||
// octet that is actually stored in the GPG file. encodeCount panics
 | 
			
		||||
// if i is not in the above range (encodedCount above takes care to
 | 
			
		||||
// pass i in the correct range). See RFC 4880 Section 3.7.7.1.
 | 
			
		||||
func encodeCount(i int) uint8 {
 | 
			
		||||
	if i < 65536 || i > 65011712 {
 | 
			
		||||
		panic("count arg i outside the required range")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for encoded := 96; encoded < 256; encoded++ {
 | 
			
		||||
		count := decodeCount(uint8(encoded))
 | 
			
		||||
		if count >= i {
 | 
			
		||||
			return uint8(encoded)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 255
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// decodeCount returns the s2k mode 3 iterative "count" corresponding to
 | 
			
		||||
// the encoded octet c.
 | 
			
		||||
func decodeCount(c uint8) int {
 | 
			
		||||
	return (16 + int(c&15)) << (uint32(c>>4) + 6)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Simple writes to out the result of computing the Simple S2K function (RFC
 | 
			
		||||
// 4880, section 3.7.1.1) using the given hash and input passphrase.
 | 
			
		||||
func Simple(out []byte, h hash.Hash, in []byte) {
 | 
			
		||||
	Salted(out, h, in, nil)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var zero [1]byte
 | 
			
		||||
 | 
			
		||||
// Salted writes to out the result of computing the Salted S2K function (RFC
 | 
			
		||||
// 4880, section 3.7.1.2) using the given hash, input passphrase and salt.
 | 
			
		||||
func Salted(out []byte, h hash.Hash, in []byte, salt []byte) {
 | 
			
		||||
	done := 0
 | 
			
		||||
	var digest []byte
 | 
			
		||||
 | 
			
		||||
	for i := 0; done < len(out); i++ {
 | 
			
		||||
		h.Reset()
 | 
			
		||||
		for j := 0; j < i; j++ {
 | 
			
		||||
			h.Write(zero[:])
 | 
			
		||||
		}
 | 
			
		||||
		h.Write(salt)
 | 
			
		||||
		h.Write(in)
 | 
			
		||||
		digest = h.Sum(digest[:0])
 | 
			
		||||
		n := copy(out[done:], digest)
 | 
			
		||||
		done += n
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Iterated writes to out the result of computing the Iterated and Salted S2K
 | 
			
		||||
// function (RFC 4880, section 3.7.1.3) using the given hash, input passphrase,
 | 
			
		||||
// salt and iteration count.
 | 
			
		||||
func Iterated(out []byte, h hash.Hash, in []byte, salt []byte, count int) {
 | 
			
		||||
	combined := make([]byte, len(in)+len(salt))
 | 
			
		||||
	copy(combined, salt)
 | 
			
		||||
	copy(combined[len(salt):], in)
 | 
			
		||||
 | 
			
		||||
	if count < len(combined) {
 | 
			
		||||
		count = len(combined)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	done := 0
 | 
			
		||||
	var digest []byte
 | 
			
		||||
	for i := 0; done < len(out); i++ {
 | 
			
		||||
		h.Reset()
 | 
			
		||||
		for j := 0; j < i; j++ {
 | 
			
		||||
			h.Write(zero[:])
 | 
			
		||||
		}
 | 
			
		||||
		written := 0
 | 
			
		||||
		for written < count {
 | 
			
		||||
			if written+len(combined) > count {
 | 
			
		||||
				todo := count - written
 | 
			
		||||
				h.Write(combined[:todo])
 | 
			
		||||
				written = count
 | 
			
		||||
			} else {
 | 
			
		||||
				h.Write(combined)
 | 
			
		||||
				written += len(combined)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		digest = h.Sum(digest[:0])
 | 
			
		||||
		n := copy(out[done:], digest)
 | 
			
		||||
		done += n
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Generate generates valid parameters from given configuration.
 | 
			
		||||
// It will enforce salted + hashed s2k method
 | 
			
		||||
func Generate(rand io.Reader, c *Config) (*Params, error) {
 | 
			
		||||
	hashId, ok := HashToHashId(c.Hash)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return nil, errors.UnsupportedError("no such hash")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	params := &Params{
 | 
			
		||||
		mode:      3, // Enforce iterared + salted method
 | 
			
		||||
		hashId:    hashId,
 | 
			
		||||
		salt:      make([]byte, 8),
 | 
			
		||||
		countByte: c.EncodedCount(),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if _, err := io.ReadFull(rand, params.salt); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return params, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Parse reads a binary specification for a string-to-key transformation from r
 | 
			
		||||
// and returns a function which performs that transform. If the S2K is a special
 | 
			
		||||
// GNU extension that indicates that the private key is missing, then the error
 | 
			
		||||
// returned is errors.ErrDummyPrivateKey.
 | 
			
		||||
func Parse(r io.Reader) (f func(out, in []byte), err error) {
 | 
			
		||||
	params, err := ParseIntoParams(r)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return params.Function()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ParseIntoParams reads a binary specification for a string-to-key
 | 
			
		||||
// transformation from r and returns a struct describing the s2k parameters.
 | 
			
		||||
func ParseIntoParams(r io.Reader) (params *Params, err error) {
 | 
			
		||||
	var buf [9]byte
 | 
			
		||||
 | 
			
		||||
	_, err = io.ReadFull(r, buf[:2])
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	params = &Params{
 | 
			
		||||
		mode:   buf[0],
 | 
			
		||||
		hashId: buf[1],
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch params.mode {
 | 
			
		||||
	case 0:
 | 
			
		||||
		return params, nil
 | 
			
		||||
	case 1:
 | 
			
		||||
		_, err = io.ReadFull(r, buf[:8])
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		params.salt = buf[:8]
 | 
			
		||||
		return params, nil
 | 
			
		||||
	case 3:
 | 
			
		||||
		_, err = io.ReadFull(r, buf[:9])
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		params.salt = buf[:8]
 | 
			
		||||
		params.countByte = buf[8]
 | 
			
		||||
		return params, nil
 | 
			
		||||
	case 101:
 | 
			
		||||
		// This is a GNU extension. See
 | 
			
		||||
		// https://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=blob;f=doc/DETAILS;h=fe55ae16ab4e26d8356dc574c9e8bc935e71aef1;hb=23191d7851eae2217ecdac6484349849a24fd94a#l1109
 | 
			
		||||
		if _, err = io.ReadFull(r, buf[:4]); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		if buf[0] == 'G' && buf[1] == 'N' && buf[2] == 'U' && buf[3] == 1 {
 | 
			
		||||
			return params, nil
 | 
			
		||||
		}
 | 
			
		||||
		return nil, errors.UnsupportedError("GNU S2K extension")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil, errors.UnsupportedError("S2K function")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (params *Params) Dummy() bool {
 | 
			
		||||
	return params != nil && params.mode == 101
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (params *Params) Function() (f func(out, in []byte), err error) {
 | 
			
		||||
	if params.Dummy() {
 | 
			
		||||
		return nil, errors.ErrDummyPrivateKey("dummy key found")
 | 
			
		||||
	}
 | 
			
		||||
	hashObj, ok := HashIdToHash(params.hashId)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return nil, errors.UnsupportedError("hash for S2K function: " + strconv.Itoa(int(params.hashId)))
 | 
			
		||||
	}
 | 
			
		||||
	if !hashObj.Available() {
 | 
			
		||||
		return nil, errors.UnsupportedError("hash not available: " + strconv.Itoa(int(hashObj)))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch params.mode {
 | 
			
		||||
	case 0:
 | 
			
		||||
		f := func(out, in []byte) {
 | 
			
		||||
			Simple(out, hashObj.New(), in)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return f, nil
 | 
			
		||||
	case 1:
 | 
			
		||||
		f := func(out, in []byte) {
 | 
			
		||||
			Salted(out, hashObj.New(), in, params.salt)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return f, nil
 | 
			
		||||
	case 3:
 | 
			
		||||
		f := func(out, in []byte) {
 | 
			
		||||
			Iterated(out, hashObj.New(), in, params.salt, decodeCount(params.countByte))
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return f, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil, errors.UnsupportedError("S2K function")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (params *Params) Serialize(w io.Writer) (err error) {
 | 
			
		||||
	if _, err = w.Write([]byte{params.mode}); err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if _, err = w.Write([]byte{params.hashId}); err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if params.Dummy() {
 | 
			
		||||
		_, err = w.Write(append([]byte("GNU"), 1))
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if params.mode > 0 {
 | 
			
		||||
		if _, err = w.Write(params.salt); err != nil {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		if params.mode == 3 {
 | 
			
		||||
			_, err = w.Write([]byte{params.countByte})
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Serialize salts and stretches the given passphrase and writes the
 | 
			
		||||
// resulting key into key. It also serializes an S2K descriptor to
 | 
			
		||||
// w. The key stretching can be configured with c, which may be
 | 
			
		||||
// nil. In that case, sensible defaults will be used.
 | 
			
		||||
func Serialize(w io.Writer, key []byte, rand io.Reader, passphrase []byte, c *Config) error {
 | 
			
		||||
	params, err := Generate(rand, c)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	err = params.Serialize(w)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	f, err := params.Function()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	f(key, passphrase)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// HashIdToHash returns a crypto.Hash which corresponds to the given OpenPGP
 | 
			
		||||
// hash id.
 | 
			
		||||
func HashIdToHash(id byte) (h crypto.Hash, ok bool) {
 | 
			
		||||
	if hash, ok := algorithm.HashById[id]; ok {
 | 
			
		||||
		return hash.HashFunc(), true
 | 
			
		||||
	}
 | 
			
		||||
	return 0, false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// HashIdToString returns the name of the hash function corresponding to the
 | 
			
		||||
// given OpenPGP hash id.
 | 
			
		||||
func HashIdToString(id byte) (name string, ok bool) {
 | 
			
		||||
	if hash, ok := algorithm.HashById[id]; ok {
 | 
			
		||||
		return hash.String(), true
 | 
			
		||||
	}
 | 
			
		||||
	return "", false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// HashIdToHash returns an OpenPGP hash id which corresponds the given Hash.
 | 
			
		||||
func HashToHashId(h crypto.Hash) (id byte, ok bool) {
 | 
			
		||||
	for id, hash := range algorithm.HashById {
 | 
			
		||||
		if hash.HashFunc() == h {
 | 
			
		||||
			return id, true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return 0, false
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										568
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/write.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										568
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/write.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,568 @@
 | 
			
		||||
// Copyright 2011 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package openpgp
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto"
 | 
			
		||||
	"hash"
 | 
			
		||||
	"io"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/openpgp/armor"
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/openpgp/errors"
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/openpgp/packet"
 | 
			
		||||
	"github.com/ProtonMail/go-crypto/openpgp/s2k"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// DetachSign signs message with the private key from signer (which must
 | 
			
		||||
// already have been decrypted) and writes the signature to w.
 | 
			
		||||
// If config is nil, sensible defaults will be used.
 | 
			
		||||
func DetachSign(w io.Writer, signer *Entity, message io.Reader, config *packet.Config) error {
 | 
			
		||||
	return detachSign(w, signer, message, packet.SigTypeBinary, config)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ArmoredDetachSign signs message with the private key from signer (which
 | 
			
		||||
// must already have been decrypted) and writes an armored signature to w.
 | 
			
		||||
// If config is nil, sensible defaults will be used.
 | 
			
		||||
func ArmoredDetachSign(w io.Writer, signer *Entity, message io.Reader, config *packet.Config) (err error) {
 | 
			
		||||
	return armoredDetachSign(w, signer, message, packet.SigTypeBinary, config)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DetachSignText signs message (after canonicalising the line endings) with
 | 
			
		||||
// the private key from signer (which must already have been decrypted) and
 | 
			
		||||
// writes the signature to w.
 | 
			
		||||
// If config is nil, sensible defaults will be used.
 | 
			
		||||
func DetachSignText(w io.Writer, signer *Entity, message io.Reader, config *packet.Config) error {
 | 
			
		||||
	return detachSign(w, signer, message, packet.SigTypeText, config)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ArmoredDetachSignText signs message (after canonicalising the line endings)
 | 
			
		||||
// with the private key from signer (which must already have been decrypted)
 | 
			
		||||
// and writes an armored signature to w.
 | 
			
		||||
// If config is nil, sensible defaults will be used.
 | 
			
		||||
func ArmoredDetachSignText(w io.Writer, signer *Entity, message io.Reader, config *packet.Config) error {
 | 
			
		||||
	return armoredDetachSign(w, signer, message, packet.SigTypeText, config)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func armoredDetachSign(w io.Writer, signer *Entity, message io.Reader, sigType packet.SignatureType, config *packet.Config) (err error) {
 | 
			
		||||
	out, err := armor.Encode(w, SignatureType, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	err = detachSign(out, signer, message, sigType, config)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	return out.Close()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func detachSign(w io.Writer, signer *Entity, message io.Reader, sigType packet.SignatureType, config *packet.Config) (err error) {
 | 
			
		||||
	signingKey, ok := signer.SigningKeyById(config.Now(), config.SigningKey())
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return errors.InvalidArgumentError("no valid signing keys")
 | 
			
		||||
	}
 | 
			
		||||
	if signingKey.PrivateKey == nil {
 | 
			
		||||
		return errors.InvalidArgumentError("signing key doesn't have a private key")
 | 
			
		||||
	}
 | 
			
		||||
	if signingKey.PrivateKey.Encrypted {
 | 
			
		||||
		return errors.InvalidArgumentError("signing key is encrypted")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sig := new(packet.Signature)
 | 
			
		||||
	sig.SigType = sigType
 | 
			
		||||
	sig.PubKeyAlgo = signingKey.PrivateKey.PubKeyAlgo
 | 
			
		||||
	sig.Hash = config.Hash()
 | 
			
		||||
	sig.CreationTime = config.Now()
 | 
			
		||||
	sigLifetimeSecs := config.SigLifetime()
 | 
			
		||||
	sig.SigLifetimeSecs = &sigLifetimeSecs
 | 
			
		||||
	sig.IssuerKeyId = &signingKey.PrivateKey.KeyId
 | 
			
		||||
 | 
			
		||||
	h, wrappedHash, err := hashForSignature(sig.Hash, sig.SigType)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if _, err = io.Copy(wrappedHash, message); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = sig.Sign(h, signingKey.PrivateKey, config)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return sig.Serialize(w)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FileHints contains metadata about encrypted files. This metadata is, itself,
 | 
			
		||||
// encrypted.
 | 
			
		||||
type FileHints struct {
 | 
			
		||||
	// IsBinary can be set to hint that the contents are binary data.
 | 
			
		||||
	IsBinary bool
 | 
			
		||||
	// FileName hints at the name of the file that should be written. It's
 | 
			
		||||
	// truncated to 255 bytes if longer. It may be empty to suggest that the
 | 
			
		||||
	// file should not be written to disk. It may be equal to "_CONSOLE" to
 | 
			
		||||
	// suggest the data should not be written to disk.
 | 
			
		||||
	FileName string
 | 
			
		||||
	// ModTime contains the modification time of the file, or the zero time if not applicable.
 | 
			
		||||
	ModTime time.Time
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SymmetricallyEncrypt acts like gpg -c: it encrypts a file with a passphrase.
 | 
			
		||||
// The resulting WriteCloser must be closed after the contents of the file have
 | 
			
		||||
// been written.
 | 
			
		||||
// If config is nil, sensible defaults will be used.
 | 
			
		||||
func SymmetricallyEncrypt(ciphertext io.Writer, passphrase []byte, hints *FileHints, config *packet.Config) (plaintext io.WriteCloser, err error) {
 | 
			
		||||
	if hints == nil {
 | 
			
		||||
		hints = &FileHints{}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	key, err := packet.SerializeSymmetricKeyEncrypted(ciphertext, passphrase, config)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var w io.WriteCloser
 | 
			
		||||
	if config.AEAD() != nil {
 | 
			
		||||
		w, err = packet.SerializeAEADEncrypted(ciphertext, key, config.Cipher(), config.AEAD().Mode(), config)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		w, err = packet.SerializeSymmetricallyEncrypted(ciphertext, config.Cipher(), key, config)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	literalData := w
 | 
			
		||||
	if algo := config.Compression(); algo != packet.CompressionNone {
 | 
			
		||||
		var compConfig *packet.CompressionConfig
 | 
			
		||||
		if config != nil {
 | 
			
		||||
			compConfig = config.CompressionConfig
 | 
			
		||||
		}
 | 
			
		||||
		literalData, err = packet.SerializeCompressed(w, algo, compConfig)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var epochSeconds uint32
 | 
			
		||||
	if !hints.ModTime.IsZero() {
 | 
			
		||||
		epochSeconds = uint32(hints.ModTime.Unix())
 | 
			
		||||
	}
 | 
			
		||||
	return packet.SerializeLiteral(literalData, hints.IsBinary, hints.FileName, epochSeconds)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// intersectPreferences mutates and returns a prefix of a that contains only
 | 
			
		||||
// the values in the intersection of a and b. The order of a is preserved.
 | 
			
		||||
func intersectPreferences(a []uint8, b []uint8) (intersection []uint8) {
 | 
			
		||||
	var j int
 | 
			
		||||
	for _, v := range a {
 | 
			
		||||
		for _, v2 := range b {
 | 
			
		||||
			if v == v2 {
 | 
			
		||||
				a[j] = v
 | 
			
		||||
				j++
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return a[:j]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func hashToHashId(h crypto.Hash) uint8 {
 | 
			
		||||
	v, ok := s2k.HashToHashId(h)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		panic("tried to convert unknown hash")
 | 
			
		||||
	}
 | 
			
		||||
	return v
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// EncryptText encrypts a message to a number of recipients and, optionally,
 | 
			
		||||
// signs it. Optional information is contained in 'hints', also encrypted, that
 | 
			
		||||
// aids the recipients in processing the message. The resulting WriteCloser
 | 
			
		||||
// must be closed after the contents of the file have been written. If config
 | 
			
		||||
// is nil, sensible defaults will be used. The signing is done in text mode.
 | 
			
		||||
func EncryptText(ciphertext io.Writer, to []*Entity, signed *Entity, hints *FileHints, config *packet.Config) (plaintext io.WriteCloser, err error) {
 | 
			
		||||
	return encrypt(ciphertext, ciphertext, to, signed, hints, packet.SigTypeText, config)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Encrypt encrypts a message to a number of recipients and, optionally, signs
 | 
			
		||||
// it. hints contains optional information, that is also encrypted, that aids
 | 
			
		||||
// the recipients in processing the message. The resulting WriteCloser must
 | 
			
		||||
// be closed after the contents of the file have been written.
 | 
			
		||||
// If config is nil, sensible defaults will be used.
 | 
			
		||||
func Encrypt(ciphertext io.Writer, to []*Entity, signed *Entity, hints *FileHints, config *packet.Config) (plaintext io.WriteCloser, err error) {
 | 
			
		||||
	return encrypt(ciphertext, ciphertext, to, signed, hints, packet.SigTypeBinary, config)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// EncryptSplit encrypts a message to a number of recipients and, optionally, signs
 | 
			
		||||
// it. hints contains optional information, that is also encrypted, that aids
 | 
			
		||||
// the recipients in processing the message. The resulting WriteCloser must
 | 
			
		||||
// be closed after the contents of the file have been written.
 | 
			
		||||
// If config is nil, sensible defaults will be used.
 | 
			
		||||
func EncryptSplit(keyWriter io.Writer, dataWriter io.Writer, to []*Entity, signed *Entity, hints *FileHints, config *packet.Config) (plaintext io.WriteCloser, err error) {
 | 
			
		||||
	return encrypt(keyWriter, dataWriter, to, signed, hints, packet.SigTypeBinary, config)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// EncryptTextSplit encrypts a message to a number of recipients and, optionally, signs
 | 
			
		||||
// it. hints contains optional information, that is also encrypted, that aids
 | 
			
		||||
// the recipients in processing the message. The resulting WriteCloser must
 | 
			
		||||
// be closed after the contents of the file have been written.
 | 
			
		||||
// If config is nil, sensible defaults will be used.
 | 
			
		||||
func EncryptTextSplit(keyWriter io.Writer, dataWriter io.Writer, to []*Entity, signed *Entity, hints *FileHints, config *packet.Config) (plaintext io.WriteCloser, err error) {
 | 
			
		||||
	return encrypt(keyWriter, dataWriter, to, signed, hints, packet.SigTypeText, config)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// writeAndSign writes the data as a payload package and, optionally, signs
 | 
			
		||||
// it. hints contains optional information, that is also encrypted,
 | 
			
		||||
// that aids the recipients in processing the message. The resulting
 | 
			
		||||
// WriteCloser must be closed after the contents of the file have been
 | 
			
		||||
// written. If config is nil, sensible defaults will be used.
 | 
			
		||||
func writeAndSign(payload io.WriteCloser, candidateHashes []uint8, signed *Entity, hints *FileHints, sigType packet.SignatureType, config *packet.Config) (plaintext io.WriteCloser, err error) {
 | 
			
		||||
	var signer *packet.PrivateKey
 | 
			
		||||
	if signed != nil {
 | 
			
		||||
		signKey, ok := signed.SigningKeyById(config.Now(), config.SigningKey())
 | 
			
		||||
		if !ok {
 | 
			
		||||
			return nil, errors.InvalidArgumentError("no valid signing keys")
 | 
			
		||||
		}
 | 
			
		||||
		signer = signKey.PrivateKey
 | 
			
		||||
		if signer == nil {
 | 
			
		||||
			return nil, errors.InvalidArgumentError("no private key in signing key")
 | 
			
		||||
		}
 | 
			
		||||
		if signer.Encrypted {
 | 
			
		||||
			return nil, errors.InvalidArgumentError("signing key must be decrypted")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var hash crypto.Hash
 | 
			
		||||
	for _, hashId := range candidateHashes {
 | 
			
		||||
		if h, ok := s2k.HashIdToHash(hashId); ok && h.Available() {
 | 
			
		||||
			hash = h
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// If the hash specified by config is a candidate, we'll use that.
 | 
			
		||||
	if configuredHash := config.Hash(); configuredHash.Available() {
 | 
			
		||||
		for _, hashId := range candidateHashes {
 | 
			
		||||
			if h, ok := s2k.HashIdToHash(hashId); ok && h == configuredHash {
 | 
			
		||||
				hash = h
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if hash == 0 {
 | 
			
		||||
		hashId := candidateHashes[0]
 | 
			
		||||
		name, ok := s2k.HashIdToString(hashId)
 | 
			
		||||
		if !ok {
 | 
			
		||||
			name = "#" + strconv.Itoa(int(hashId))
 | 
			
		||||
		}
 | 
			
		||||
		return nil, errors.InvalidArgumentError("cannot encrypt because no candidate hash functions are compiled in. (Wanted " + name + " in this case.)")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if signer != nil {
 | 
			
		||||
		ops := &packet.OnePassSignature{
 | 
			
		||||
			SigType:    sigType,
 | 
			
		||||
			Hash:       hash,
 | 
			
		||||
			PubKeyAlgo: signer.PubKeyAlgo,
 | 
			
		||||
			KeyId:      signer.KeyId,
 | 
			
		||||
			IsLast:     true,
 | 
			
		||||
		}
 | 
			
		||||
		if err := ops.Serialize(payload); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if hints == nil {
 | 
			
		||||
		hints = &FileHints{}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	w := payload
 | 
			
		||||
	if signer != nil {
 | 
			
		||||
		// If we need to write a signature packet after the literal
 | 
			
		||||
		// data then we need to stop literalData from closing
 | 
			
		||||
		// encryptedData.
 | 
			
		||||
		w = noOpCloser{w}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
	var epochSeconds uint32
 | 
			
		||||
	if !hints.ModTime.IsZero() {
 | 
			
		||||
		epochSeconds = uint32(hints.ModTime.Unix())
 | 
			
		||||
	}
 | 
			
		||||
	literalData, err := packet.SerializeLiteral(w, hints.IsBinary, hints.FileName, epochSeconds)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if signer != nil {
 | 
			
		||||
		h, wrappedHash, err := hashForSignature(hash, sigType)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		metadata := &packet.LiteralData{
 | 
			
		||||
			Format:   't',
 | 
			
		||||
			FileName: hints.FileName,
 | 
			
		||||
			Time:     epochSeconds,
 | 
			
		||||
		}
 | 
			
		||||
		if hints.IsBinary {
 | 
			
		||||
			metadata.Format = 'b'
 | 
			
		||||
		}
 | 
			
		||||
		return signatureWriter{payload, literalData, hash, wrappedHash, h, signer, sigType, config, metadata}, nil
 | 
			
		||||
	}
 | 
			
		||||
	return literalData, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// encrypt encrypts a message to a number of recipients and, optionally, signs
 | 
			
		||||
// it. hints contains optional information, that is also encrypted, that aids
 | 
			
		||||
// the recipients in processing the message. The resulting WriteCloser must
 | 
			
		||||
// be closed after the contents of the file have been written.
 | 
			
		||||
// If config is nil, sensible defaults will be used.
 | 
			
		||||
func encrypt(keyWriter io.Writer, dataWriter io.Writer, to []*Entity, signed *Entity, hints *FileHints, sigType packet.SignatureType, config *packet.Config) (plaintext io.WriteCloser, err error) {
 | 
			
		||||
	if len(to) == 0 {
 | 
			
		||||
		return nil, errors.InvalidArgumentError("no encryption recipient provided")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// These are the possible ciphers that we'll use for the message.
 | 
			
		||||
	candidateCiphers := []uint8{
 | 
			
		||||
		uint8(packet.CipherAES128),
 | 
			
		||||
		uint8(packet.CipherAES256),
 | 
			
		||||
		uint8(packet.CipherCAST5),
 | 
			
		||||
	}
 | 
			
		||||
	// These are the possible hash functions that we'll use for the signature.
 | 
			
		||||
	candidateHashes := []uint8{
 | 
			
		||||
		hashToHashId(crypto.SHA256),
 | 
			
		||||
		hashToHashId(crypto.SHA384),
 | 
			
		||||
		hashToHashId(crypto.SHA512),
 | 
			
		||||
		hashToHashId(crypto.SHA1),
 | 
			
		||||
		hashToHashId(crypto.RIPEMD160),
 | 
			
		||||
	}
 | 
			
		||||
	candidateAeadModes := []uint8{
 | 
			
		||||
		uint8(packet.AEADModeEAX),
 | 
			
		||||
		uint8(packet.AEADModeOCB),
 | 
			
		||||
		uint8(packet.AEADModeExperimentalGCM),
 | 
			
		||||
	}
 | 
			
		||||
	candidateCompression := []uint8{
 | 
			
		||||
		uint8(packet.CompressionNone),
 | 
			
		||||
		uint8(packet.CompressionZIP),
 | 
			
		||||
		uint8(packet.CompressionZLIB),
 | 
			
		||||
	}
 | 
			
		||||
	// In the event that a recipient doesn't specify any supported ciphers
 | 
			
		||||
	// or hash functions, these are the ones that we assume that every
 | 
			
		||||
	// implementation supports.
 | 
			
		||||
	defaultCiphers := candidateCiphers[0:1]
 | 
			
		||||
	defaultHashes := candidateHashes[0:1]
 | 
			
		||||
	defaultAeadModes := candidateAeadModes[0:1]
 | 
			
		||||
	defaultCompression := candidateCompression[0:1]
 | 
			
		||||
 | 
			
		||||
	encryptKeys := make([]Key, len(to))
 | 
			
		||||
	// AEAD is used only if every key supports it.
 | 
			
		||||
	aeadSupported := true
 | 
			
		||||
 | 
			
		||||
	for i := range to {
 | 
			
		||||
		var ok bool
 | 
			
		||||
		encryptKeys[i], ok = to[i].EncryptionKey(config.Now())
 | 
			
		||||
		if !ok {
 | 
			
		||||
			return nil, errors.InvalidArgumentError("cannot encrypt a message to key id " + strconv.FormatUint(to[i].PrimaryKey.KeyId, 16) + " because it has no valid encryption keys")
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		sig := to[i].PrimaryIdentity().SelfSignature
 | 
			
		||||
		if sig.AEAD == false {
 | 
			
		||||
			aeadSupported = false
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		preferredSymmetric := sig.PreferredSymmetric
 | 
			
		||||
		if len(preferredSymmetric) == 0 {
 | 
			
		||||
			preferredSymmetric = defaultCiphers
 | 
			
		||||
		}
 | 
			
		||||
		preferredHashes := sig.PreferredHash
 | 
			
		||||
		if len(preferredHashes) == 0 {
 | 
			
		||||
			preferredHashes = defaultHashes
 | 
			
		||||
		}
 | 
			
		||||
		preferredAeadModes := sig.PreferredAEAD
 | 
			
		||||
		if len(preferredAeadModes) == 0 {
 | 
			
		||||
			preferredAeadModes = defaultAeadModes
 | 
			
		||||
		}
 | 
			
		||||
		preferredCompression := sig.PreferredCompression
 | 
			
		||||
		if len(preferredCompression) == 0 {
 | 
			
		||||
			preferredCompression = defaultCompression
 | 
			
		||||
		}
 | 
			
		||||
		candidateCiphers = intersectPreferences(candidateCiphers, preferredSymmetric)
 | 
			
		||||
		candidateHashes = intersectPreferences(candidateHashes, preferredHashes)
 | 
			
		||||
		candidateAeadModes = intersectPreferences(candidateAeadModes, preferredAeadModes)
 | 
			
		||||
		candidateCompression = intersectPreferences(candidateCompression, preferredCompression)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(candidateCiphers) == 0 || len(candidateHashes) == 0 || len(candidateAeadModes) == 0 {
 | 
			
		||||
		return nil, errors.InvalidArgumentError("cannot encrypt because recipient set shares no common algorithms")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cipher := packet.CipherFunction(candidateCiphers[0])
 | 
			
		||||
	mode := packet.AEADMode(candidateAeadModes[0])
 | 
			
		||||
	// If the cipher specified by config is a candidate, we'll use that.
 | 
			
		||||
	configuredCipher := config.Cipher()
 | 
			
		||||
	for _, c := range candidateCiphers {
 | 
			
		||||
		cipherFunc := packet.CipherFunction(c)
 | 
			
		||||
		if cipherFunc == configuredCipher {
 | 
			
		||||
			cipher = cipherFunc
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	symKey := make([]byte, cipher.KeySize())
 | 
			
		||||
	if _, err := io.ReadFull(config.Random(), symKey); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, key := range encryptKeys {
 | 
			
		||||
		if err := packet.SerializeEncryptedKey(keyWriter, key.PublicKey, cipher, symKey, config); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var payload io.WriteCloser
 | 
			
		||||
	if config.AEAD() != nil && aeadSupported {
 | 
			
		||||
		payload, err = packet.SerializeAEADEncrypted(dataWriter, symKey, cipher, mode, config)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		payload, err = packet.SerializeSymmetricallyEncrypted(dataWriter, cipher, symKey, config)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	payload, err = handleCompression(payload, candidateCompression, config)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return writeAndSign(payload, candidateHashes, signed, hints, sigType, config)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Sign signs a message. The resulting WriteCloser must be closed after the
 | 
			
		||||
// contents of the file have been written.  hints contains optional information
 | 
			
		||||
// that aids the recipients in processing the message.
 | 
			
		||||
// If config is nil, sensible defaults will be used.
 | 
			
		||||
func Sign(output io.Writer, signed *Entity, hints *FileHints, config *packet.Config) (input io.WriteCloser, err error) {
 | 
			
		||||
	if signed == nil {
 | 
			
		||||
		return nil, errors.InvalidArgumentError("no signer provided")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// These are the possible hash functions that we'll use for the signature.
 | 
			
		||||
	candidateHashes := []uint8{
 | 
			
		||||
		hashToHashId(crypto.SHA256),
 | 
			
		||||
		hashToHashId(crypto.SHA384),
 | 
			
		||||
		hashToHashId(crypto.SHA512),
 | 
			
		||||
		hashToHashId(crypto.SHA1),
 | 
			
		||||
		hashToHashId(crypto.RIPEMD160),
 | 
			
		||||
	}
 | 
			
		||||
	defaultHashes := candidateHashes[0:1]
 | 
			
		||||
	preferredHashes := signed.PrimaryIdentity().SelfSignature.PreferredHash
 | 
			
		||||
	if len(preferredHashes) == 0 {
 | 
			
		||||
		preferredHashes = defaultHashes
 | 
			
		||||
	}
 | 
			
		||||
	candidateHashes = intersectPreferences(candidateHashes, preferredHashes)
 | 
			
		||||
	if len(candidateHashes) == 0 {
 | 
			
		||||
		return nil, errors.InvalidArgumentError("cannot sign because signing key shares no common algorithms with candidate hashes")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return writeAndSign(noOpCloser{output}, candidateHashes, signed, hints, packet.SigTypeBinary, config)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// signatureWriter hashes the contents of a message while passing it along to
 | 
			
		||||
// literalData. When closed, it closes literalData, writes a signature packet
 | 
			
		||||
// to encryptedData and then also closes encryptedData.
 | 
			
		||||
type signatureWriter struct {
 | 
			
		||||
	encryptedData io.WriteCloser
 | 
			
		||||
	literalData   io.WriteCloser
 | 
			
		||||
	hashType      crypto.Hash
 | 
			
		||||
	wrappedHash   hash.Hash
 | 
			
		||||
	h             hash.Hash
 | 
			
		||||
	signer        *packet.PrivateKey
 | 
			
		||||
	sigType       packet.SignatureType
 | 
			
		||||
	config        *packet.Config
 | 
			
		||||
	metadata      *packet.LiteralData // V5 signatures protect document metadata
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s signatureWriter) Write(data []byte) (int, error) {
 | 
			
		||||
	s.wrappedHash.Write(data)
 | 
			
		||||
	switch s.sigType {
 | 
			
		||||
	case packet.SigTypeBinary:
 | 
			
		||||
		return s.literalData.Write(data)
 | 
			
		||||
	case packet.SigTypeText:
 | 
			
		||||
		flag := 0
 | 
			
		||||
		return writeCanonical(s.literalData, data, &flag)
 | 
			
		||||
	}
 | 
			
		||||
	return 0, errors.UnsupportedError("unsupported signature type: " + strconv.Itoa(int(s.sigType)))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s signatureWriter) Close() error {
 | 
			
		||||
	sig := &packet.Signature{
 | 
			
		||||
		Version:      s.signer.Version,
 | 
			
		||||
		SigType:      s.sigType,
 | 
			
		||||
		PubKeyAlgo:   s.signer.PubKeyAlgo,
 | 
			
		||||
		Hash:         s.hashType,
 | 
			
		||||
		CreationTime: s.config.Now(),
 | 
			
		||||
		IssuerKeyId:  &s.signer.KeyId,
 | 
			
		||||
		Metadata:     s.metadata,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := sig.Sign(s.h, s.signer, s.config); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if err := s.literalData.Close(); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if err := sig.Serialize(s.encryptedData); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	return s.encryptedData.Close()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// noOpCloser is like an ioutil.NopCloser, but for an io.Writer.
 | 
			
		||||
// TODO: we have two of these in OpenPGP packages alone. This probably needs
 | 
			
		||||
// to be promoted somewhere more common.
 | 
			
		||||
type noOpCloser struct {
 | 
			
		||||
	w io.Writer
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c noOpCloser) Write(data []byte) (n int, err error) {
 | 
			
		||||
	return c.w.Write(data)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c noOpCloser) Close() error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func handleCompression(compressed io.WriteCloser, candidateCompression []uint8, config *packet.Config) (data io.WriteCloser, err error) {
 | 
			
		||||
	data = compressed
 | 
			
		||||
	confAlgo := config.Compression()
 | 
			
		||||
	if confAlgo == packet.CompressionNone {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	finalAlgo := packet.CompressionNone
 | 
			
		||||
	// if compression specified by config available we will use it
 | 
			
		||||
	for _, c := range candidateCompression {
 | 
			
		||||
		if uint8(confAlgo) == c {
 | 
			
		||||
			finalAlgo = confAlgo
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if finalAlgo != packet.CompressionNone {
 | 
			
		||||
		var compConfig *packet.CompressionConfig
 | 
			
		||||
		if config != nil {
 | 
			
		||||
			compConfig = config.CompressionConfig
 | 
			
		||||
		}
 | 
			
		||||
		data, err = packet.SerializeCompressed(compressed, finalAlgo, compConfig)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return data, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										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
 | 
			
		||||
							
								
								
									
										57
									
								
								vendor/github.com/cloudflare/circl/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								vendor/github.com/cloudflare/circl/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,57 @@
 | 
			
		||||
Copyright (c) 2019 Cloudflare. 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 Cloudflare 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.
 | 
			
		||||
 | 
			
		||||
========================================================================
 | 
			
		||||
 | 
			
		||||
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.
 | 
			
		||||
							
								
								
									
										96
									
								
								vendor/github.com/cloudflare/circl/dh/x25519/curve.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								vendor/github.com/cloudflare/circl/dh/x25519/curve.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,96 @@
 | 
			
		||||
package x25519
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	fp "github.com/cloudflare/circl/math/fp25519"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ladderJoye calculates a fixed-point multiplication with the generator point.
 | 
			
		||||
// The algorithm is the right-to-left Joye's ladder as described
 | 
			
		||||
// in "How to precompute a ladder" in SAC'2017.
 | 
			
		||||
func ladderJoye(k *Key) {
 | 
			
		||||
	w := [5]fp.Elt{} // [mu,x1,z1,x2,z2] order must be preserved.
 | 
			
		||||
	fp.SetOne(&w[1]) // x1 = 1
 | 
			
		||||
	fp.SetOne(&w[2]) // z1 = 1
 | 
			
		||||
	w[3] = fp.Elt{   // x2 = G-S
 | 
			
		||||
		0xbd, 0xaa, 0x2f, 0xc8, 0xfe, 0xe1, 0x94, 0x7e,
 | 
			
		||||
		0xf8, 0xed, 0xb2, 0x14, 0xae, 0x95, 0xf0, 0xbb,
 | 
			
		||||
		0xe2, 0x48, 0x5d, 0x23, 0xb9, 0xa0, 0xc7, 0xad,
 | 
			
		||||
		0x34, 0xab, 0x7c, 0xe2, 0xee, 0xcd, 0xae, 0x1e,
 | 
			
		||||
	}
 | 
			
		||||
	fp.SetOne(&w[4]) // z2 = 1
 | 
			
		||||
 | 
			
		||||
	const n = 255
 | 
			
		||||
	const h = 3
 | 
			
		||||
	swap := uint(1)
 | 
			
		||||
	for s := 0; s < n-h; s++ {
 | 
			
		||||
		i := (s + h) / 8
 | 
			
		||||
		j := (s + h) % 8
 | 
			
		||||
		bit := uint((k[i] >> uint(j)) & 1)
 | 
			
		||||
		copy(w[0][:], tableGenerator[s*Size:(s+1)*Size])
 | 
			
		||||
		diffAdd(&w, swap^bit)
 | 
			
		||||
		swap = bit
 | 
			
		||||
	}
 | 
			
		||||
	for s := 0; s < h; s++ {
 | 
			
		||||
		double(&w[1], &w[2])
 | 
			
		||||
	}
 | 
			
		||||
	toAffine((*[fp.Size]byte)(k), &w[1], &w[2])
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ladderMontgomery calculates a generic scalar point multiplication
 | 
			
		||||
// The algorithm implemented is the left-to-right Montgomery's ladder.
 | 
			
		||||
func ladderMontgomery(k, xP *Key) {
 | 
			
		||||
	w := [5]fp.Elt{}      // [x1, x2, z2, x3, z3] order must be preserved.
 | 
			
		||||
	w[0] = *(*fp.Elt)(xP) // x1 = xP
 | 
			
		||||
	fp.SetOne(&w[1])      // x2 = 1
 | 
			
		||||
	w[3] = *(*fp.Elt)(xP) // x3 = xP
 | 
			
		||||
	fp.SetOne(&w[4])      // z3 = 1
 | 
			
		||||
 | 
			
		||||
	move := uint(0)
 | 
			
		||||
	for s := 255 - 1; s >= 0; s-- {
 | 
			
		||||
		i := s / 8
 | 
			
		||||
		j := s % 8
 | 
			
		||||
		bit := uint((k[i] >> uint(j)) & 1)
 | 
			
		||||
		ladderStep(&w, move^bit)
 | 
			
		||||
		move = bit
 | 
			
		||||
	}
 | 
			
		||||
	toAffine((*[fp.Size]byte)(k), &w[1], &w[2])
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func toAffine(k *[fp.Size]byte, x, z *fp.Elt) {
 | 
			
		||||
	fp.Inv(z, z)
 | 
			
		||||
	fp.Mul(x, x, z)
 | 
			
		||||
	_ = fp.ToBytes(k[:], x)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var lowOrderPoints = [5]fp.Elt{
 | 
			
		||||
	{ /* (0,_,1) point of order 2 on Curve25519 */
 | 
			
		||||
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 | 
			
		||||
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 | 
			
		||||
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 | 
			
		||||
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 | 
			
		||||
	},
 | 
			
		||||
	{ /* (1,_,1) point of order 4 on Curve25519 */
 | 
			
		||||
		0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 | 
			
		||||
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 | 
			
		||||
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 | 
			
		||||
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 | 
			
		||||
	},
 | 
			
		||||
	{ /* (x,_,1) first point of order 8 on Curve25519 */
 | 
			
		||||
		0xe0, 0xeb, 0x7a, 0x7c, 0x3b, 0x41, 0xb8, 0xae,
 | 
			
		||||
		0x16, 0x56, 0xe3, 0xfa, 0xf1, 0x9f, 0xc4, 0x6a,
 | 
			
		||||
		0xda, 0x09, 0x8d, 0xeb, 0x9c, 0x32, 0xb1, 0xfd,
 | 
			
		||||
		0x86, 0x62, 0x05, 0x16, 0x5f, 0x49, 0xb8, 0x00,
 | 
			
		||||
	},
 | 
			
		||||
	{ /* (x,_,1) second point of order 8 on Curve25519 */
 | 
			
		||||
		0x5f, 0x9c, 0x95, 0xbc, 0xa3, 0x50, 0x8c, 0x24,
 | 
			
		||||
		0xb1, 0xd0, 0xb1, 0x55, 0x9c, 0x83, 0xef, 0x5b,
 | 
			
		||||
		0x04, 0x44, 0x5c, 0xc4, 0x58, 0x1c, 0x8e, 0x86,
 | 
			
		||||
		0xd8, 0x22, 0x4e, 0xdd, 0xd0, 0x9f, 0x11, 0x57,
 | 
			
		||||
	},
 | 
			
		||||
	{ /* (-1,_,1) a point of order 4 on the twist of Curve25519 */
 | 
			
		||||
		0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
 | 
			
		||||
		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
 | 
			
		||||
		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
 | 
			
		||||
		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										30
									
								
								vendor/github.com/cloudflare/circl/dh/x25519/curve_amd64.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								vendor/github.com/cloudflare/circl/dh/x25519/curve_amd64.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
			
		||||
//go:build amd64 && !purego
 | 
			
		||||
// +build amd64,!purego
 | 
			
		||||
 | 
			
		||||
package x25519
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	fp "github.com/cloudflare/circl/math/fp25519"
 | 
			
		||||
	"golang.org/x/sys/cpu"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var hasBmi2Adx = cpu.X86.HasBMI2 && cpu.X86.HasADX
 | 
			
		||||
 | 
			
		||||
var _ = hasBmi2Adx
 | 
			
		||||
 | 
			
		||||
func double(x, z *fp.Elt)             { doubleAmd64(x, z) }
 | 
			
		||||
func diffAdd(w *[5]fp.Elt, b uint)    { diffAddAmd64(w, b) }
 | 
			
		||||
func ladderStep(w *[5]fp.Elt, b uint) { ladderStepAmd64(w, b) }
 | 
			
		||||
func mulA24(z, x *fp.Elt)             { mulA24Amd64(z, x) }
 | 
			
		||||
 | 
			
		||||
//go:noescape
 | 
			
		||||
func ladderStepAmd64(w *[5]fp.Elt, b uint)
 | 
			
		||||
 | 
			
		||||
//go:noescape
 | 
			
		||||
func diffAddAmd64(w *[5]fp.Elt, b uint)
 | 
			
		||||
 | 
			
		||||
//go:noescape
 | 
			
		||||
func doubleAmd64(x, z *fp.Elt)
 | 
			
		||||
 | 
			
		||||
//go:noescape
 | 
			
		||||
func mulA24Amd64(z, x *fp.Elt)
 | 
			
		||||
							
								
								
									
										111
									
								
								vendor/github.com/cloudflare/circl/dh/x25519/curve_amd64.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								vendor/github.com/cloudflare/circl/dh/x25519/curve_amd64.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,111 @@
 | 
			
		||||
#define ladderStepLeg          \
 | 
			
		||||
    addSub(x2,z2)              \
 | 
			
		||||
    addSub(x3,z3)              \
 | 
			
		||||
    integerMulLeg(b0,x2,z3)    \
 | 
			
		||||
    integerMulLeg(b1,x3,z2)    \
 | 
			
		||||
    reduceFromDoubleLeg(t0,b0) \
 | 
			
		||||
    reduceFromDoubleLeg(t1,b1) \
 | 
			
		||||
    addSub(t0,t1)              \
 | 
			
		||||
    cselect(x2,x3,regMove)     \
 | 
			
		||||
    cselect(z2,z3,regMove)     \
 | 
			
		||||
    integerSqrLeg(b0,t0)       \
 | 
			
		||||
    integerSqrLeg(b1,t1)       \
 | 
			
		||||
    reduceFromDoubleLeg(x3,b0) \
 | 
			
		||||
    reduceFromDoubleLeg(z3,b1) \
 | 
			
		||||
    integerMulLeg(b0,x1,z3)    \
 | 
			
		||||
    reduceFromDoubleLeg(z3,b0) \
 | 
			
		||||
    integerSqrLeg(b0,x2)       \
 | 
			
		||||
    integerSqrLeg(b1,z2)       \
 | 
			
		||||
    reduceFromDoubleLeg(x2,b0) \
 | 
			
		||||
    reduceFromDoubleLeg(z2,b1) \
 | 
			
		||||
    subtraction(t0,x2,z2)      \
 | 
			
		||||
    multiplyA24Leg(t1,t0)      \
 | 
			
		||||
    additionLeg(t1,t1,z2)      \
 | 
			
		||||
    integerMulLeg(b0,x2,z2)    \
 | 
			
		||||
    integerMulLeg(b1,t0,t1)    \
 | 
			
		||||
    reduceFromDoubleLeg(x2,b0) \
 | 
			
		||||
    reduceFromDoubleLeg(z2,b1)
 | 
			
		||||
 | 
			
		||||
#define ladderStepBmi2Adx      \
 | 
			
		||||
    addSub(x2,z2)              \
 | 
			
		||||
    addSub(x3,z3)              \
 | 
			
		||||
    integerMulAdx(b0,x2,z3)    \
 | 
			
		||||
    integerMulAdx(b1,x3,z2)    \
 | 
			
		||||
    reduceFromDoubleAdx(t0,b0) \
 | 
			
		||||
    reduceFromDoubleAdx(t1,b1) \
 | 
			
		||||
    addSub(t0,t1)              \
 | 
			
		||||
    cselect(x2,x3,regMove)     \
 | 
			
		||||
    cselect(z2,z3,regMove)     \
 | 
			
		||||
    integerSqrAdx(b0,t0)       \
 | 
			
		||||
    integerSqrAdx(b1,t1)       \
 | 
			
		||||
    reduceFromDoubleAdx(x3,b0) \
 | 
			
		||||
    reduceFromDoubleAdx(z3,b1) \
 | 
			
		||||
    integerMulAdx(b0,x1,z3)    \
 | 
			
		||||
    reduceFromDoubleAdx(z3,b0) \
 | 
			
		||||
    integerSqrAdx(b0,x2)       \
 | 
			
		||||
    integerSqrAdx(b1,z2)       \
 | 
			
		||||
    reduceFromDoubleAdx(x2,b0) \
 | 
			
		||||
    reduceFromDoubleAdx(z2,b1) \
 | 
			
		||||
    subtraction(t0,x2,z2)      \
 | 
			
		||||
    multiplyA24Adx(t1,t0)      \
 | 
			
		||||
    additionAdx(t1,t1,z2)      \
 | 
			
		||||
    integerMulAdx(b0,x2,z2)    \
 | 
			
		||||
    integerMulAdx(b1,t0,t1)    \
 | 
			
		||||
    reduceFromDoubleAdx(x2,b0) \
 | 
			
		||||
    reduceFromDoubleAdx(z2,b1)
 | 
			
		||||
 | 
			
		||||
#define difAddLeg              \
 | 
			
		||||
    addSub(x1,z1)              \
 | 
			
		||||
    integerMulLeg(b0,z1,ui)    \
 | 
			
		||||
    reduceFromDoubleLeg(z1,b0) \
 | 
			
		||||
    addSub(x1,z1)              \
 | 
			
		||||
    integerSqrLeg(b0,x1)       \
 | 
			
		||||
    integerSqrLeg(b1,z1)       \
 | 
			
		||||
    reduceFromDoubleLeg(x1,b0) \
 | 
			
		||||
    reduceFromDoubleLeg(z1,b1) \
 | 
			
		||||
    integerMulLeg(b0,x1,z2)    \
 | 
			
		||||
    integerMulLeg(b1,z1,x2)    \
 | 
			
		||||
    reduceFromDoubleLeg(x1,b0) \
 | 
			
		||||
    reduceFromDoubleLeg(z1,b1)
 | 
			
		||||
 | 
			
		||||
#define difAddBmi2Adx          \
 | 
			
		||||
    addSub(x1,z1)              \
 | 
			
		||||
    integerMulAdx(b0,z1,ui)    \
 | 
			
		||||
    reduceFromDoubleAdx(z1,b0) \
 | 
			
		||||
    addSub(x1,z1)              \
 | 
			
		||||
    integerSqrAdx(b0,x1)       \
 | 
			
		||||
    integerSqrAdx(b1,z1)       \
 | 
			
		||||
    reduceFromDoubleAdx(x1,b0) \
 | 
			
		||||
    reduceFromDoubleAdx(z1,b1) \
 | 
			
		||||
    integerMulAdx(b0,x1,z2)    \
 | 
			
		||||
    integerMulAdx(b1,z1,x2)    \
 | 
			
		||||
    reduceFromDoubleAdx(x1,b0) \
 | 
			
		||||
    reduceFromDoubleAdx(z1,b1)
 | 
			
		||||
 | 
			
		||||
#define doubleLeg              \
 | 
			
		||||
    addSub(x1,z1)              \
 | 
			
		||||
    integerSqrLeg(b0,x1)       \
 | 
			
		||||
    integerSqrLeg(b1,z1)       \
 | 
			
		||||
    reduceFromDoubleLeg(x1,b0) \
 | 
			
		||||
    reduceFromDoubleLeg(z1,b1) \
 | 
			
		||||
    subtraction(t0,x1,z1)      \
 | 
			
		||||
    multiplyA24Leg(t1,t0)      \
 | 
			
		||||
    additionLeg(t1,t1,z1)      \
 | 
			
		||||
    integerMulLeg(b0,x1,z1)    \
 | 
			
		||||
    integerMulLeg(b1,t0,t1)    \
 | 
			
		||||
    reduceFromDoubleLeg(x1,b0) \
 | 
			
		||||
    reduceFromDoubleLeg(z1,b1)
 | 
			
		||||
 | 
			
		||||
#define doubleBmi2Adx          \
 | 
			
		||||
    addSub(x1,z1)              \
 | 
			
		||||
    integerSqrAdx(b0,x1)       \
 | 
			
		||||
    integerSqrAdx(b1,z1)       \
 | 
			
		||||
    reduceFromDoubleAdx(x1,b0) \
 | 
			
		||||
    reduceFromDoubleAdx(z1,b1) \
 | 
			
		||||
    subtraction(t0,x1,z1)      \
 | 
			
		||||
    multiplyA24Adx(t1,t0)      \
 | 
			
		||||
    additionAdx(t1,t1,z1)      \
 | 
			
		||||
    integerMulAdx(b0,x1,z1)    \
 | 
			
		||||
    integerMulAdx(b1,t0,t1)    \
 | 
			
		||||
    reduceFromDoubleAdx(x1,b0) \
 | 
			
		||||
    reduceFromDoubleAdx(z1,b1)
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user