mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-06-02 23:27:32 +02:00
Bump go-git, and get rid of github.com/imdario/mergo (#4460)
- **PR Description** This updates our go-git fork to the newest version (based on 5.14.1), and then updates the mergo dependency to use dario.cat/mergo instead of github.com/imdario/mergo.
This commit is contained in:
commit
391654984b
39
go.mod
39
go.mod
@ -3,6 +3,7 @@ module github.com/jesseduffield/lazygit
|
||||
go 1.24.0
|
||||
|
||||
require (
|
||||
dario.cat/mergo v1.0.1
|
||||
github.com/adrg/xdg v0.4.0
|
||||
github.com/atotto/clipboard v0.1.4
|
||||
github.com/aybabtme/humanlog v0.4.1
|
||||
@ -11,10 +12,9 @@ require (
|
||||
github.com/gdamore/tcell/v2 v2.8.1
|
||||
github.com/go-errors/errors v1.5.1
|
||||
github.com/gookit/color v1.4.2
|
||||
github.com/imdario/mergo v0.3.11
|
||||
github.com/integrii/flaggy v1.4.0
|
||||
github.com/jesseduffield/generics v0.0.0-20250406224309-4f541cb84918
|
||||
github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d
|
||||
github.com/jesseduffield/go-git/v5 v5.14.1-0.20250407170251-e1a013310ccd
|
||||
github.com/jesseduffield/gocui v0.3.1-0.20250408140206-7f1bb9232647
|
||||
github.com/jesseduffield/kill v0.0.0-20250101124109-e216ddbe133a
|
||||
github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5
|
||||
@ -30,51 +30,58 @@ require (
|
||||
github.com/samber/lo v1.31.0
|
||||
github.com/sanity-io/litter v1.5.2
|
||||
github.com/sasha-s/go-deadlock v0.3.5
|
||||
github.com/sirupsen/logrus v1.4.2
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/spf13/afero v1.9.5
|
||||
github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad
|
||||
github.com/stefanhaller/git-todo-parser v0.0.7-0.20240406123903-fd957137b6e2
|
||||
github.com/stretchr/testify v1.8.1
|
||||
github.com/stretchr/testify v1.10.0
|
||||
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778
|
||||
golang.org/x/exp v0.0.0-20220318154914-8dddf5d87bd8
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56
|
||||
golang.org/x/sync v0.13.0
|
||||
gopkg.in/ozeidan/fuzzy-patricia.v3 v3.0.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||
github.com/ProtonMail/go-crypto v1.1.6 // indirect
|
||||
github.com/bahlo/generic-list-go v0.2.0 // indirect
|
||||
github.com/buger/jsonparser v1.1.1 // indirect
|
||||
github.com/cloudflare/circl v1.6.0 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.4.1 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/emirpasic/gods v1.12.0 // indirect
|
||||
github.com/emirpasic/gods v1.18.1 // indirect
|
||||
github.com/fatih/color v1.9.0 // indirect
|
||||
github.com/gdamore/encoding v1.0.1 // indirect
|
||||
github.com/go-git/gcfg v1.5.0 // indirect
|
||||
github.com/go-git/go-billy/v5 v5.0.0 // indirect
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
||||
github.com/go-git/go-billy/v5 v5.6.2 // indirect
|
||||
github.com/go-logfmt/logfmt v0.5.0 // indirect
|
||||
github.com/gobwas/glob v0.2.3 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
|
||||
github.com/hpcloud/tail v1.0.0 // indirect
|
||||
github.com/invopop/jsonschema v0.10.0 // indirect
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd // indirect
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
|
||||
github.com/kevinburke/ssh_config v1.2.0 // indirect
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 // indirect
|
||||
github.com/kylelemons/godebug v1.1.0 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-colorable v0.1.11 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/onsi/ginkgo v1.10.3 // indirect
|
||||
github.com/onsi/gomega v1.7.1 // indirect
|
||||
github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 // indirect
|
||||
github.com/pjbgf/sha1cd v0.3.2 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/sergi/go-diff v1.1.0 // indirect
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
|
||||
github.com/skeema/knownhosts v1.3.1 // indirect
|
||||
github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect
|
||||
github.com/xanzy/ssh-agent v0.2.1 // indirect
|
||||
golang.org/x/crypto v0.31.0 // indirect
|
||||
golang.org/x/net v0.33.0 // indirect
|
||||
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
||||
golang.org/x/crypto v0.37.0 // indirect
|
||||
golang.org/x/net v0.39.0 // indirect
|
||||
golang.org/x/sys v0.32.0 // indirect
|
||||
golang.org/x/term v0.31.0 // indirect
|
||||
golang.org/x/text v0.24.0 // indirect
|
||||
gopkg.in/fsnotify.v1 v1.4.7 // indirect
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
)
|
||||
|
131
go.sum
131
go.sum
@ -35,15 +35,20 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl
|
||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
|
||||
dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
|
||||
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
|
||||
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||
github.com/ProtonMail/go-crypto v1.1.6 h1:ZcV+Ropw6Qn0AX9brlQLAUXfqLBc7Bl+f/DmNxpLfdw=
|
||||
github.com/ProtonMail/go-crypto v1.1.6/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
|
||||
github.com/adrg/xdg v0.4.0 h1:RzRqFcjH4nE5C6oTAxhBtoE2IRyjBSa62SCbyPidvls=
|
||||
github.com/adrg/xdg v0.4.0/go.mod h1:N6ag73EX4wyxeaoeHctc1mas01KZgsj5tYiAIwqJE/E=
|
||||
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs=
|
||||
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
|
||||
github.com/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/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
|
||||
@ -60,20 +65,25 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cloudflare/circl v1.6.0 h1:cr5JKic4HI+LkINy2lg3W2jF8sHCVTBncJr5gIIq7qk=
|
||||
github.com/cloudflare/circl v1.6.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
|
||||
github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21 h1:tuijfIjZyjZaHq9xDUh0tNitwXshJpbLkqMOJv4H3do=
|
||||
github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21/go.mod h1:po7NpZ/QiTKzBKyrsEAxwnTamCoh8uDk/egRpQ7siIc=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw=
|
||||
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s=
|
||||
github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
|
||||
github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
|
||||
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
|
||||
github.com/elazarl/goproxy v1.7.2 h1:Y2o6urb7Eule09PjlhQRGNsqRfPmYI3KKQLFpCAV3+o=
|
||||
github.com/elazarl/goproxy v1.7.2/go.mod h1:82vkLNir0ALaW14Rc399OTTjyNREgmdL2cVoIbS6XaE=
|
||||
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
|
||||
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
@ -83,24 +93,22 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7
|
||||
github.com/fatih/color v1.7.1-0.20180516100307-2d684516a886/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
|
||||
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/gdamore/encoding v1.0.1 h1:YzKZckdBL6jVt2Gc+5p82qhrGiqMdG/eNs6Wy0u3Uhw=
|
||||
github.com/gdamore/encoding v1.0.1/go.mod h1:0Z0cMFinngz9kS1QfMjCP8TY7em3bZYeeklsSDPivEo=
|
||||
github.com/gdamore/tcell/v2 v2.8.0/go.mod h1:bj8ori1BG3OYMjmb3IklZVWfZUJ1UBQt9JXrOCOhGWw=
|
||||
github.com/gdamore/tcell/v2 v2.8.1 h1:KPNxyqclpWpWQlPLx6Xui1pMk8S+7+R37h3g07997NU=
|
||||
github.com/gdamore/tcell/v2 v2.8.1/go.mod h1:bj8ori1BG3OYMjmb3IklZVWfZUJ1UBQt9JXrOCOhGWw=
|
||||
github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0=
|
||||
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||
github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=
|
||||
github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU=
|
||||
github.com/go-errors/errors v1.0.2/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs=
|
||||
github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk=
|
||||
github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
|
||||
github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4=
|
||||
github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E=
|
||||
github.com/go-git/go-billy/v5 v5.0.0 h1:7NQHvd9FVid8VL4qVUMm8XifBK+2xCoZ2lSk0agRrHM=
|
||||
github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12 h1:PbKy9zOy4aAKrJ5pibIRpVO2BXnK1Tlcg+caKI7Ox5M=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw=
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
|
||||
github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UNbRM=
|
||||
github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
@ -113,6 +121,8 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfU
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
@ -145,8 +155,9 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
@ -173,9 +184,6 @@ github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||
github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA=
|
||||
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||
github.com/integrii/flaggy v1.4.0 h1:A1x7SYx4jqu5NSrY14z8Z+0UyX2S5ygfJJrfolWR3zM=
|
||||
github.com/integrii/flaggy v1.4.0/go.mod h1:tnTxHeTJbah0gQ6/K0RW0J7fMUBk9MCF5blhm43LNpI=
|
||||
github.com/invopop/jsonschema v0.10.0 h1:c1ktzNLBun3LyQQhyty5WE3lulbOdIIyOVlkmDLehcE=
|
||||
@ -184,8 +192,8 @@ github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOl
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
||||
github.com/jesseduffield/generics v0.0.0-20250406224309-4f541cb84918 h1:meoUDZGF6jZAbhW5IBwj92mTqGmrOn+Cuu0jM7/aUcs=
|
||||
github.com/jesseduffield/generics v0.0.0-20250406224309-4f541cb84918/go.mod h1:+LLj9/WUPAP8LqCchs7P+7X0R98HiFujVFANdNaxhGk=
|
||||
github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d h1:bO+OmbreIv91rCe8NmscRwhFSqkDJtzWCPV4Y+SQuXE=
|
||||
github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d/go.mod h1:nGNEErzf+NRznT+N2SWqmHnDnF9aLgANB1CUNEan09o=
|
||||
github.com/jesseduffield/go-git/v5 v5.14.1-0.20250407170251-e1a013310ccd h1:ViKj6qth8FgcIWizn9KiACWwPemWSymx62OPN0tHT+Q=
|
||||
github.com/jesseduffield/go-git/v5 v5.14.1-0.20250407170251-e1a013310ccd/go.mod h1:lRhCiBr6XjQrvcQVa+UYsy/99d3wMXn/a0nSQlhnhlA=
|
||||
github.com/jesseduffield/gocui v0.3.1-0.20250408140206-7f1bb9232647 h1:XpoXCyLGCB4mczPc1q/8dJefr6OB1xa7jyhH5a5eJqY=
|
||||
github.com/jesseduffield/gocui v0.3.1-0.20250408140206-7f1bb9232647/go.mod h1:sLIyZ2J42R6idGdtemZzsiR3xY5EF0KsvYEGh3dQv3s=
|
||||
github.com/jesseduffield/kill v0.0.0-20250101124109-e216ddbe133a h1:UDeJ3EBk04bXDLOPvuqM3on8HvyJfISw0+UMqW+0a4g=
|
||||
@ -194,7 +202,6 @@ github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5 h1:CDuQmfOj
|
||||
github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5/go.mod h1:qxN4mHOAyeIDLP7IK7defgPClM/z1Kze8VVQiaEjzsQ=
|
||||
github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e h1:uw/oo+kg7t/oeMs6sqlAwr85ND/9cpO3up3VxphxY0U=
|
||||
github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e/go.mod h1:u60qdFGXRd36jyEXxetz0vQceQIxzI13lIo3EFUDf4I=
|
||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
@ -202,16 +209,15 @@ github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 h1:iQTw/8FWTuc7uia
|
||||
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
|
||||
github.com/karimkhaleel/jsonschema v0.0.0-20231001195015-d933f0d94ea3 h1:s995u+gNQADMaixtNOs+jilRC/Q78q0UXSI7+4T0cDE=
|
||||
github.com/karimkhaleel/jsonschema v0.0.0-20231001195015-d933f0d94ea3/go.mod h1:MCbEh21gjOzxc31udr3u4QM9DAdf8TFJCZz3u5hYIxA=
|
||||
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v2wtGp9Gmz1Ze3eVRAWJMLokvN3QjdzCHLY=
|
||||
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
|
||||
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
@ -237,20 +243,16 @@ github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6T
|
||||
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mgutz/str v1.2.0 h1:4IzWSdIz9qPQWLfKZ0rJcV0jcUDpxvP4JVZ4GXQyvSw=
|
||||
github.com/mgutz/str v1.2.0/go.mod h1:w1v0ofgLaJdoD0HpQ3fycxKD1WtxpjSo151pK/31q6w=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc=
|
||||
github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg=
|
||||
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/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.10.3 h1:OoxbjfXVZyod1fmWYhI7SEyaD8B00ynP3T+D5GiyHOY=
|
||||
github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/gomega v1.7.1 h1:K0jcRCwNQM3vFGh1ppMtDh/+7ApJrjldlX8fA0jDTLQ=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
|
||||
github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
|
||||
github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 h1:Dx7Ovyv/SFnMFw3fD4oEoeorXc6saIiQ23LrGLth0Gw=
|
||||
github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pjbgf/sha1cd v0.3.2 h1:a9wb0bp1oC2TGwStyn0Umc/IGKQnEgF0vVaZ8QF8eo4=
|
||||
github.com/pjbgf/sha1cd v0.3.2/go.mod h1:zQWigSxVmsHEZow5qaLtPYxpcKMMQpa09ixqBxuCS6A=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
|
||||
@ -263,6 +265,8 @@ github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUc
|
||||
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||
github.com/sahilm/fuzzy v0.1.0 h1:FzWGaw2Opqyu+794ZQ9SYifWv2EIXpwP4q8dY1kDAwI=
|
||||
github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
|
||||
github.com/samber/lo v1.31.0 h1:Sfa+/064Tdo4SvlohQUQzBhgSer9v/coGvKQI/XLWAM=
|
||||
@ -271,10 +275,13 @@ github.com/sanity-io/litter v1.5.2 h1:AnC8s9BMORWH5a4atZ4D6FPVvKGzHcnc5/IVTa87my
|
||||
github.com/sanity-io/litter v1.5.2/go.mod h1:5Z71SvaYy5kcGtyglXOC9rrUi3c1E8CamFWjQsazTh0=
|
||||
github.com/sasha-s/go-deadlock v0.3.5 h1:tNCOEEDG6tBqrNDOX35j/7hL5FcFViG6awUGROb2NsU=
|
||||
github.com/sasha-s/go-deadlock v0.3.5/go.mod h1:bugP6EGbdGYObIlx7pUZtWqlvo8k9H6vCBBsiChJQ5U=
|
||||
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
|
||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/skeema/knownhosts v1.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnBY8=
|
||||
github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY=
|
||||
github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM=
|
||||
github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ=
|
||||
github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad h1:fiWzISvDn0Csy5H0iwgAuJGQTUpVfEMJJd4nRFXogbc=
|
||||
@ -282,26 +289,21 @@ github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKk
|
||||
github.com/stefanhaller/git-todo-parser v0.0.7-0.20240406123903-fd957137b6e2 h1:RTNWemd/9z9A5L/AggEP3OdhRz5dXETB/wdAlYF0SuM=
|
||||
github.com/stefanhaller/git-todo-parser v0.0.7-0.20240406123903-fd957137b6e2/go.mod h1:HFt9hGqMzgQ+gVxMKcvTvGaFz4Y0yYycqqAp2V3wcJY=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v0.0.0-20161117074351-18a02ba4a312/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
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.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/thoas/go-funk v0.9.1 h1:O549iLZqPpTUQ10ykd26sZhzD+rmR5pWhuElrhbC20M=
|
||||
github.com/thoas/go-funk v0.9.1/go.mod h1:+IWnUfUmFO1+WVYQWQtIJHeRRdaIyyYglZN7xzUPe4Q=
|
||||
github.com/urfave/cli v1.20.1-0.20180226030253-8e01ec4cd3e2/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc=
|
||||
github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw=
|
||||
github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70=
|
||||
github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
|
||||
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
|
||||
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
|
||||
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8=
|
||||
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
@ -315,21 +317,20 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
||||
golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
|
||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
|
||||
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
@ -340,8 +341,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
|
||||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/exp v0.0.0-20220318154914-8dddf5d87bd8 h1:s/+U+w0teGzcoH2mdIlFQ6KfVKGaYpgyGdUefZrn9TU=
|
||||
golang.org/x/exp v0.0.0-20220318154914-8dddf5d87bd8/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
@ -372,7 +373,6 @@ golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
@ -409,8 +409,8 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
|
||||
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
|
||||
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@ -440,13 +440,10 @@ golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
|
||||
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.0.0-20170407050850-f3918c30c5c2/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@ -475,6 +472,7 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@ -484,6 +482,7 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
@ -669,8 +668,8 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
@ -681,9 +680,7 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWD
|
||||
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.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 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
@ -7,9 +7,9 @@ import (
|
||||
"io/fs"
|
||||
"strings"
|
||||
|
||||
"dario.cat/mergo"
|
||||
"github.com/cloudfoundry/jibber_jabber"
|
||||
"github.com/go-errors/errors"
|
||||
"github.com/imdario/mergo"
|
||||
"github.com/samber/lo"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
@ -13,6 +13,9 @@
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
# Golang/Intellij
|
||||
.idea
|
||||
|
||||
# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
|
||||
.glide/
|
||||
|
112
vendor/dario.cat/mergo/CONTRIBUTING.md
vendored
Normal file
112
vendor/dario.cat/mergo/CONTRIBUTING.md
vendored
Normal file
@ -0,0 +1,112 @@
|
||||
<!-- omit in toc -->
|
||||
# Contributing to mergo
|
||||
|
||||
First off, thanks for taking the time to contribute! ❤️
|
||||
|
||||
All types of contributions are encouraged and valued. See the [Table of Contents](#table-of-contents) for different ways to help and details about how this project handles them. Please make sure to read the relevant section before making your contribution. It will make it a lot easier for us maintainers and smooth out the experience for all involved. The community looks forward to your contributions. 🎉
|
||||
|
||||
> And if you like the project, but just don't have time to contribute, that's fine. There are other easy ways to support the project and show your appreciation, which we would also be very happy about:
|
||||
> - Star the project
|
||||
> - Tweet about it
|
||||
> - Refer this project in your project's readme
|
||||
> - Mention the project at local meetups and tell your friends/colleagues
|
||||
|
||||
<!-- omit in toc -->
|
||||
## Table of Contents
|
||||
|
||||
- [Code of Conduct](#code-of-conduct)
|
||||
- [I Have a Question](#i-have-a-question)
|
||||
- [I Want To Contribute](#i-want-to-contribute)
|
||||
- [Reporting Bugs](#reporting-bugs)
|
||||
- [Suggesting Enhancements](#suggesting-enhancements)
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
This project and everyone participating in it is governed by the
|
||||
[mergo Code of Conduct](https://github.com/imdario/mergoblob/master/CODE_OF_CONDUCT.md).
|
||||
By participating, you are expected to uphold this code. Please report unacceptable behavior
|
||||
to <>.
|
||||
|
||||
|
||||
## I Have a Question
|
||||
|
||||
> If you want to ask a question, we assume that you have read the available [Documentation](https://pkg.go.dev/github.com/imdario/mergo).
|
||||
|
||||
Before you ask a question, it is best to search for existing [Issues](https://github.com/imdario/mergo/issues) that might help you. In case you have found a suitable issue and still need clarification, you can write your question in this issue. It is also advisable to search the internet for answers first.
|
||||
|
||||
If you then still feel the need to ask a question and need clarification, we recommend the following:
|
||||
|
||||
- Open an [Issue](https://github.com/imdario/mergo/issues/new).
|
||||
- Provide as much context as you can about what you're running into.
|
||||
- Provide project and platform versions (nodejs, npm, etc), depending on what seems relevant.
|
||||
|
||||
We will then take care of the issue as soon as possible.
|
||||
|
||||
## I Want To Contribute
|
||||
|
||||
> ### Legal Notice <!-- omit in toc -->
|
||||
> When contributing to this project, you must agree that you have authored 100% of the content, that you have the necessary rights to the content and that the content you contribute may be provided under the project license.
|
||||
|
||||
### Reporting Bugs
|
||||
|
||||
<!-- omit in toc -->
|
||||
#### Before Submitting a Bug Report
|
||||
|
||||
A good bug report shouldn't leave others needing to chase you up for more information. Therefore, we ask you to investigate carefully, collect information and describe the issue in detail in your report. Please complete the following steps in advance to help us fix any potential bug as fast as possible.
|
||||
|
||||
- Make sure that you are using the latest version.
|
||||
- Determine if your bug is really a bug and not an error on your side e.g. using incompatible environment components/versions (Make sure that you have read the [documentation](). If you are looking for support, you might want to check [this section](#i-have-a-question)).
|
||||
- To see if other users have experienced (and potentially already solved) the same issue you are having, check if there is not already a bug report existing for your bug or error in the [bug tracker](https://github.com/imdario/mergoissues?q=label%3Abug).
|
||||
- Also make sure to search the internet (including Stack Overflow) to see if users outside of the GitHub community have discussed the issue.
|
||||
- Collect information about the bug:
|
||||
- Stack trace (Traceback)
|
||||
- OS, Platform and Version (Windows, Linux, macOS, x86, ARM)
|
||||
- Version of the interpreter, compiler, SDK, runtime environment, package manager, depending on what seems relevant.
|
||||
- Possibly your input and the output
|
||||
- Can you reliably reproduce the issue? And can you also reproduce it with older versions?
|
||||
|
||||
<!-- omit in toc -->
|
||||
#### How Do I Submit a Good Bug Report?
|
||||
|
||||
> You must never report security related issues, vulnerabilities or bugs including sensitive information to the issue tracker, or elsewhere in public. Instead sensitive bugs must be sent by email to .
|
||||
<!-- You may add a PGP key to allow the messages to be sent encrypted as well. -->
|
||||
|
||||
We use GitHub issues to track bugs and errors. If you run into an issue with the project:
|
||||
|
||||
- Open an [Issue](https://github.com/imdario/mergo/issues/new). (Since we can't be sure at this point whether it is a bug or not, we ask you not to talk about a bug yet and not to label the issue.)
|
||||
- Explain the behavior you would expect and the actual behavior.
|
||||
- Please provide as much context as possible and describe the *reproduction steps* that someone else can follow to recreate the issue on their own. This usually includes your code. For good bug reports you should isolate the problem and create a reduced test case.
|
||||
- Provide the information you collected in the previous section.
|
||||
|
||||
Once it's filed:
|
||||
|
||||
- The project team will label the issue accordingly.
|
||||
- A team member will try to reproduce the issue with your provided steps. If there are no reproduction steps or no obvious way to reproduce the issue, the team will ask you for those steps and mark the issue as `needs-repro`. Bugs with the `needs-repro` tag will not be addressed until they are reproduced.
|
||||
- If the team is able to reproduce the issue, it will be marked `needs-fix`, as well as possibly other tags (such as `critical`), and the issue will be left to be implemented by someone.
|
||||
|
||||
### Suggesting Enhancements
|
||||
|
||||
This section guides you through submitting an enhancement suggestion for mergo, **including completely new features and minor improvements to existing functionality**. Following these guidelines will help maintainers and the community to understand your suggestion and find related suggestions.
|
||||
|
||||
<!-- omit in toc -->
|
||||
#### Before Submitting an Enhancement
|
||||
|
||||
- Make sure that you are using the latest version.
|
||||
- Read the [documentation]() carefully and find out if the functionality is already covered, maybe by an individual configuration.
|
||||
- Perform a [search](https://github.com/imdario/mergo/issues) to see if the enhancement has already been suggested. If it has, add a comment to the existing issue instead of opening a new one.
|
||||
- Find out whether your idea fits with the scope and aims of the project. It's up to you to make a strong case to convince the project's developers of the merits of this feature. Keep in mind that we want features that will be useful to the majority of our users and not just a small subset. If you're just targeting a minority of users, consider writing an add-on/plugin library.
|
||||
|
||||
<!-- omit in toc -->
|
||||
#### How Do I Submit a Good Enhancement Suggestion?
|
||||
|
||||
Enhancement suggestions are tracked as [GitHub issues](https://github.com/imdario/mergo/issues).
|
||||
|
||||
- Use a **clear and descriptive title** for the issue to identify the suggestion.
|
||||
- Provide a **step-by-step description of the suggested enhancement** in as many details as possible.
|
||||
- **Describe the current behavior** and **explain which behavior you expected to see instead** and why. At this point you can also tell which alternatives do not work for you.
|
||||
- You may want to **include screenshots and animated GIFs** which help you demonstrate the steps or point out the part which the suggestion is related to. You can use [this tool](https://www.cockos.com/licecap/) to record GIFs on macOS and Windows, and [this tool](https://github.com/colinkeenan/silentcast) or [this tool](https://github.com/GNOME/byzanz) on Linux. <!-- this should only be included if the project has a GUI -->
|
||||
- **Explain why this enhancement would be useful** to most mergo users. You may also want to point out the other projects that solved it better and which could serve as inspiration.
|
||||
|
||||
<!-- omit in toc -->
|
||||
## Attribution
|
||||
This guide is based on the **contributing-gen**. [Make your own](https://github.com/bttger/contributing-gen)!
|
@ -1,18 +1,20 @@
|
||||
# Mergo
|
||||
|
||||
|
||||
[![GoDoc][3]][4]
|
||||
[![GitHub release][5]][6]
|
||||
[![GoCard][7]][8]
|
||||
[![Build Status][1]][2]
|
||||
[![Coverage Status][9]][10]
|
||||
[![Test status][1]][2]
|
||||
[![OpenSSF Scorecard][21]][22]
|
||||
[![OpenSSF Best Practices][19]][20]
|
||||
[![Coverage status][9]][10]
|
||||
[![Sourcegraph][11]][12]
|
||||
[![FOSSA Status][13]][14]
|
||||
[![FOSSA status][13]][14]
|
||||
|
||||
[![GoCenter Kudos][15]][16]
|
||||
[![GoDoc][3]][4]
|
||||
[![Become my sponsor][15]][16]
|
||||
[![Tidelift][17]][18]
|
||||
|
||||
[1]: https://travis-ci.org/imdario/mergo.png
|
||||
[2]: https://travis-ci.org/imdario/mergo
|
||||
[1]: https://github.com/imdario/mergo/workflows/tests/badge.svg?branch=master
|
||||
[2]: https://github.com/imdario/mergo/actions/workflows/tests.yml
|
||||
[3]: https://godoc.org/github.com/imdario/mergo?status.svg
|
||||
[4]: https://godoc.org/github.com/imdario/mergo
|
||||
[5]: https://img.shields.io/github/release/imdario/mergo.svg
|
||||
@ -25,8 +27,14 @@
|
||||
[12]: https://sourcegraph.com/github.com/imdario/mergo?badge
|
||||
[13]: https://app.fossa.io/api/projects/git%2Bgithub.com%2Fimdario%2Fmergo.svg?type=shield
|
||||
[14]: https://app.fossa.io/projects/git%2Bgithub.com%2Fimdario%2Fmergo?ref=badge_shield
|
||||
[15]: https://search.gocenter.io/api/ui/badge/github.com%2Fimdario%2Fmergo
|
||||
[16]: https://search.gocenter.io/github.com/imdario/mergo
|
||||
[15]: https://img.shields.io/github/sponsors/imdario
|
||||
[16]: https://github.com/sponsors/imdario
|
||||
[17]: https://tidelift.com/badges/package/go/github.com%2Fimdario%2Fmergo
|
||||
[18]: https://tidelift.com/subscription/pkg/go-github.com-imdario-mergo
|
||||
[19]: https://bestpractices.coreinfrastructure.org/projects/7177/badge
|
||||
[20]: https://bestpractices.coreinfrastructure.org/projects/7177
|
||||
[21]: https://api.securityscorecards.dev/projects/github.com/imdario/mergo/badge
|
||||
[22]: https://api.securityscorecards.dev/projects/github.com/imdario/mergo
|
||||
|
||||
A helper to merge structs and maps in Golang. Useful for configuration default values, avoiding messy if-statements.
|
||||
|
||||
@ -36,76 +44,60 @@ Also a lovely [comune](http://en.wikipedia.org/wiki/Mergo) (municipality) in the
|
||||
|
||||
## Status
|
||||
|
||||
It is ready for production use. [It is used in several projects by Docker, Google, The Linux Foundation, VMWare, Shopify, etc](https://github.com/imdario/mergo#mergo-in-the-wild).
|
||||
Mergo is stable and frozen, ready for production. Check a short list of the projects using at large scale it [here](https://github.com/imdario/mergo#mergo-in-the-wild).
|
||||
|
||||
### Important note
|
||||
No new features are accepted. They will be considered for a future v2 that improves the implementation and fixes bugs for corner cases.
|
||||
|
||||
Please keep in mind that a problematic PR broke [0.3.9](//github.com/imdario/mergo/releases/tag/0.3.9). I reverted it in [0.3.10](//github.com/imdario/mergo/releases/tag/0.3.10), and I consider it stable but not bug-free. Also, this version adds suppot for go modules.
|
||||
### Important notes
|
||||
|
||||
#### 1.0.0
|
||||
|
||||
In [1.0.0](//github.com/imdario/mergo/releases/tag/1.0.0) Mergo moves to a vanity URL `dario.cat/mergo`. No more v1 versions will be released.
|
||||
|
||||
If the vanity URL is causing issues in your project due to a dependency pulling Mergo - it isn't a direct dependency in your project - it is recommended to use [replace](https://github.com/golang/go/wiki/Modules#when-should-i-use-the-replace-directive) to pin the version to the last one with the old import URL:
|
||||
|
||||
```
|
||||
replace github.com/imdario/mergo => github.com/imdario/mergo v0.3.16
|
||||
```
|
||||
|
||||
#### 0.3.9
|
||||
|
||||
Please keep in mind that a problematic PR broke [0.3.9](//github.com/imdario/mergo/releases/tag/0.3.9). I reverted it in [0.3.10](//github.com/imdario/mergo/releases/tag/0.3.10), and I consider it stable but not bug-free. Also, this version adds support for go modules.
|
||||
|
||||
Keep in mind that in [0.3.2](//github.com/imdario/mergo/releases/tag/0.3.2), Mergo changed `Merge()`and `Map()` signatures to support [transformers](#transformers). I added an optional/variadic argument so that it won't break the existing code.
|
||||
|
||||
If you were using Mergo before April 6th, 2015, please check your project works as intended after updating your local copy with ```go get -u github.com/imdario/mergo```. I apologize for any issue caused by its previous behavior and any future bug that Mergo could cause in existing projects after the change (release 0.2.0).
|
||||
If you were using Mergo before April 6th, 2015, please check your project works as intended after updating your local copy with ```go get -u dario.cat/mergo```. I apologize for any issue caused by its previous behavior and any future bug that Mergo could cause in existing projects after the change (release 0.2.0).
|
||||
|
||||
### Donations
|
||||
|
||||
If Mergo is useful to you, consider buying me a coffee, a beer, or making a monthly donation to allow me to keep building great free software. :heart_eyes:
|
||||
|
||||
<a href='https://ko-fi.com/B0B58839' target='_blank'><img height='36' style='border:0px;height:36px;' src='https://az743702.vo.msecnd.net/cdn/kofi1.png?v=0' border='0' alt='Buy Me a Coffee at ko-fi.com' /></a>
|
||||
[](https://beerpay.io/imdario/mergo)
|
||||
[](https://beerpay.io/imdario/mergo)
|
||||
<a href="https://liberapay.com/dario/donate"><img alt="Donate using Liberapay" src="https://liberapay.com/assets/widgets/donate.svg"></a>
|
||||
<a href='https://github.com/sponsors/imdario' target='_blank'><img alt="Become my sponsor" src="https://img.shields.io/github/sponsors/imdario?style=for-the-badge" /></a>
|
||||
|
||||
### Mergo in the wild
|
||||
|
||||
- [moby/moby](https://github.com/moby/moby)
|
||||
- [kubernetes/kubernetes](https://github.com/kubernetes/kubernetes)
|
||||
- [vmware/dispatch](https://github.com/vmware/dispatch)
|
||||
- [Shopify/themekit](https://github.com/Shopify/themekit)
|
||||
- [imdario/zas](https://github.com/imdario/zas)
|
||||
- [matcornic/hermes](https://github.com/matcornic/hermes)
|
||||
- [OpenBazaar/openbazaar-go](https://github.com/OpenBazaar/openbazaar-go)
|
||||
- [kataras/iris](https://github.com/kataras/iris)
|
||||
- [michaelsauter/crane](https://github.com/michaelsauter/crane)
|
||||
- [go-task/task](https://github.com/go-task/task)
|
||||
- [sensu/uchiwa](https://github.com/sensu/uchiwa)
|
||||
- [ory/hydra](https://github.com/ory/hydra)
|
||||
- [sisatech/vcli](https://github.com/sisatech/vcli)
|
||||
- [dairycart/dairycart](https://github.com/dairycart/dairycart)
|
||||
- [projectcalico/felix](https://github.com/projectcalico/felix)
|
||||
- [resin-os/balena](https://github.com/resin-os/balena)
|
||||
- [go-kivik/kivik](https://github.com/go-kivik/kivik)
|
||||
- [Telefonica/govice](https://github.com/Telefonica/govice)
|
||||
- [supergiant/supergiant](supergiant/supergiant)
|
||||
- [SergeyTsalkov/brooce](https://github.com/SergeyTsalkov/brooce)
|
||||
- [soniah/dnsmadeeasy](https://github.com/soniah/dnsmadeeasy)
|
||||
- [ohsu-comp-bio/funnel](https://github.com/ohsu-comp-bio/funnel)
|
||||
- [EagerIO/Stout](https://github.com/EagerIO/Stout)
|
||||
- [lynndylanhurley/defsynth-api](https://github.com/lynndylanhurley/defsynth-api)
|
||||
- [russross/canvasassignments](https://github.com/russross/canvasassignments)
|
||||
- [rdegges/cryptly-api](https://github.com/rdegges/cryptly-api)
|
||||
- [casualjim/exeggutor](https://github.com/casualjim/exeggutor)
|
||||
- [divshot/gitling](https://github.com/divshot/gitling)
|
||||
- [RWJMurphy/gorl](https://github.com/RWJMurphy/gorl)
|
||||
- [andrerocker/deploy42](https://github.com/andrerocker/deploy42)
|
||||
- [elwinar/rambler](https://github.com/elwinar/rambler)
|
||||
- [tmaiaroto/gopartman](https://github.com/tmaiaroto/gopartman)
|
||||
- [jfbus/impressionist](https://github.com/jfbus/impressionist)
|
||||
- [Jmeyering/zealot](https://github.com/Jmeyering/zealot)
|
||||
- [godep-migrator/rigger-host](https://github.com/godep-migrator/rigger-host)
|
||||
- [Dronevery/MultiwaySwitch-Go](https://github.com/Dronevery/MultiwaySwitch-Go)
|
||||
- [thoas/picfit](https://github.com/thoas/picfit)
|
||||
- [mantasmatelis/whooplist-server](https://github.com/mantasmatelis/whooplist-server)
|
||||
- [jnuthong/item_search](https://github.com/jnuthong/item_search)
|
||||
- [bukalapak/snowboard](https://github.com/bukalapak/snowboard)
|
||||
- [janoszen/containerssh](https://github.com/janoszen/containerssh)
|
||||
Mergo is used by [thousands](https://deps.dev/go/dario.cat%2Fmergo/v1.0.0/dependents) [of](https://deps.dev/go/github.com%2Fimdario%2Fmergo/v0.3.16/dependents) [projects](https://deps.dev/go/github.com%2Fimdario%2Fmergo/v0.3.12), including:
|
||||
|
||||
* [containerd/containerd](https://github.com/containerd/containerd)
|
||||
* [datadog/datadog-agent](https://github.com/datadog/datadog-agent)
|
||||
* [docker/cli/](https://github.com/docker/cli/)
|
||||
* [goreleaser/goreleaser](https://github.com/goreleaser/goreleaser)
|
||||
* [go-micro/go-micro](https://github.com/go-micro/go-micro)
|
||||
* [grafana/loki](https://github.com/grafana/loki)
|
||||
* [kubernetes/kubernetes](https://github.com/kubernetes/kubernetes)
|
||||
* [masterminds/sprig](github.com/Masterminds/sprig)
|
||||
* [moby/moby](https://github.com/moby/moby)
|
||||
* [slackhq/nebula](https://github.com/slackhq/nebula)
|
||||
* [volcano-sh/volcano](https://github.com/volcano-sh/volcano)
|
||||
|
||||
## Install
|
||||
|
||||
go get github.com/imdario/mergo
|
||||
go get dario.cat/mergo
|
||||
|
||||
// use in your .go code
|
||||
import (
|
||||
"github.com/imdario/mergo"
|
||||
"dario.cat/mergo"
|
||||
)
|
||||
|
||||
## Usage
|
||||
@ -126,6 +118,39 @@ if err := mergo.Merge(&dst, src, mergo.WithOverride); err != nil {
|
||||
}
|
||||
```
|
||||
|
||||
If you need to override pointers, so the source pointer's value is assigned to the destination's pointer, you must use `WithoutDereference`:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"dario.cat/mergo"
|
||||
)
|
||||
|
||||
type Foo struct {
|
||||
A *string
|
||||
B int64
|
||||
}
|
||||
|
||||
func main() {
|
||||
first := "first"
|
||||
second := "second"
|
||||
src := Foo{
|
||||
A: &first,
|
||||
B: 2,
|
||||
}
|
||||
|
||||
dest := Foo{
|
||||
A: &second,
|
||||
B: 1,
|
||||
}
|
||||
|
||||
mergo.Merge(&dest, src, mergo.WithOverride, mergo.WithoutDereference)
|
||||
}
|
||||
```
|
||||
|
||||
Additionally, you can map a `map[string]interface{}` to a struct (and otherwise, from struct to map), following the same restrictions as in `Merge()`. Keys are capitalized to find each corresponding exported field.
|
||||
|
||||
```go
|
||||
@ -143,7 +168,7 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/imdario/mergo"
|
||||
"dario.cat/mergo"
|
||||
)
|
||||
|
||||
type Foo struct {
|
||||
@ -168,7 +193,7 @@ func main() {
|
||||
|
||||
Note: if test are failing due missing package, please execute:
|
||||
|
||||
go get gopkg.in/yaml.v2
|
||||
go get gopkg.in/yaml.v3
|
||||
|
||||
### Transformers
|
||||
|
||||
@ -179,9 +204,9 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/imdario/mergo"
|
||||
"reflect"
|
||||
"time"
|
||||
"dario.cat/mergo"
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
|
||||
type timeTransformer struct {
|
||||
@ -218,7 +243,6 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Contact me
|
||||
|
||||
If I can help you, you have an idea or you are using Mergo in your projects, don't hesitate to drop me a line (or a pull request): [@im_dario](https://twitter.com/im_dario)
|
||||
@ -227,21 +251,8 @@ If I can help you, you have an idea or you are using Mergo in your projects, don
|
||||
|
||||
Written by [Dario Castañé](http://dario.im).
|
||||
|
||||
## Top Contributors
|
||||
|
||||
[](https://sourcerer.io/fame/imdario/imdario/mergo/links/0)
|
||||
[](https://sourcerer.io/fame/imdario/imdario/mergo/links/1)
|
||||
[](https://sourcerer.io/fame/imdario/imdario/mergo/links/2)
|
||||
[](https://sourcerer.io/fame/imdario/imdario/mergo/links/3)
|
||||
[](https://sourcerer.io/fame/imdario/imdario/mergo/links/4)
|
||||
[](https://sourcerer.io/fame/imdario/imdario/mergo/links/5)
|
||||
[](https://sourcerer.io/fame/imdario/imdario/mergo/links/6)
|
||||
[](https://sourcerer.io/fame/imdario/imdario/mergo/links/7)
|
||||
|
||||
|
||||
## License
|
||||
|
||||
[BSD 3-Clause](http://opensource.org/licenses/BSD-3-Clause) license, as [Go language](http://golang.org/LICENSE).
|
||||
|
||||
|
||||
[](https://app.fossa.io/projects/git%2Bgithub.com%2Fimdario%2Fmergo?ref=badge_large)
|
14
vendor/dario.cat/mergo/SECURITY.md
vendored
Normal file
14
vendor/dario.cat/mergo/SECURITY.md
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
| Version | Supported |
|
||||
| ------- | ------------------ |
|
||||
| 0.3.x | :white_check_mark: |
|
||||
| < 0.3 | :x: |
|
||||
|
||||
## Security contact information
|
||||
|
||||
To report a security vulnerability, please use the
|
||||
[Tidelift security contact](https://tidelift.com/security).
|
||||
Tidelift will coordinate the fix and disclosure.
|
@ -8,30 +8,36 @@ A helper to merge structs and maps in Golang. Useful for configuration default v
|
||||
|
||||
Mergo merges same-type structs and maps by setting default values in zero-value fields. Mergo won't merge unexported (private) fields. It will do recursively any exported one. It also won't merge structs inside maps (because they are not addressable using Go reflection).
|
||||
|
||||
Status
|
||||
# Status
|
||||
|
||||
It is ready for production use. It is used in several projects by Docker, Google, The Linux Foundation, VMWare, Shopify, etc.
|
||||
|
||||
Important note
|
||||
# Important notes
|
||||
|
||||
1.0.0
|
||||
|
||||
In 1.0.0 Mergo moves to a vanity URL `dario.cat/mergo`.
|
||||
|
||||
0.3.9
|
||||
|
||||
Please keep in mind that a problematic PR broke 0.3.9. We reverted it in 0.3.10. We consider 0.3.10 as stable but not bug-free. . Also, this version adds suppot for go modules.
|
||||
|
||||
Keep in mind that in 0.3.2, Mergo changed Merge() and Map() signatures to support transformers. We added an optional/variadic argument so that it won't break the existing code.
|
||||
|
||||
If you were using Mergo before April 6th, 2015, please check your project works as intended after updating your local copy with go get -u github.com/imdario/mergo. I apologize for any issue caused by its previous behavior and any future bug that Mergo could cause in existing projects after the change (release 0.2.0).
|
||||
If you were using Mergo before April 6th, 2015, please check your project works as intended after updating your local copy with go get -u dario.cat/mergo. I apologize for any issue caused by its previous behavior and any future bug that Mergo could cause in existing projects after the change (release 0.2.0).
|
||||
|
||||
Install
|
||||
# Install
|
||||
|
||||
Do your usual installation procedure:
|
||||
|
||||
go get github.com/imdario/mergo
|
||||
go get dario.cat/mergo
|
||||
|
||||
// use in your .go code
|
||||
import (
|
||||
"github.com/imdario/mergo"
|
||||
)
|
||||
// use in your .go code
|
||||
import (
|
||||
"dario.cat/mergo"
|
||||
)
|
||||
|
||||
Usage
|
||||
# Usage
|
||||
|
||||
You can only merge same-type structs with exported fields initialized as zero value of their type and same-types maps. Mergo won't merge unexported (private) fields but will do recursively any exported one. It won't merge empty structs value as they are zero values too. Also, maps will be merged recursively except for structs inside maps (because they are not addressable using Go reflection).
|
||||
|
||||
@ -59,7 +65,7 @@ Here is a nice example:
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/imdario/mergo"
|
||||
"dario.cat/mergo"
|
||||
)
|
||||
|
||||
type Foo struct {
|
||||
@ -81,7 +87,7 @@ Here is a nice example:
|
||||
// {two 2}
|
||||
}
|
||||
|
||||
Transformers
|
||||
# Transformers
|
||||
|
||||
Transformers allow to merge specific types differently than in the default behavior. In other words, now you can customize how some types are merged. For example, time.Time is a struct; it doesn't have zero value but IsZero can return true because it has fields with zero value. How can we merge a non-zero time.Time?
|
||||
|
||||
@ -89,9 +95,9 @@ Transformers allow to merge specific types differently than in the default behav
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/imdario/mergo"
|
||||
"reflect"
|
||||
"time"
|
||||
"dario.cat/mergo"
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
|
||||
type timeTransformer struct {
|
||||
@ -127,17 +133,16 @@ Transformers allow to merge specific types differently than in the default behav
|
||||
// { 2018-01-12 01:15:00 +0000 UTC m=+0.000000001 }
|
||||
}
|
||||
|
||||
Contact me
|
||||
# Contact me
|
||||
|
||||
If I can help you, you have an idea or you are using Mergo in your projects, don't hesitate to drop me a line (or a pull request): https://twitter.com/im_dario
|
||||
|
||||
About
|
||||
# About
|
||||
|
||||
Written by Dario Castañé: https://da.rio.hn
|
||||
|
||||
License
|
||||
# License
|
||||
|
||||
BSD 3-Clause license, as Go language.
|
||||
|
||||
*/
|
||||
package mergo
|
@ -44,7 +44,7 @@ func deepMap(dst, src reflect.Value, visited map[uintptr]*visit, depth int, conf
|
||||
}
|
||||
}
|
||||
// Remember, remember...
|
||||
visited[h] = &visit{addr, typ, seen}
|
||||
visited[h] = &visit{typ, seen, addr}
|
||||
}
|
||||
zeroValue := reflect.Value{}
|
||||
switch dst.Kind() {
|
||||
@ -58,7 +58,7 @@ func deepMap(dst, src reflect.Value, visited map[uintptr]*visit, depth int, conf
|
||||
}
|
||||
fieldName := field.Name
|
||||
fieldName = changeInitialCase(fieldName, unicode.ToLower)
|
||||
if v, ok := dstMap[fieldName]; !ok || (isEmptyValue(reflect.ValueOf(v)) || overwrite) {
|
||||
if _, ok := dstMap[fieldName]; !ok || (!isEmptyValue(reflect.ValueOf(src.Field(i).Interface()), !config.ShouldNotDereference) && overwrite) || config.overwriteWithEmptyValue {
|
||||
dstMap[fieldName] = src.Field(i).Interface()
|
||||
}
|
||||
}
|
||||
@ -142,7 +142,7 @@ func MapWithOverwrite(dst, src interface{}, opts ...func(*Config)) error {
|
||||
|
||||
func _map(dst, src interface{}, opts ...func(*Config)) error {
|
||||
if dst != nil && reflect.ValueOf(dst).Kind() != reflect.Ptr {
|
||||
return ErrNonPointerAgument
|
||||
return ErrNonPointerArgument
|
||||
}
|
||||
var (
|
||||
vDst, vSrc reflect.Value
|
@ -38,10 +38,11 @@ func isExportedComponent(field *reflect.StructField) bool {
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
Transformers Transformers
|
||||
Overwrite bool
|
||||
ShouldNotDereference bool
|
||||
AppendSlice bool
|
||||
TypeCheck bool
|
||||
Transformers Transformers
|
||||
overwriteWithEmptyValue bool
|
||||
overwriteSliceWithEmptyValue bool
|
||||
sliceDeepCopy bool
|
||||
@ -76,10 +77,10 @@ func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, co
|
||||
}
|
||||
}
|
||||
// Remember, remember...
|
||||
visited[h] = &visit{addr, typ, seen}
|
||||
visited[h] = &visit{typ, seen, addr}
|
||||
}
|
||||
|
||||
if config.Transformers != nil && !isEmptyValue(dst) {
|
||||
if config.Transformers != nil && !isReflectNil(dst) && dst.IsValid() {
|
||||
if fn := config.Transformers.Transformer(dst.Type()); fn != nil {
|
||||
err = fn(dst, src)
|
||||
return
|
||||
@ -95,17 +96,22 @@ func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, co
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (isReflectNil(dst) || overwrite) && (!isEmptyValue(src) || overwriteWithEmptySrc) {
|
||||
if dst.CanSet() && (isReflectNil(dst) || overwrite) && (!isEmptyValue(src, !config.ShouldNotDereference) || overwriteWithEmptySrc) {
|
||||
dst.Set(src)
|
||||
}
|
||||
}
|
||||
case reflect.Map:
|
||||
if dst.IsNil() && !src.IsNil() {
|
||||
dst.Set(reflect.MakeMap(dst.Type()))
|
||||
if dst.CanSet() {
|
||||
dst.Set(reflect.MakeMap(dst.Type()))
|
||||
} else {
|
||||
dst = src
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if src.Kind() != reflect.Map {
|
||||
if overwrite {
|
||||
if overwrite && dst.CanSet() {
|
||||
dst.Set(src)
|
||||
}
|
||||
return
|
||||
@ -157,7 +163,7 @@ func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, co
|
||||
dstSlice = reflect.ValueOf(dstElement.Interface())
|
||||
}
|
||||
|
||||
if (!isEmptyValue(src) || overwriteWithEmptySrc || overwriteSliceWithEmptySrc) && (overwrite || isEmptyValue(dst)) && !config.AppendSlice && !sliceDeepCopy {
|
||||
if (!isEmptyValue(src, !config.ShouldNotDereference) || overwriteWithEmptySrc || overwriteSliceWithEmptySrc) && (overwrite || isEmptyValue(dst, !config.ShouldNotDereference)) && !config.AppendSlice && !sliceDeepCopy {
|
||||
if typeCheck && srcSlice.Type() != dstSlice.Type() {
|
||||
return fmt.Errorf("cannot override two slices with different type (%s, %s)", srcSlice.Type(), dstSlice.Type())
|
||||
}
|
||||
@ -189,22 +195,38 @@ func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, co
|
||||
dst.SetMapIndex(key, dstSlice)
|
||||
}
|
||||
}
|
||||
if dstElement.IsValid() && !isEmptyValue(dstElement) && (reflect.TypeOf(srcElement.Interface()).Kind() == reflect.Map || reflect.TypeOf(srcElement.Interface()).Kind() == reflect.Slice) {
|
||||
continue
|
||||
|
||||
if dstElement.IsValid() && !isEmptyValue(dstElement, !config.ShouldNotDereference) {
|
||||
if reflect.TypeOf(srcElement.Interface()).Kind() == reflect.Slice {
|
||||
continue
|
||||
}
|
||||
if reflect.TypeOf(srcElement.Interface()).Kind() == reflect.Map && reflect.TypeOf(dstElement.Interface()).Kind() == reflect.Map {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if srcElement.IsValid() && ((srcElement.Kind() != reflect.Ptr && overwrite) || !dstElement.IsValid() || isEmptyValue(dstElement)) {
|
||||
if srcElement.IsValid() && ((srcElement.Kind() != reflect.Ptr && overwrite) || !dstElement.IsValid() || isEmptyValue(dstElement, !config.ShouldNotDereference)) {
|
||||
if dst.IsNil() {
|
||||
dst.Set(reflect.MakeMap(dst.Type()))
|
||||
}
|
||||
dst.SetMapIndex(key, srcElement)
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that all keys in dst are deleted if they are not in src.
|
||||
if overwriteWithEmptySrc {
|
||||
for _, key := range dst.MapKeys() {
|
||||
srcElement := src.MapIndex(key)
|
||||
if !srcElement.IsValid() {
|
||||
dst.SetMapIndex(key, reflect.Value{})
|
||||
}
|
||||
}
|
||||
}
|
||||
case reflect.Slice:
|
||||
if !dst.CanSet() {
|
||||
break
|
||||
}
|
||||
if (!isEmptyValue(src) || overwriteWithEmptySrc || overwriteSliceWithEmptySrc) && (overwrite || isEmptyValue(dst)) && !config.AppendSlice && !sliceDeepCopy {
|
||||
if (!isEmptyValue(src, !config.ShouldNotDereference) || overwriteWithEmptySrc || overwriteSliceWithEmptySrc) && (overwrite || isEmptyValue(dst, !config.ShouldNotDereference)) && !config.AppendSlice && !sliceDeepCopy {
|
||||
dst.Set(src)
|
||||
} else if config.AppendSlice {
|
||||
if src.Type() != dst.Type() {
|
||||
@ -239,12 +261,18 @@ func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, co
|
||||
|
||||
if src.Kind() != reflect.Interface {
|
||||
if dst.IsNil() || (src.Kind() != reflect.Ptr && overwrite) {
|
||||
if dst.CanSet() && (overwrite || isEmptyValue(dst)) {
|
||||
if dst.CanSet() && (overwrite || isEmptyValue(dst, !config.ShouldNotDereference)) {
|
||||
dst.Set(src)
|
||||
}
|
||||
} else if src.Kind() == reflect.Ptr {
|
||||
if err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, config); err != nil {
|
||||
return
|
||||
if !config.ShouldNotDereference {
|
||||
if err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, config); err != nil {
|
||||
return
|
||||
}
|
||||
} else if src.Elem().Kind() != reflect.Struct {
|
||||
if overwriteWithEmptySrc || (overwrite && !src.IsNil()) || dst.IsNil() {
|
||||
dst.Set(src)
|
||||
}
|
||||
}
|
||||
} else if dst.Elem().Type() == src.Type() {
|
||||
if err = deepMerge(dst.Elem(), src, visited, depth+1, config); err != nil {
|
||||
@ -257,7 +285,7 @@ func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, co
|
||||
}
|
||||
|
||||
if dst.IsNil() || overwrite {
|
||||
if dst.CanSet() && (overwrite || isEmptyValue(dst)) {
|
||||
if dst.CanSet() && (overwrite || isEmptyValue(dst, !config.ShouldNotDereference)) {
|
||||
dst.Set(src)
|
||||
}
|
||||
break
|
||||
@ -270,7 +298,7 @@ func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, co
|
||||
break
|
||||
}
|
||||
default:
|
||||
mustSet := (isEmptyValue(dst) || overwrite) && (!isEmptyValue(src) || overwriteWithEmptySrc)
|
||||
mustSet := (isEmptyValue(dst, !config.ShouldNotDereference) || overwrite) && (!isEmptyValue(src, !config.ShouldNotDereference) || overwriteWithEmptySrc)
|
||||
if mustSet {
|
||||
if dst.CanSet() {
|
||||
dst.Set(src)
|
||||
@ -321,6 +349,12 @@ func WithOverrideEmptySlice(config *Config) {
|
||||
config.overwriteSliceWithEmptyValue = true
|
||||
}
|
||||
|
||||
// WithoutDereference prevents dereferencing pointers when evaluating whether they are empty
|
||||
// (i.e. a non-nil pointer is never considered empty).
|
||||
func WithoutDereference(config *Config) {
|
||||
config.ShouldNotDereference = true
|
||||
}
|
||||
|
||||
// WithAppendSlice will make merge append slices instead of overwriting it.
|
||||
func WithAppendSlice(config *Config) {
|
||||
config.AppendSlice = true
|
||||
@ -339,7 +373,7 @@ func WithSliceDeepCopy(config *Config) {
|
||||
|
||||
func merge(dst, src interface{}, opts ...func(*Config)) error {
|
||||
if dst != nil && reflect.ValueOf(dst).Kind() != reflect.Ptr {
|
||||
return ErrNonPointerAgument
|
||||
return ErrNonPointerArgument
|
||||
}
|
||||
var (
|
||||
vDst, vSrc reflect.Value
|
@ -17,10 +17,10 @@ import (
|
||||
var (
|
||||
ErrNilArguments = errors.New("src and dst must not be nil")
|
||||
ErrDifferentArgumentsTypes = errors.New("src and dst must be of same type")
|
||||
ErrNotSupported = errors.New("only structs and maps are supported")
|
||||
ErrNotSupported = errors.New("only structs, maps, and slices are supported")
|
||||
ErrExpectedMapAsDestination = errors.New("dst was expected to be a map")
|
||||
ErrExpectedStructAsDestination = errors.New("dst was expected to be a struct")
|
||||
ErrNonPointerAgument = errors.New("dst must be a pointer")
|
||||
ErrNonPointerArgument = errors.New("dst must be a pointer")
|
||||
)
|
||||
|
||||
// During deepMerge, must keep track of checks that are
|
||||
@ -28,13 +28,13 @@ var (
|
||||
// checks in progress are true when it reencounters them.
|
||||
// Visited are stored in a map indexed by 17 * a1 + a2;
|
||||
type visit struct {
|
||||
ptr uintptr
|
||||
typ reflect.Type
|
||||
next *visit
|
||||
ptr uintptr
|
||||
}
|
||||
|
||||
// From src/pkg/encoding/json/encode.go.
|
||||
func isEmptyValue(v reflect.Value) bool {
|
||||
func isEmptyValue(v reflect.Value, shouldDereference bool) bool {
|
||||
switch v.Kind() {
|
||||
case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
|
||||
return v.Len() == 0
|
||||
@ -50,7 +50,10 @@ func isEmptyValue(v reflect.Value) bool {
|
||||
if v.IsNil() {
|
||||
return true
|
||||
}
|
||||
return isEmptyValue(v.Elem())
|
||||
if shouldDereference {
|
||||
return isEmptyValue(v.Elem(), shouldDereference)
|
||||
}
|
||||
return false
|
||||
case reflect.Func:
|
||||
return v.IsNil()
|
||||
case reflect.Invalid:
|
||||
@ -65,7 +68,7 @@ func resolveValues(dst, src interface{}) (vDst, vSrc reflect.Value, err error) {
|
||||
return
|
||||
}
|
||||
vDst = reflect.ValueOf(dst).Elem()
|
||||
if vDst.Kind() != reflect.Struct && vDst.Kind() != reflect.Map {
|
||||
if vDst.Kind() != reflect.Struct && vDst.Kind() != reflect.Map && vDst.Kind() != reflect.Slice {
|
||||
err = ErrNotSupported
|
||||
return
|
||||
}
|
1
vendor/github.com/Microsoft/go-winio/.gitattributes
generated
vendored
Normal file
1
vendor/github.com/Microsoft/go-winio/.gitattributes
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
* text=auto eol=lf
|
10
vendor/github.com/Microsoft/go-winio/.gitignore
generated
vendored
Normal file
10
vendor/github.com/Microsoft/go-winio/.gitignore
generated
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
.vscode/
|
||||
|
||||
*.exe
|
||||
|
||||
# testing
|
||||
testdata
|
||||
|
||||
# go workspaces
|
||||
go.work
|
||||
go.work.sum
|
147
vendor/github.com/Microsoft/go-winio/.golangci.yml
generated
vendored
Normal file
147
vendor/github.com/Microsoft/go-winio/.golangci.yml
generated
vendored
Normal file
@ -0,0 +1,147 @@
|
||||
linters:
|
||||
enable:
|
||||
# style
|
||||
- containedctx # struct contains a context
|
||||
- dupl # duplicate code
|
||||
- errname # erorrs are named correctly
|
||||
- nolintlint # "//nolint" directives are properly explained
|
||||
- revive # golint replacement
|
||||
- unconvert # unnecessary conversions
|
||||
- wastedassign
|
||||
|
||||
# bugs, performance, unused, etc ...
|
||||
- contextcheck # function uses a non-inherited context
|
||||
- errorlint # errors not wrapped for 1.13
|
||||
- exhaustive # check exhaustiveness of enum switch statements
|
||||
- gofmt # files are gofmt'ed
|
||||
- gosec # security
|
||||
- nilerr # returns nil even with non-nil error
|
||||
- thelper # test helpers without t.Helper()
|
||||
- unparam # unused function params
|
||||
|
||||
issues:
|
||||
exclude-dirs:
|
||||
- pkg/etw/sample
|
||||
|
||||
exclude-rules:
|
||||
# err is very often shadowed in nested scopes
|
||||
- linters:
|
||||
- govet
|
||||
text: '^shadow: declaration of "err" shadows declaration'
|
||||
|
||||
# ignore long lines for skip autogen directives
|
||||
- linters:
|
||||
- revive
|
||||
text: "^line-length-limit: "
|
||||
source: "^//(go:generate|sys) "
|
||||
|
||||
#TODO: remove after upgrading to go1.18
|
||||
# ignore comment spacing for nolint and sys directives
|
||||
- linters:
|
||||
- revive
|
||||
text: "^comment-spacings: no space between comment delimiter and comment text"
|
||||
source: "//(cspell:|nolint:|sys |todo)"
|
||||
|
||||
# not on go 1.18 yet, so no any
|
||||
- linters:
|
||||
- revive
|
||||
text: "^use-any: since GO 1.18 'interface{}' can be replaced by 'any'"
|
||||
|
||||
# allow unjustified ignores of error checks in defer statements
|
||||
- linters:
|
||||
- nolintlint
|
||||
text: "^directive `//nolint:errcheck` should provide explanation"
|
||||
source: '^\s*defer '
|
||||
|
||||
# allow unjustified ignores of error lints for io.EOF
|
||||
- linters:
|
||||
- nolintlint
|
||||
text: "^directive `//nolint:errorlint` should provide explanation"
|
||||
source: '[=|!]= io.EOF'
|
||||
|
||||
|
||||
linters-settings:
|
||||
exhaustive:
|
||||
default-signifies-exhaustive: true
|
||||
govet:
|
||||
enable-all: true
|
||||
disable:
|
||||
# struct order is often for Win32 compat
|
||||
# also, ignore pointer bytes/GC issues for now until performance becomes an issue
|
||||
- fieldalignment
|
||||
nolintlint:
|
||||
require-explanation: true
|
||||
require-specific: true
|
||||
revive:
|
||||
# revive is more configurable than static check, so likely the preferred alternative to static-check
|
||||
# (once the perf issue is solved: https://github.com/golangci/golangci-lint/issues/2997)
|
||||
enable-all-rules:
|
||||
true
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md
|
||||
rules:
|
||||
# rules with required arguments
|
||||
- name: argument-limit
|
||||
disabled: true
|
||||
- name: banned-characters
|
||||
disabled: true
|
||||
- name: cognitive-complexity
|
||||
disabled: true
|
||||
- name: cyclomatic
|
||||
disabled: true
|
||||
- name: file-header
|
||||
disabled: true
|
||||
- name: function-length
|
||||
disabled: true
|
||||
- name: function-result-limit
|
||||
disabled: true
|
||||
- name: max-public-structs
|
||||
disabled: true
|
||||
# geneally annoying rules
|
||||
- name: add-constant # complains about any and all strings and integers
|
||||
disabled: true
|
||||
- name: confusing-naming # we frequently use "Foo()" and "foo()" together
|
||||
disabled: true
|
||||
- name: flag-parameter # excessive, and a common idiom we use
|
||||
disabled: true
|
||||
- name: unhandled-error # warns over common fmt.Print* and io.Close; rely on errcheck instead
|
||||
disabled: true
|
||||
# general config
|
||||
- name: line-length-limit
|
||||
arguments:
|
||||
- 140
|
||||
- name: var-naming
|
||||
arguments:
|
||||
- []
|
||||
- - CID
|
||||
- CRI
|
||||
- CTRD
|
||||
- DACL
|
||||
- DLL
|
||||
- DOS
|
||||
- ETW
|
||||
- FSCTL
|
||||
- GCS
|
||||
- GMSA
|
||||
- HCS
|
||||
- HV
|
||||
- IO
|
||||
- LCOW
|
||||
- LDAP
|
||||
- LPAC
|
||||
- LTSC
|
||||
- MMIO
|
||||
- NT
|
||||
- OCI
|
||||
- PMEM
|
||||
- PWSH
|
||||
- RX
|
||||
- SACl
|
||||
- SID
|
||||
- SMB
|
||||
- TX
|
||||
- VHD
|
||||
- VHDX
|
||||
- VMID
|
||||
- VPCI
|
||||
- WCOW
|
||||
- WIM
|
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
|
@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013 Mitchell Hashimoto
|
||||
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
|
||||
@ -9,13 +9,14 @@ 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 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.
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
89
vendor/github.com/Microsoft/go-winio/README.md
generated
vendored
Normal file
89
vendor/github.com/Microsoft/go-winio/README.md
generated
vendored
Normal file
@ -0,0 +1,89 @@
|
||||
# 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 [Microsoft CLA](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.
|
||||
|
||||
Additionally, the pull request pipeline requires the following steps to be performed before
|
||||
mergining.
|
||||
|
||||
### Code Sign-Off
|
||||
|
||||
We require that contributors sign their commits using [`git commit --signoff`][git-commit-s]
|
||||
to certify they either authored the work themselves or otherwise have permission to use it in this project.
|
||||
|
||||
A range of commits can be signed off using [`git rebase --signoff`][git-rebase-s].
|
||||
|
||||
Please see [the developer certificate](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.
|
||||
|
||||
### Linting
|
||||
|
||||
Code must pass a linting stage, which uses [`golangci-lint`][lint].
|
||||
The linting settings are stored in [`.golangci.yaml`](./.golangci.yaml), and can be run
|
||||
automatically with VSCode by adding the following to your workspace or folder settings:
|
||||
|
||||
```json
|
||||
"go.lintTool": "golangci-lint",
|
||||
"go.lintOnSave": "package",
|
||||
```
|
||||
|
||||
Additional editor [integrations options are also available][lint-ide].
|
||||
|
||||
Alternatively, `golangci-lint` can be [installed locally][lint-install] and run from the repo root:
|
||||
|
||||
```shell
|
||||
# use . or specify a path to only lint a package
|
||||
# to show all lint errors, use flags "--max-issues-per-linter=0 --max-same-issues=0"
|
||||
> golangci-lint run ./...
|
||||
```
|
||||
|
||||
### Go Generate
|
||||
|
||||
The pipeline checks that auto-generated code, via `go generate`, are up to date.
|
||||
|
||||
This can be done for the entire repo:
|
||||
|
||||
```shell
|
||||
> go generate ./...
|
||||
```
|
||||
|
||||
## 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][natefinch] for the inspiration for this library.
|
||||
See [npipe](https://github.com/natefinch/npipe) for another named pipe implementation.
|
||||
|
||||
[lint]: https://golangci-lint.run/
|
||||
[lint-ide]: https://golangci-lint.run/usage/integrations/#editor-integration
|
||||
[lint-install]: https://golangci-lint.run/usage/install/#local-installation
|
||||
|
||||
[git-commit-s]: https://git-scm.com/docs/git-commit#Documentation/git-commit.txt--s
|
||||
[git-rebase-s]: https://git-scm.com/docs/git-rebase#Documentation/git-rebase.txt---signoff
|
||||
|
||||
[natefinch]: https://github.com/natefinch
|
41
vendor/github.com/Microsoft/go-winio/SECURITY.md
generated
vendored
Normal file
41
vendor/github.com/Microsoft/go-winio/SECURITY.md
generated
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
<!-- BEGIN MICROSOFT SECURITY.MD V0.0.7 BLOCK -->
|
||||
|
||||
## Security
|
||||
|
||||
Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).
|
||||
|
||||
If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below.
|
||||
|
||||
## Reporting Security Issues
|
||||
|
||||
**Please do not report security vulnerabilities through public GitHub issues.**
|
||||
|
||||
Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report).
|
||||
|
||||
If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey).
|
||||
|
||||
You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc).
|
||||
|
||||
Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
|
||||
|
||||
* Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
|
||||
* Full paths of source file(s) related to the manifestation of the issue
|
||||
* The location of the affected source code (tag/branch/commit or direct URL)
|
||||
* Any special configuration required to reproduce the issue
|
||||
* Step-by-step instructions to reproduce the issue
|
||||
* Proof-of-concept or exploit code (if possible)
|
||||
* Impact of the issue, including how an attacker might exploit the issue
|
||||
|
||||
This information will help us triage your report more quickly.
|
||||
|
||||
If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs.
|
||||
|
||||
## Preferred Languages
|
||||
|
||||
We prefer all communications to be in English.
|
||||
|
||||
## Policy
|
||||
|
||||
Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd).
|
||||
|
||||
<!-- END MICROSOFT SECURITY.MD BLOCK -->
|
287
vendor/github.com/Microsoft/go-winio/backup.go
generated
vendored
Normal file
287
vendor/github.com/Microsoft/go-winio/backup.go
generated
vendored
Normal file
@ -0,0 +1,287 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package winio
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"runtime"
|
||||
"unicode/utf16"
|
||||
|
||||
"github.com/Microsoft/go-winio/internal/fs"
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
//sys backupRead(h windows.Handle, b []byte, bytesRead *uint32, abort bool, processSecurity bool, context *uintptr) (err error) = BackupRead
|
||||
//sys backupWrite(h windows.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 //revive:disable-line:var-naming ID, not Id
|
||||
BackupReparseData
|
||||
BackupSparseBlock
|
||||
BackupTxfsData
|
||||
)
|
||||
|
||||
const (
|
||||
StreamSparseAttributes = uint32(8)
|
||||
)
|
||||
|
||||
//nolint:revive // var-naming: ALL_CAPS
|
||||
const (
|
||||
WRITE_DAC = windows.WRITE_DAC
|
||||
WRITE_OWNER = windows.WRITE_OWNER
|
||||
ACCESS_SYSTEM_SECURITY = windows.ACCESS_SYSTEM_SECURITY
|
||||
)
|
||||
|
||||
// BackupHeader represents a backup stream of a file.
|
||||
type BackupHeader struct {
|
||||
//revive:disable-next-line:var-naming ID, not Id
|
||||
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 { //nolint:nestif // todo: flatten this
|
||||
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(io.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 = windows.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(windows.Handle(r.f.Fd()), b, &bytesRead, false, r.includeSecurity, &r.ctx)
|
||||
if err != nil {
|
||||
return 0, &os.PathError{Op: "BackupRead", Path: r.f.Name(), Err: 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(windows.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(windows.Handle(w.f.Fd()), b, &bytesWritten, false, w.includeSecurity, &w.ctx)
|
||||
if err != nil {
|
||||
return 0, &os.PathError{Op: "BackupWrite", Path: w.f.Name(), Err: 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(windows.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) {
|
||||
h, err := fs.CreateFile(path,
|
||||
fs.AccessMask(access),
|
||||
fs.FileShareMode(share),
|
||||
nil,
|
||||
fs.FileCreationDisposition(createmode),
|
||||
fs.FILE_FLAG_BACKUP_SEMANTICS|fs.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
|
||||
}
|
22
vendor/github.com/Microsoft/go-winio/doc.go
generated
vendored
Normal file
22
vendor/github.com/Microsoft/go-winio/doc.go
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
// This package provides utilities for efficiently performing Win32 IO operations in Go.
|
||||
// Currently, this package is provides support for genreal IO and management of
|
||||
// - named pipes
|
||||
// - files
|
||||
// - [Hyper-V sockets]
|
||||
//
|
||||
// This code is similar to Go's [net] package, and uses IO completion ports to avoid
|
||||
// blocking IO on system threads, allowing Go to reuse the thread to schedule other goroutines.
|
||||
//
|
||||
// This limits support to Windows Vista and newer operating systems.
|
||||
//
|
||||
// Additionally, this package provides support for:
|
||||
// - creating and managing GUIDs
|
||||
// - writing to [ETW]
|
||||
// - opening and manageing VHDs
|
||||
// - parsing [Windows Image files]
|
||||
// - auto-generating Win32 API code
|
||||
//
|
||||
// [Hyper-V sockets]: https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/user-guide/make-integration-service
|
||||
// [ETW]: https://docs.microsoft.com/en-us/windows-hardware/drivers/devtest/event-tracing-for-windows--etw-
|
||||
// [Windows Image files]: https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/work-with-windows-images
|
||||
package winio
|
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 ea, nb, err
|
||||
}
|
||||
|
||||
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, nb, err
|
||||
}
|
||||
|
||||
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 ea, nb, err
|
||||
}
|
||||
|
||||
// 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 eas, err
|
||||
}
|
||||
|
||||
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
|
||||
}
|
320
vendor/github.com/Microsoft/go-winio/file.go
generated
vendored
Normal file
320
vendor/github.com/Microsoft/go-winio/file.go
generated
vendored
Normal file
@ -0,0 +1,320 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package winio
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"runtime"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
//sys cancelIoEx(file windows.Handle, o *windows.Overlapped) (err error) = CancelIoEx
|
||||
//sys createIoCompletionPort(file windows.Handle, port windows.Handle, key uintptr, threadCount uint32) (newport windows.Handle, err error) = CreateIoCompletionPort
|
||||
//sys getQueuedCompletionStatus(port windows.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) = GetQueuedCompletionStatus
|
||||
//sys setFileCompletionNotificationModes(h windows.Handle, flags uint8) (err error) = SetFileCompletionNotificationModes
|
||||
//sys wsaGetOverlappedResult(h windows.Handle, o *windows.Overlapped, bytes *uint32, wait bool, flags *uint32) (err error) = ws2_32.WSAGetOverlappedResult
|
||||
|
||||
var (
|
||||
ErrFileClosed = errors.New("file has already been closed")
|
||||
ErrTimeout = &timeoutError{}
|
||||
)
|
||||
|
||||
type timeoutError struct{}
|
||||
|
||||
func (*timeoutError) Error() string { return "i/o timeout" }
|
||||
func (*timeoutError) Timeout() bool { return true }
|
||||
func (*timeoutError) Temporary() bool { return true }
|
||||
|
||||
type timeoutChan chan struct{}
|
||||
|
||||
var ioInitOnce sync.Once
|
||||
var ioCompletionPort windows.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 windows.Overlapped
|
||||
ch chan ioResult
|
||||
}
|
||||
|
||||
func initIO() {
|
||||
h, err := createIoCompletionPort(windows.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 windows.Handle
|
||||
wg sync.WaitGroup
|
||||
wgLock sync.RWMutex
|
||||
closing atomic.Bool
|
||||
socket bool
|
||||
readDeadline deadlineHandler
|
||||
writeDeadline deadlineHandler
|
||||
}
|
||||
|
||||
type deadlineHandler struct {
|
||||
setLock sync.Mutex
|
||||
channel timeoutChan
|
||||
channelLock sync.RWMutex
|
||||
timer *time.Timer
|
||||
timedout atomic.Bool
|
||||
}
|
||||
|
||||
// makeWin32File makes a new win32File from an existing file handle.
|
||||
func makeWin32File(h windows.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, windows.FILE_SKIP_COMPLETION_PORT_ON_SUCCESS|windows.FILE_SKIP_SET_EVENT_ON_HANDLE)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f.readDeadline.channel = make(timeoutChan)
|
||||
f.writeDeadline.channel = make(timeoutChan)
|
||||
return f, nil
|
||||
}
|
||||
|
||||
// Deprecated: use NewOpenFile instead.
|
||||
func MakeOpenFile(h syscall.Handle) (io.ReadWriteCloser, error) {
|
||||
return NewOpenFile(windows.Handle(h))
|
||||
}
|
||||
|
||||
func NewOpenFile(h windows.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
|
||||
windows.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.Load()
|
||||
}
|
||||
|
||||
// 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.Load() {
|
||||
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 windows.Handle) {
|
||||
for {
|
||||
var bytes uint32
|
||||
var key uintptr
|
||||
var op *ioOperation
|
||||
err := getQueuedCompletionStatus(h, &bytes, &key, &op, windows.INFINITE)
|
||||
if op == nil {
|
||||
panic(err)
|
||||
}
|
||||
op.ch <- ioResult{bytes, err}
|
||||
}
|
||||
}
|
||||
|
||||
// todo: helsaawy - create an asyncIO version that takes a context
|
||||
|
||||
// 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 != windows.ERROR_IO_PENDING { //nolint:errorlint // err is Errno
|
||||
return int(bytes), err
|
||||
}
|
||||
|
||||
if f.closing.Load() {
|
||||
_ = 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 == windows.ERROR_OPERATION_ABORTED { //nolint:errorlint // err is Errno
|
||||
if f.closing.Load() {
|
||||
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 == windows.ERROR_OPERATION_ABORTED { //nolint:errorlint // err is Errno
|
||||
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.
|
||||
// todo: (de)allocate *ioOperation via win32 heap functions, instead of needing to KeepAlive?
|
||||
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.Load() {
|
||||
return 0, ErrTimeout
|
||||
}
|
||||
|
||||
var bytes uint32
|
||||
err = windows.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 == windows.ERROR_BROKEN_PIPE { //nolint:errorlint // err is Errno
|
||||
return 0, io.EOF
|
||||
}
|
||||
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.Load() {
|
||||
return 0, ErrTimeout
|
||||
}
|
||||
|
||||
var bytes uint32
|
||||
err = windows.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 windows.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.Store(false)
|
||||
|
||||
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.Store(true)
|
||||
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
|
||||
}
|
106
vendor/github.com/Microsoft/go-winio/fileinfo.go
generated
vendored
Normal file
106
vendor/github.com/Microsoft/go-winio/fileinfo.go
generated
vendored
Normal file
@ -0,0 +1,106 @@
|
||||
//go:build windows
|
||||
// +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
|
||||
_ uint32 // padding
|
||||
}
|
||||
|
||||
// alignedFileBasicInfo is a FileBasicInfo, but aligned to uint64 by containing
|
||||
// uint64 rather than windows.Filetime. Filetime contains two uint32s. uint64
|
||||
// alignment is necessary to pass this as FILE_BASIC_INFO.
|
||||
type alignedFileBasicInfo struct {
|
||||
CreationTime, LastAccessTime, LastWriteTime, ChangeTime uint64
|
||||
FileAttributes uint32
|
||||
_ uint32 // padding
|
||||
}
|
||||
|
||||
// GetFileBasicInfo retrieves times and attributes for a file.
|
||||
func GetFileBasicInfo(f *os.File) (*FileBasicInfo, error) {
|
||||
bi := &alignedFileBasicInfo{}
|
||||
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)
|
||||
// Reinterpret the alignedFileBasicInfo as a FileBasicInfo so it matches the
|
||||
// public API of this module. The data may be unnecessarily aligned.
|
||||
return (*FileBasicInfo)(unsafe.Pointer(bi)), nil
|
||||
}
|
||||
|
||||
// SetFileBasicInfo sets times and attributes for a file.
|
||||
func SetFileBasicInfo(f *os.File, bi *FileBasicInfo) error {
|
||||
// Create an alignedFileBasicInfo based on a FileBasicInfo. The copy is
|
||||
// suitable to pass to GetFileInformationByHandleEx.
|
||||
biAligned := *(*alignedFileBasicInfo)(unsafe.Pointer(bi))
|
||||
if err := windows.SetFileInformationByHandle(
|
||||
windows.Handle(f.Fd()),
|
||||
windows.FileBasicInfo,
|
||||
(*byte)(unsafe.Pointer(&biAligned)),
|
||||
uint32(unsafe.Sizeof(biAligned)),
|
||||
); 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
|
||||
}
|
582
vendor/github.com/Microsoft/go-winio/hvsock.go
generated
vendored
Normal file
582
vendor/github.com/Microsoft/go-winio/hvsock.go
generated
vendored
Normal file
@ -0,0 +1,582 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package winio
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
|
||||
"github.com/Microsoft/go-winio/internal/socket"
|
||||
"github.com/Microsoft/go-winio/pkg/guid"
|
||||
)
|
||||
|
||||
const afHVSock = 34 // AF_HYPERV
|
||||
|
||||
// Well known Service and VM IDs
|
||||
// https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/user-guide/make-integration-service#vmid-wildcards
|
||||
|
||||
// HvsockGUIDWildcard is the wildcard VmId for accepting connections from all partitions.
|
||||
func HvsockGUIDWildcard() guid.GUID { // 00000000-0000-0000-0000-000000000000
|
||||
return guid.GUID{}
|
||||
}
|
||||
|
||||
// HvsockGUIDBroadcast is the wildcard VmId for broadcasting sends to all partitions.
|
||||
func HvsockGUIDBroadcast() guid.GUID { // ffffffff-ffff-ffff-ffff-ffffffffffff
|
||||
return guid.GUID{
|
||||
Data1: 0xffffffff,
|
||||
Data2: 0xffff,
|
||||
Data3: 0xffff,
|
||||
Data4: [8]uint8{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
|
||||
}
|
||||
}
|
||||
|
||||
// HvsockGUIDLoopback is the Loopback VmId for accepting connections to the same partition as the connector.
|
||||
func HvsockGUIDLoopback() guid.GUID { // e0e16197-dd56-4a10-9195-5ee7a155a838
|
||||
return guid.GUID{
|
||||
Data1: 0xe0e16197,
|
||||
Data2: 0xdd56,
|
||||
Data3: 0x4a10,
|
||||
Data4: [8]uint8{0x91, 0x95, 0x5e, 0xe7, 0xa1, 0x55, 0xa8, 0x38},
|
||||
}
|
||||
}
|
||||
|
||||
// HvsockGUIDSiloHost is the address of a silo's host partition:
|
||||
// - The silo host of a hosted silo is the utility VM.
|
||||
// - The silo host of a silo on a physical host is the physical host.
|
||||
func HvsockGUIDSiloHost() guid.GUID { // 36bd0c5c-7276-4223-88ba-7d03b654c568
|
||||
return guid.GUID{
|
||||
Data1: 0x36bd0c5c,
|
||||
Data2: 0x7276,
|
||||
Data3: 0x4223,
|
||||
Data4: [8]byte{0x88, 0xba, 0x7d, 0x03, 0xb6, 0x54, 0xc5, 0x68},
|
||||
}
|
||||
}
|
||||
|
||||
// HvsockGUIDChildren is the wildcard VmId for accepting connections from the connector's child partitions.
|
||||
func HvsockGUIDChildren() guid.GUID { // 90db8b89-0d35-4f79-8ce9-49ea0ac8b7cd
|
||||
return guid.GUID{
|
||||
Data1: 0x90db8b89,
|
||||
Data2: 0xd35,
|
||||
Data3: 0x4f79,
|
||||
Data4: [8]uint8{0x8c, 0xe9, 0x49, 0xea, 0xa, 0xc8, 0xb7, 0xcd},
|
||||
}
|
||||
}
|
||||
|
||||
// HvsockGUIDParent is the wildcard VmId for accepting connections from the connector's parent partition.
|
||||
// Listening on this VmId accepts connection from:
|
||||
// - Inside silos: silo host partition.
|
||||
// - Inside hosted silo: host of the VM.
|
||||
// - Inside VM: VM host.
|
||||
// - Physical host: Not supported.
|
||||
func HvsockGUIDParent() guid.GUID { // a42e7cda-d03f-480c-9cc2-a4de20abb878
|
||||
return guid.GUID{
|
||||
Data1: 0xa42e7cda,
|
||||
Data2: 0xd03f,
|
||||
Data3: 0x480c,
|
||||
Data4: [8]uint8{0x9c, 0xc2, 0xa4, 0xde, 0x20, 0xab, 0xb8, 0x78},
|
||||
}
|
||||
}
|
||||
|
||||
// hvsockVsockServiceTemplate is the Service GUID used for the VSOCK protocol.
|
||||
func hvsockVsockServiceTemplate() guid.GUID { // 00000000-facb-11e6-bd58-64006a7986d3
|
||||
return guid.GUID{
|
||||
Data2: 0xfacb,
|
||||
Data3: 0x11e6,
|
||||
Data4: [8]uint8{0xbd, 0x58, 0x64, 0x00, 0x6a, 0x79, 0x86, 0xd3},
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
var _ socket.RawSockaddr = &rawHvsockAddr{}
|
||||
|
||||
// Network returns the address's network name, "hvsock".
|
||||
func (*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 := hvsockVsockServiceTemplate() // make a copy
|
||||
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
|
||||
}
|
||||
|
||||
// Sockaddr returns a pointer to and the size of this struct.
|
||||
//
|
||||
// Implements the [socket.RawSockaddr] interface, and allows use in
|
||||
// [socket.Bind] and [socket.ConnectEx].
|
||||
func (r *rawHvsockAddr) Sockaddr() (unsafe.Pointer, int32, error) {
|
||||
return unsafe.Pointer(r), int32(unsafe.Sizeof(rawHvsockAddr{})), nil
|
||||
}
|
||||
|
||||
// Sockaddr interface allows use with `sockets.Bind()` and `.ConnectEx()`.
|
||||
func (r *rawHvsockAddr) FromBytes(b []byte) error {
|
||||
n := int(unsafe.Sizeof(rawHvsockAddr{}))
|
||||
|
||||
if len(b) < n {
|
||||
return fmt.Errorf("got %d, want %d: %w", len(b), n, socket.ErrBufferSize)
|
||||
}
|
||||
|
||||
copy(unsafe.Slice((*byte)(unsafe.Pointer(r)), n), b[:n])
|
||||
if r.Family != afHVSock {
|
||||
return fmt.Errorf("got %d, want %d: %w", r.Family, afHVSock, socket.ErrAddrFamily)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// HvsockListener is a socket listener for the AF_HYPERV address family.
|
||||
type HvsockListener struct {
|
||||
sock *win32File
|
||||
addr HvsockAddr
|
||||
}
|
||||
|
||||
var _ net.Listener = &HvsockListener{}
|
||||
|
||||
// HvsockConn is a connected socket of the AF_HYPERV address family.
|
||||
type HvsockConn struct {
|
||||
sock *win32File
|
||||
local, remote HvsockAddr
|
||||
}
|
||||
|
||||
var _ net.Conn = &HvsockConn{}
|
||||
|
||||
func newHVSocket() (*win32File, error) {
|
||||
fd, err := windows.Socket(afHVSock, windows.SOCK_STREAM, 1)
|
||||
if err != nil {
|
||||
return nil, os.NewSyscallError("socket", err)
|
||||
}
|
||||
f, err := makeWin32File(fd)
|
||||
if err != nil {
|
||||
windows.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}
|
||||
|
||||
var sock *win32File
|
||||
sock, err = newHVSocket()
|
||||
if err != nil {
|
||||
return nil, l.opErr("listen", err)
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
_ = sock.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
sa := addr.raw()
|
||||
err = socket.Bind(sock.handle, &sa)
|
||||
if err != nil {
|
||||
return nil, l.opErr("listen", os.NewSyscallError("socket", err))
|
||||
}
|
||||
err = windows.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.
|
||||
//
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/mswsock/nf-mswsock-acceptex
|
||||
const addrlen = uint32(16 + unsafe.Sizeof(rawHvsockAddr{}))
|
||||
var addrbuf [addrlen * 2]byte
|
||||
|
||||
var bytes uint32
|
||||
err = windows.AcceptEx(l.sock.handle, sock.handle, &addrbuf[0], 0 /* rxdatalen */, addrlen, addrlen, &bytes, &c.o)
|
||||
if _, err = l.sock.asyncIO(c, nil, bytes, err); err != nil {
|
||||
return nil, l.opErr("accept", os.NewSyscallError("acceptex", err))
|
||||
}
|
||||
|
||||
conn := &HvsockConn{
|
||||
sock: sock,
|
||||
}
|
||||
// The local address returned in the AcceptEx buffer is the same as the Listener socket's
|
||||
// address. However, the service GUID reported by GetSockName is different from the Listeners
|
||||
// socket, and is sometimes the same as the local address of the socket that dialed the
|
||||
// address, with the service GUID.Data1 incremented, but othertimes is different.
|
||||
// todo: does the local address matter? is the listener's address or the actual address appropriate?
|
||||
conn.local.fromRaw((*rawHvsockAddr)(unsafe.Pointer(&addrbuf[0])))
|
||||
conn.remote.fromRaw((*rawHvsockAddr)(unsafe.Pointer(&addrbuf[addrlen])))
|
||||
|
||||
// initialize the accepted socket and update its properties with those of the listening socket
|
||||
if err = windows.Setsockopt(sock.handle,
|
||||
windows.SOL_SOCKET, windows.SO_UPDATE_ACCEPT_CONTEXT,
|
||||
(*byte)(unsafe.Pointer(&l.sock.handle)), int32(unsafe.Sizeof(l.sock.handle))); err != nil {
|
||||
return nil, conn.opErr("accept", os.NewSyscallError("setsockopt", err))
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
// HvsockDialer configures and dials a Hyper-V Socket (ie, [HvsockConn]).
|
||||
type HvsockDialer struct {
|
||||
// Deadline is the time the Dial operation must connect before erroring.
|
||||
Deadline time.Time
|
||||
|
||||
// Retries is the number of additional connects to try if the connection times out, is refused,
|
||||
// or the host is unreachable
|
||||
Retries uint
|
||||
|
||||
// RetryWait is the time to wait after a connection error to retry
|
||||
RetryWait time.Duration
|
||||
|
||||
rt *time.Timer // redial wait timer
|
||||
}
|
||||
|
||||
// Dial the Hyper-V socket at addr.
|
||||
//
|
||||
// See [HvsockDialer.Dial] for more information.
|
||||
func Dial(ctx context.Context, addr *HvsockAddr) (conn *HvsockConn, err error) {
|
||||
return (&HvsockDialer{}).Dial(ctx, addr)
|
||||
}
|
||||
|
||||
// Dial attempts to connect to the Hyper-V socket at addr, and returns a connection if successful.
|
||||
// Will attempt (HvsockDialer).Retries if dialing fails, waiting (HvsockDialer).RetryWait between
|
||||
// retries.
|
||||
//
|
||||
// Dialing can be cancelled either by providing (HvsockDialer).Deadline, or cancelling ctx.
|
||||
func (d *HvsockDialer) Dial(ctx context.Context, addr *HvsockAddr) (conn *HvsockConn, err error) {
|
||||
op := "dial"
|
||||
// create the conn early to use opErr()
|
||||
conn = &HvsockConn{
|
||||
remote: *addr,
|
||||
}
|
||||
|
||||
if !d.Deadline.IsZero() {
|
||||
var cancel context.CancelFunc
|
||||
ctx, cancel = context.WithDeadline(ctx, d.Deadline)
|
||||
defer cancel()
|
||||
}
|
||||
|
||||
// preemptive timeout/cancellation check
|
||||
if err = ctx.Err(); err != nil {
|
||||
return nil, conn.opErr(op, err)
|
||||
}
|
||||
|
||||
sock, err := newHVSocket()
|
||||
if err != nil {
|
||||
return nil, conn.opErr(op, err)
|
||||
}
|
||||
defer func() {
|
||||
if sock != nil {
|
||||
sock.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
sa := addr.raw()
|
||||
err = socket.Bind(sock.handle, &sa)
|
||||
if err != nil {
|
||||
return nil, conn.opErr(op, os.NewSyscallError("bind", err))
|
||||
}
|
||||
|
||||
c, err := sock.prepareIO()
|
||||
if err != nil {
|
||||
return nil, conn.opErr(op, err)
|
||||
}
|
||||
defer sock.wg.Done()
|
||||
var bytes uint32
|
||||
for i := uint(0); i <= d.Retries; i++ {
|
||||
err = socket.ConnectEx(
|
||||
sock.handle,
|
||||
&sa,
|
||||
nil, // sendBuf
|
||||
0, // sendDataLen
|
||||
&bytes,
|
||||
(*windows.Overlapped)(unsafe.Pointer(&c.o)))
|
||||
_, err = sock.asyncIO(c, nil, bytes, err)
|
||||
if i < d.Retries && canRedial(err) {
|
||||
if err = d.redialWait(ctx); err == nil {
|
||||
continue
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return nil, conn.opErr(op, os.NewSyscallError("connectex", err))
|
||||
}
|
||||
|
||||
// update the connection properties, so shutdown can be used
|
||||
if err = windows.Setsockopt(
|
||||
sock.handle,
|
||||
windows.SOL_SOCKET,
|
||||
windows.SO_UPDATE_CONNECT_CONTEXT,
|
||||
nil, // optvalue
|
||||
0, // optlen
|
||||
); err != nil {
|
||||
return nil, conn.opErr(op, os.NewSyscallError("setsockopt", err))
|
||||
}
|
||||
|
||||
// get the local name
|
||||
var sal rawHvsockAddr
|
||||
err = socket.GetSockName(sock.handle, &sal)
|
||||
if err != nil {
|
||||
return nil, conn.opErr(op, os.NewSyscallError("getsockname", err))
|
||||
}
|
||||
conn.local.fromRaw(&sal)
|
||||
|
||||
// one last check for timeout, since asyncIO doesn't check the context
|
||||
if err = ctx.Err(); err != nil {
|
||||
return nil, conn.opErr(op, err)
|
||||
}
|
||||
|
||||
conn.sock = sock
|
||||
sock = nil
|
||||
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
// redialWait waits before attempting to redial, resetting the timer as appropriate.
|
||||
func (d *HvsockDialer) redialWait(ctx context.Context) (err error) {
|
||||
if d.RetryWait == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if d.rt == nil {
|
||||
d.rt = time.NewTimer(d.RetryWait)
|
||||
} else {
|
||||
// should already be stopped and drained
|
||||
d.rt.Reset(d.RetryWait)
|
||||
}
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
case <-d.rt.C:
|
||||
return nil
|
||||
}
|
||||
|
||||
// stop and drain the timer
|
||||
if !d.rt.Stop() {
|
||||
<-d.rt.C
|
||||
}
|
||||
return ctx.Err()
|
||||
}
|
||||
|
||||
// assumes error is a plain, unwrapped windows.Errno provided by direct syscall.
|
||||
func canRedial(err error) bool {
|
||||
//nolint:errorlint // guaranteed to be an Errno
|
||||
switch err {
|
||||
case windows.WSAECONNREFUSED, windows.WSAENETUNREACH, windows.WSAETIMEDOUT,
|
||||
windows.ERROR_CONNECTION_REFUSED, windows.ERROR_CONNECTION_UNAVAIL:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (conn *HvsockConn) opErr(op string, err error) error {
|
||||
// translate from "file closed" to "socket closed"
|
||||
if errors.Is(err, ErrFileClosed) {
|
||||
err = socket.ErrSocketClosed
|
||||
}
|
||||
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 := windows.WSABuf{Buf: &b[0], Len: uint32(len(b))}
|
||||
var flags, bytes uint32
|
||||
err = windows.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 {
|
||||
var eno windows.Errno
|
||||
if errors.As(err, &eno) {
|
||||
err = os.NewSyscallError("wsarecv", eno)
|
||||
}
|
||||
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 := windows.WSABuf{Buf: &b[0], Len: uint32(len(b))}
|
||||
var bytes uint32
|
||||
err = windows.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 {
|
||||
var eno windows.Errno
|
||||
if errors.As(err, &eno) {
|
||||
err = os.NewSyscallError("wsasend", eno)
|
||||
}
|
||||
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()
|
||||
}
|
||||
|
||||
// shutdown disables sending or receiving on a socket.
|
||||
func (conn *HvsockConn) shutdown(how int) error {
|
||||
if conn.IsClosed() {
|
||||
return socket.ErrSocketClosed
|
||||
}
|
||||
|
||||
err := windows.Shutdown(conn.sock.handle, how)
|
||||
if err != nil {
|
||||
// If the connection was closed, shutdowns fail with "not connected"
|
||||
if errors.Is(err, windows.WSAENOTCONN) ||
|
||||
errors.Is(err, windows.WSAESHUTDOWN) {
|
||||
err = socket.ErrSocketClosed
|
||||
}
|
||||
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(windows.SHUT_RD)
|
||||
if err != nil {
|
||||
return conn.opErr("closeread", 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(windows.SHUT_WR)
|
||||
if err != nil {
|
||||
return conn.opErr("closewrite", 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 {
|
||||
// todo: implement `SetDeadline` for `win32File`
|
||||
if err := conn.SetReadDeadline(t); err != nil {
|
||||
return fmt.Errorf("set read deadline: %w", err)
|
||||
}
|
||||
if err := conn.SetWriteDeadline(t); err != nil {
|
||||
return fmt.Errorf("set write deadline: %w", err)
|
||||
}
|
||||
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)
|
||||
}
|
2
vendor/github.com/Microsoft/go-winio/internal/fs/doc.go
generated
vendored
Normal file
2
vendor/github.com/Microsoft/go-winio/internal/fs/doc.go
generated
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
// This package contains Win32 filesystem functionality.
|
||||
package fs
|
262
vendor/github.com/Microsoft/go-winio/internal/fs/fs.go
generated
vendored
Normal file
262
vendor/github.com/Microsoft/go-winio/internal/fs/fs.go
generated
vendored
Normal file
@ -0,0 +1,262 @@
|
||||
//go:build windows
|
||||
|
||||
package fs
|
||||
|
||||
import (
|
||||
"golang.org/x/sys/windows"
|
||||
|
||||
"github.com/Microsoft/go-winio/internal/stringbuffer"
|
||||
)
|
||||
|
||||
//go:generate go run github.com/Microsoft/go-winio/tools/mkwinsyscall -output zsyscall_windows.go fs.go
|
||||
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew
|
||||
//sys CreateFile(name string, access AccessMask, mode FileShareMode, sa *windows.SecurityAttributes, createmode FileCreationDisposition, attrs FileFlagOrAttribute, templatefile windows.Handle) (handle windows.Handle, err error) [failretval==windows.InvalidHandle] = CreateFileW
|
||||
|
||||
const NullHandle windows.Handle = 0
|
||||
|
||||
// AccessMask defines standard, specific, and generic rights.
|
||||
//
|
||||
// Used with CreateFile and NtCreateFile (and co.).
|
||||
//
|
||||
// Bitmask:
|
||||
// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
|
||||
// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
|
||||
// +---------------+---------------+-------------------------------+
|
||||
// |G|G|G|G|Resvd|A| StandardRights| SpecificRights |
|
||||
// |R|W|E|A| |S| | |
|
||||
// +-+-------------+---------------+-------------------------------+
|
||||
//
|
||||
// GR Generic Read
|
||||
// GW Generic Write
|
||||
// GE Generic Exectue
|
||||
// GA Generic All
|
||||
// Resvd Reserved
|
||||
// AS Access Security System
|
||||
//
|
||||
// https://learn.microsoft.com/en-us/windows/win32/secauthz/access-mask
|
||||
//
|
||||
// https://learn.microsoft.com/en-us/windows/win32/secauthz/generic-access-rights
|
||||
//
|
||||
// https://learn.microsoft.com/en-us/windows/win32/fileio/file-access-rights-constants
|
||||
type AccessMask = windows.ACCESS_MASK
|
||||
|
||||
//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
|
||||
const (
|
||||
// Not actually any.
|
||||
//
|
||||
// For CreateFile: "query certain metadata such as file, directory, or device attributes without accessing that file or device"
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew#parameters
|
||||
FILE_ANY_ACCESS AccessMask = 0
|
||||
|
||||
GENERIC_READ AccessMask = 0x8000_0000
|
||||
GENERIC_WRITE AccessMask = 0x4000_0000
|
||||
GENERIC_EXECUTE AccessMask = 0x2000_0000
|
||||
GENERIC_ALL AccessMask = 0x1000_0000
|
||||
ACCESS_SYSTEM_SECURITY AccessMask = 0x0100_0000
|
||||
|
||||
// Specific Object Access
|
||||
// from ntioapi.h
|
||||
|
||||
FILE_READ_DATA AccessMask = (0x0001) // file & pipe
|
||||
FILE_LIST_DIRECTORY AccessMask = (0x0001) // directory
|
||||
|
||||
FILE_WRITE_DATA AccessMask = (0x0002) // file & pipe
|
||||
FILE_ADD_FILE AccessMask = (0x0002) // directory
|
||||
|
||||
FILE_APPEND_DATA AccessMask = (0x0004) // file
|
||||
FILE_ADD_SUBDIRECTORY AccessMask = (0x0004) // directory
|
||||
FILE_CREATE_PIPE_INSTANCE AccessMask = (0x0004) // named pipe
|
||||
|
||||
FILE_READ_EA AccessMask = (0x0008) // file & directory
|
||||
FILE_READ_PROPERTIES AccessMask = FILE_READ_EA
|
||||
|
||||
FILE_WRITE_EA AccessMask = (0x0010) // file & directory
|
||||
FILE_WRITE_PROPERTIES AccessMask = FILE_WRITE_EA
|
||||
|
||||
FILE_EXECUTE AccessMask = (0x0020) // file
|
||||
FILE_TRAVERSE AccessMask = (0x0020) // directory
|
||||
|
||||
FILE_DELETE_CHILD AccessMask = (0x0040) // directory
|
||||
|
||||
FILE_READ_ATTRIBUTES AccessMask = (0x0080) // all
|
||||
|
||||
FILE_WRITE_ATTRIBUTES AccessMask = (0x0100) // all
|
||||
|
||||
FILE_ALL_ACCESS AccessMask = (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1FF)
|
||||
FILE_GENERIC_READ AccessMask = (STANDARD_RIGHTS_READ | FILE_READ_DATA | FILE_READ_ATTRIBUTES | FILE_READ_EA | SYNCHRONIZE)
|
||||
FILE_GENERIC_WRITE AccessMask = (STANDARD_RIGHTS_WRITE | FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | FILE_APPEND_DATA | SYNCHRONIZE)
|
||||
FILE_GENERIC_EXECUTE AccessMask = (STANDARD_RIGHTS_EXECUTE | FILE_READ_ATTRIBUTES | FILE_EXECUTE | SYNCHRONIZE)
|
||||
|
||||
SPECIFIC_RIGHTS_ALL AccessMask = 0x0000FFFF
|
||||
|
||||
// Standard Access
|
||||
// from ntseapi.h
|
||||
|
||||
DELETE AccessMask = 0x0001_0000
|
||||
READ_CONTROL AccessMask = 0x0002_0000
|
||||
WRITE_DAC AccessMask = 0x0004_0000
|
||||
WRITE_OWNER AccessMask = 0x0008_0000
|
||||
SYNCHRONIZE AccessMask = 0x0010_0000
|
||||
|
||||
STANDARD_RIGHTS_REQUIRED AccessMask = 0x000F_0000
|
||||
|
||||
STANDARD_RIGHTS_READ AccessMask = READ_CONTROL
|
||||
STANDARD_RIGHTS_WRITE AccessMask = READ_CONTROL
|
||||
STANDARD_RIGHTS_EXECUTE AccessMask = READ_CONTROL
|
||||
|
||||
STANDARD_RIGHTS_ALL AccessMask = 0x001F_0000
|
||||
)
|
||||
|
||||
type FileShareMode uint32
|
||||
|
||||
//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
|
||||
const (
|
||||
FILE_SHARE_NONE FileShareMode = 0x00
|
||||
FILE_SHARE_READ FileShareMode = 0x01
|
||||
FILE_SHARE_WRITE FileShareMode = 0x02
|
||||
FILE_SHARE_DELETE FileShareMode = 0x04
|
||||
FILE_SHARE_VALID_FLAGS FileShareMode = 0x07
|
||||
)
|
||||
|
||||
type FileCreationDisposition uint32
|
||||
|
||||
//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
|
||||
const (
|
||||
// from winbase.h
|
||||
|
||||
CREATE_NEW FileCreationDisposition = 0x01
|
||||
CREATE_ALWAYS FileCreationDisposition = 0x02
|
||||
OPEN_EXISTING FileCreationDisposition = 0x03
|
||||
OPEN_ALWAYS FileCreationDisposition = 0x04
|
||||
TRUNCATE_EXISTING FileCreationDisposition = 0x05
|
||||
)
|
||||
|
||||
// Create disposition values for NtCreate*
|
||||
type NTFileCreationDisposition uint32
|
||||
|
||||
//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
|
||||
const (
|
||||
// From ntioapi.h
|
||||
|
||||
FILE_SUPERSEDE NTFileCreationDisposition = 0x00
|
||||
FILE_OPEN NTFileCreationDisposition = 0x01
|
||||
FILE_CREATE NTFileCreationDisposition = 0x02
|
||||
FILE_OPEN_IF NTFileCreationDisposition = 0x03
|
||||
FILE_OVERWRITE NTFileCreationDisposition = 0x04
|
||||
FILE_OVERWRITE_IF NTFileCreationDisposition = 0x05
|
||||
FILE_MAXIMUM_DISPOSITION NTFileCreationDisposition = 0x05
|
||||
)
|
||||
|
||||
// CreateFile and co. take flags or attributes together as one parameter.
|
||||
// Define alias until we can use generics to allow both
|
||||
//
|
||||
// https://learn.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants
|
||||
type FileFlagOrAttribute uint32
|
||||
|
||||
//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
|
||||
const (
|
||||
// from winnt.h
|
||||
|
||||
FILE_FLAG_WRITE_THROUGH FileFlagOrAttribute = 0x8000_0000
|
||||
FILE_FLAG_OVERLAPPED FileFlagOrAttribute = 0x4000_0000
|
||||
FILE_FLAG_NO_BUFFERING FileFlagOrAttribute = 0x2000_0000
|
||||
FILE_FLAG_RANDOM_ACCESS FileFlagOrAttribute = 0x1000_0000
|
||||
FILE_FLAG_SEQUENTIAL_SCAN FileFlagOrAttribute = 0x0800_0000
|
||||
FILE_FLAG_DELETE_ON_CLOSE FileFlagOrAttribute = 0x0400_0000
|
||||
FILE_FLAG_BACKUP_SEMANTICS FileFlagOrAttribute = 0x0200_0000
|
||||
FILE_FLAG_POSIX_SEMANTICS FileFlagOrAttribute = 0x0100_0000
|
||||
FILE_FLAG_OPEN_REPARSE_POINT FileFlagOrAttribute = 0x0020_0000
|
||||
FILE_FLAG_OPEN_NO_RECALL FileFlagOrAttribute = 0x0010_0000
|
||||
FILE_FLAG_FIRST_PIPE_INSTANCE FileFlagOrAttribute = 0x0008_0000
|
||||
)
|
||||
|
||||
// NtCreate* functions take a dedicated CreateOptions parameter.
|
||||
//
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/Winternl/nf-winternl-ntcreatefile
|
||||
//
|
||||
// https://learn.microsoft.com/en-us/windows/win32/devnotes/nt-create-named-pipe-file
|
||||
type NTCreateOptions uint32
|
||||
|
||||
//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
|
||||
const (
|
||||
// From ntioapi.h
|
||||
|
||||
FILE_DIRECTORY_FILE NTCreateOptions = 0x0000_0001
|
||||
FILE_WRITE_THROUGH NTCreateOptions = 0x0000_0002
|
||||
FILE_SEQUENTIAL_ONLY NTCreateOptions = 0x0000_0004
|
||||
FILE_NO_INTERMEDIATE_BUFFERING NTCreateOptions = 0x0000_0008
|
||||
|
||||
FILE_SYNCHRONOUS_IO_ALERT NTCreateOptions = 0x0000_0010
|
||||
FILE_SYNCHRONOUS_IO_NONALERT NTCreateOptions = 0x0000_0020
|
||||
FILE_NON_DIRECTORY_FILE NTCreateOptions = 0x0000_0040
|
||||
FILE_CREATE_TREE_CONNECTION NTCreateOptions = 0x0000_0080
|
||||
|
||||
FILE_COMPLETE_IF_OPLOCKED NTCreateOptions = 0x0000_0100
|
||||
FILE_NO_EA_KNOWLEDGE NTCreateOptions = 0x0000_0200
|
||||
FILE_DISABLE_TUNNELING NTCreateOptions = 0x0000_0400
|
||||
FILE_RANDOM_ACCESS NTCreateOptions = 0x0000_0800
|
||||
|
||||
FILE_DELETE_ON_CLOSE NTCreateOptions = 0x0000_1000
|
||||
FILE_OPEN_BY_FILE_ID NTCreateOptions = 0x0000_2000
|
||||
FILE_OPEN_FOR_BACKUP_INTENT NTCreateOptions = 0x0000_4000
|
||||
FILE_NO_COMPRESSION NTCreateOptions = 0x0000_8000
|
||||
)
|
||||
|
||||
type FileSQSFlag = FileFlagOrAttribute
|
||||
|
||||
//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
|
||||
const (
|
||||
// from winbase.h
|
||||
|
||||
SECURITY_ANONYMOUS FileSQSFlag = FileSQSFlag(SecurityAnonymous << 16)
|
||||
SECURITY_IDENTIFICATION FileSQSFlag = FileSQSFlag(SecurityIdentification << 16)
|
||||
SECURITY_IMPERSONATION FileSQSFlag = FileSQSFlag(SecurityImpersonation << 16)
|
||||
SECURITY_DELEGATION FileSQSFlag = FileSQSFlag(SecurityDelegation << 16)
|
||||
|
||||
SECURITY_SQOS_PRESENT FileSQSFlag = 0x0010_0000
|
||||
SECURITY_VALID_SQOS_FLAGS FileSQSFlag = 0x001F_0000
|
||||
)
|
||||
|
||||
// GetFinalPathNameByHandle flags
|
||||
//
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfinalpathnamebyhandlew#parameters
|
||||
type GetFinalPathFlag uint32
|
||||
|
||||
//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
|
||||
const (
|
||||
GetFinalPathDefaultFlag GetFinalPathFlag = 0x0
|
||||
|
||||
FILE_NAME_NORMALIZED GetFinalPathFlag = 0x0
|
||||
FILE_NAME_OPENED GetFinalPathFlag = 0x8
|
||||
|
||||
VOLUME_NAME_DOS GetFinalPathFlag = 0x0
|
||||
VOLUME_NAME_GUID GetFinalPathFlag = 0x1
|
||||
VOLUME_NAME_NT GetFinalPathFlag = 0x2
|
||||
VOLUME_NAME_NONE GetFinalPathFlag = 0x4
|
||||
)
|
||||
|
||||
// getFinalPathNameByHandle facilitates calling the Windows API GetFinalPathNameByHandle
|
||||
// with the given handle and flags. It transparently takes care of creating a buffer of the
|
||||
// correct size for the call.
|
||||
//
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfinalpathnamebyhandlew
|
||||
func GetFinalPathNameByHandle(h windows.Handle, flags GetFinalPathFlag) (string, error) {
|
||||
b := stringbuffer.NewWString()
|
||||
//TODO: can loop infinitely if Win32 keeps returning the same (or a larger) n?
|
||||
for {
|
||||
n, err := windows.GetFinalPathNameByHandle(h, b.Pointer(), b.Cap(), uint32(flags))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
// If the buffer wasn't large enough, n will be the total size needed (including null terminator).
|
||||
// Resize and try again.
|
||||
if n > b.Cap() {
|
||||
b.ResizeTo(n)
|
||||
continue
|
||||
}
|
||||
// If the buffer is large enough, n will be the size not including the null terminator.
|
||||
// Convert to a Go string and return.
|
||||
return b.String(), nil
|
||||
}
|
||||
}
|
12
vendor/github.com/Microsoft/go-winio/internal/fs/security.go
generated
vendored
Normal file
12
vendor/github.com/Microsoft/go-winio/internal/fs/security.go
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
package fs
|
||||
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ne-winnt-security_impersonation_level
|
||||
type SecurityImpersonationLevel int32 // C default enums underlying type is `int`, which is Go `int32`
|
||||
|
||||
// Impersonation levels
|
||||
const (
|
||||
SecurityAnonymous SecurityImpersonationLevel = 0
|
||||
SecurityIdentification SecurityImpersonationLevel = 1
|
||||
SecurityImpersonation SecurityImpersonationLevel = 2
|
||||
SecurityDelegation SecurityImpersonationLevel = 3
|
||||
)
|
61
vendor/github.com/Microsoft/go-winio/internal/fs/zsyscall_windows.go
generated
vendored
Normal file
61
vendor/github.com/Microsoft/go-winio/internal/fs/zsyscall_windows.go
generated
vendored
Normal file
@ -0,0 +1,61 @@
|
||||
//go:build windows
|
||||
|
||||
// Code generated by 'go generate' using "github.com/Microsoft/go-winio/tools/mkwinsyscall"; DO NOT EDIT.
|
||||
|
||||
package fs
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
var _ unsafe.Pointer
|
||||
|
||||
// Do the interface allocations only once for common
|
||||
// Errno values.
|
||||
const (
|
||||
errnoERROR_IO_PENDING = 997
|
||||
)
|
||||
|
||||
var (
|
||||
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
|
||||
errERROR_EINVAL error = syscall.EINVAL
|
||||
)
|
||||
|
||||
// errnoErr returns common boxed Errno values, to prevent
|
||||
// allocations at runtime.
|
||||
func errnoErr(e syscall.Errno) error {
|
||||
switch e {
|
||||
case 0:
|
||||
return errERROR_EINVAL
|
||||
case errnoERROR_IO_PENDING:
|
||||
return errERROR_IO_PENDING
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
var (
|
||||
modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
|
||||
|
||||
procCreateFileW = modkernel32.NewProc("CreateFileW")
|
||||
)
|
||||
|
||||
func CreateFile(name string, access AccessMask, mode FileShareMode, sa *windows.SecurityAttributes, createmode FileCreationDisposition, attrs FileFlagOrAttribute, templatefile windows.Handle) (handle windows.Handle, err error) {
|
||||
var _p0 *uint16
|
||||
_p0, err = syscall.UTF16PtrFromString(name)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return _CreateFile(_p0, access, mode, sa, createmode, attrs, templatefile)
|
||||
}
|
||||
|
||||
func _CreateFile(name *uint16, access AccessMask, mode FileShareMode, sa *windows.SecurityAttributes, createmode FileCreationDisposition, attrs FileFlagOrAttribute, templatefile windows.Handle) (handle windows.Handle, err error) {
|
||||
r0, _, e1 := syscall.SyscallN(procCreateFileW.Addr(), uintptr(unsafe.Pointer(name)), uintptr(access), uintptr(mode), uintptr(unsafe.Pointer(sa)), uintptr(createmode), uintptr(attrs), uintptr(templatefile))
|
||||
handle = windows.Handle(r0)
|
||||
if handle == windows.InvalidHandle {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
20
vendor/github.com/Microsoft/go-winio/internal/socket/rawaddr.go
generated
vendored
Normal file
20
vendor/github.com/Microsoft/go-winio/internal/socket/rawaddr.go
generated
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
package socket
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// RawSockaddr allows structs to be used with [Bind] and [ConnectEx]. The
|
||||
// struct must meet the Win32 sockaddr requirements specified here:
|
||||
// https://docs.microsoft.com/en-us/windows/win32/winsock/sockaddr-2
|
||||
//
|
||||
// Specifically, the struct size must be least larger than an int16 (unsigned short)
|
||||
// for the address family.
|
||||
type RawSockaddr interface {
|
||||
// Sockaddr returns a pointer to the RawSockaddr and its struct size, allowing
|
||||
// for the RawSockaddr's data to be overwritten by syscalls (if necessary).
|
||||
//
|
||||
// It is the callers responsibility to validate that the values are valid; invalid
|
||||
// pointers or size can cause a panic.
|
||||
Sockaddr() (unsafe.Pointer, int32, error)
|
||||
}
|
177
vendor/github.com/Microsoft/go-winio/internal/socket/socket.go
generated
vendored
Normal file
177
vendor/github.com/Microsoft/go-winio/internal/socket/socket.go
generated
vendored
Normal file
@ -0,0 +1,177 @@
|
||||
//go:build windows
|
||||
|
||||
package socket
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"sync"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"github.com/Microsoft/go-winio/pkg/guid"
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
//go:generate go run github.com/Microsoft/go-winio/tools/mkwinsyscall -output zsyscall_windows.go socket.go
|
||||
|
||||
//sys getsockname(s windows.Handle, name unsafe.Pointer, namelen *int32) (err error) [failretval==socketError] = ws2_32.getsockname
|
||||
//sys getpeername(s windows.Handle, name unsafe.Pointer, namelen *int32) (err error) [failretval==socketError] = ws2_32.getpeername
|
||||
//sys bind(s windows.Handle, name unsafe.Pointer, namelen int32) (err error) [failretval==socketError] = ws2_32.bind
|
||||
|
||||
const socketError = uintptr(^uint32(0))
|
||||
|
||||
var (
|
||||
// todo(helsaawy): create custom error types to store the desired vs actual size and addr family?
|
||||
|
||||
ErrBufferSize = errors.New("buffer size")
|
||||
ErrAddrFamily = errors.New("address family")
|
||||
ErrInvalidPointer = errors.New("invalid pointer")
|
||||
ErrSocketClosed = fmt.Errorf("socket closed: %w", net.ErrClosed)
|
||||
)
|
||||
|
||||
// todo(helsaawy): replace these with generics, ie: GetSockName[S RawSockaddr](s windows.Handle) (S, error)
|
||||
|
||||
// GetSockName writes the local address of socket s to the [RawSockaddr] rsa.
|
||||
// If rsa is not large enough, the [windows.WSAEFAULT] is returned.
|
||||
func GetSockName(s windows.Handle, rsa RawSockaddr) error {
|
||||
ptr, l, err := rsa.Sockaddr()
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not retrieve socket pointer and size: %w", err)
|
||||
}
|
||||
|
||||
// although getsockname returns WSAEFAULT if the buffer is too small, it does not set
|
||||
// &l to the correct size, so--apart from doubling the buffer repeatedly--there is no remedy
|
||||
return getsockname(s, ptr, &l)
|
||||
}
|
||||
|
||||
// GetPeerName returns the remote address the socket is connected to.
|
||||
//
|
||||
// See [GetSockName] for more information.
|
||||
func GetPeerName(s windows.Handle, rsa RawSockaddr) error {
|
||||
ptr, l, err := rsa.Sockaddr()
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not retrieve socket pointer and size: %w", err)
|
||||
}
|
||||
|
||||
return getpeername(s, ptr, &l)
|
||||
}
|
||||
|
||||
func Bind(s windows.Handle, rsa RawSockaddr) (err error) {
|
||||
ptr, l, err := rsa.Sockaddr()
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not retrieve socket pointer and size: %w", err)
|
||||
}
|
||||
|
||||
return bind(s, ptr, l)
|
||||
}
|
||||
|
||||
// "golang.org/x/sys/windows".ConnectEx and .Bind only accept internal implementations of the
|
||||
// their sockaddr interface, so they cannot be used with HvsockAddr
|
||||
// Replicate functionality here from
|
||||
// https://cs.opensource.google/go/x/sys/+/master:windows/syscall_windows.go
|
||||
|
||||
// The function pointers to `AcceptEx`, `ConnectEx` and `GetAcceptExSockaddrs` must be loaded at
|
||||
// runtime via a WSAIoctl call:
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/Mswsock/nc-mswsock-lpfn_connectex#remarks
|
||||
|
||||
type runtimeFunc struct {
|
||||
id guid.GUID
|
||||
once sync.Once
|
||||
addr uintptr
|
||||
err error
|
||||
}
|
||||
|
||||
func (f *runtimeFunc) Load() error {
|
||||
f.once.Do(func() {
|
||||
var s windows.Handle
|
||||
s, f.err = windows.Socket(windows.AF_INET, windows.SOCK_STREAM, windows.IPPROTO_TCP)
|
||||
if f.err != nil {
|
||||
return
|
||||
}
|
||||
defer windows.CloseHandle(s) //nolint:errcheck
|
||||
|
||||
var n uint32
|
||||
f.err = windows.WSAIoctl(s,
|
||||
windows.SIO_GET_EXTENSION_FUNCTION_POINTER,
|
||||
(*byte)(unsafe.Pointer(&f.id)),
|
||||
uint32(unsafe.Sizeof(f.id)),
|
||||
(*byte)(unsafe.Pointer(&f.addr)),
|
||||
uint32(unsafe.Sizeof(f.addr)),
|
||||
&n,
|
||||
nil, // overlapped
|
||||
0, // completionRoutine
|
||||
)
|
||||
})
|
||||
return f.err
|
||||
}
|
||||
|
||||
var (
|
||||
// todo: add `AcceptEx` and `GetAcceptExSockaddrs`
|
||||
WSAID_CONNECTEX = guid.GUID{ //revive:disable-line:var-naming ALL_CAPS
|
||||
Data1: 0x25a207b9,
|
||||
Data2: 0xddf3,
|
||||
Data3: 0x4660,
|
||||
Data4: [8]byte{0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e},
|
||||
}
|
||||
|
||||
connectExFunc = runtimeFunc{id: WSAID_CONNECTEX}
|
||||
)
|
||||
|
||||
func ConnectEx(
|
||||
fd windows.Handle,
|
||||
rsa RawSockaddr,
|
||||
sendBuf *byte,
|
||||
sendDataLen uint32,
|
||||
bytesSent *uint32,
|
||||
overlapped *windows.Overlapped,
|
||||
) error {
|
||||
if err := connectExFunc.Load(); err != nil {
|
||||
return fmt.Errorf("failed to load ConnectEx function pointer: %w", err)
|
||||
}
|
||||
ptr, n, err := rsa.Sockaddr()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return connectEx(fd, ptr, n, sendBuf, sendDataLen, bytesSent, overlapped)
|
||||
}
|
||||
|
||||
// BOOL LpfnConnectex(
|
||||
// [in] SOCKET s,
|
||||
// [in] const sockaddr *name,
|
||||
// [in] int namelen,
|
||||
// [in, optional] PVOID lpSendBuffer,
|
||||
// [in] DWORD dwSendDataLength,
|
||||
// [out] LPDWORD lpdwBytesSent,
|
||||
// [in] LPOVERLAPPED lpOverlapped
|
||||
// )
|
||||
|
||||
func connectEx(
|
||||
s windows.Handle,
|
||||
name unsafe.Pointer,
|
||||
namelen int32,
|
||||
sendBuf *byte,
|
||||
sendDataLen uint32,
|
||||
bytesSent *uint32,
|
||||
overlapped *windows.Overlapped,
|
||||
) (err error) {
|
||||
r1, _, e1 := syscall.SyscallN(connectExFunc.addr,
|
||||
uintptr(s),
|
||||
uintptr(name),
|
||||
uintptr(namelen),
|
||||
uintptr(unsafe.Pointer(sendBuf)),
|
||||
uintptr(sendDataLen),
|
||||
uintptr(unsafe.Pointer(bytesSent)),
|
||||
uintptr(unsafe.Pointer(overlapped)),
|
||||
)
|
||||
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = error(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
69
vendor/github.com/Microsoft/go-winio/internal/socket/zsyscall_windows.go
generated
vendored
Normal file
69
vendor/github.com/Microsoft/go-winio/internal/socket/zsyscall_windows.go
generated
vendored
Normal file
@ -0,0 +1,69 @@
|
||||
//go:build windows
|
||||
|
||||
// Code generated by 'go generate' using "github.com/Microsoft/go-winio/tools/mkwinsyscall"; DO NOT EDIT.
|
||||
|
||||
package socket
|
||||
|
||||
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
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
var (
|
||||
modws2_32 = windows.NewLazySystemDLL("ws2_32.dll")
|
||||
|
||||
procbind = modws2_32.NewProc("bind")
|
||||
procgetpeername = modws2_32.NewProc("getpeername")
|
||||
procgetsockname = modws2_32.NewProc("getsockname")
|
||||
)
|
||||
|
||||
func bind(s windows.Handle, name unsafe.Pointer, namelen int32) (err error) {
|
||||
r1, _, e1 := syscall.SyscallN(procbind.Addr(), uintptr(s), uintptr(name), uintptr(namelen))
|
||||
if r1 == socketError {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getpeername(s windows.Handle, name unsafe.Pointer, namelen *int32) (err error) {
|
||||
r1, _, e1 := syscall.SyscallN(procgetpeername.Addr(), uintptr(s), uintptr(name), uintptr(unsafe.Pointer(namelen)))
|
||||
if r1 == socketError {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getsockname(s windows.Handle, name unsafe.Pointer, namelen *int32) (err error) {
|
||||
r1, _, e1 := syscall.SyscallN(procgetsockname.Addr(), uintptr(s), uintptr(name), uintptr(unsafe.Pointer(namelen)))
|
||||
if r1 == socketError {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
132
vendor/github.com/Microsoft/go-winio/internal/stringbuffer/wstring.go
generated
vendored
Normal file
132
vendor/github.com/Microsoft/go-winio/internal/stringbuffer/wstring.go
generated
vendored
Normal file
@ -0,0 +1,132 @@
|
||||
package stringbuffer
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"unicode/utf16"
|
||||
)
|
||||
|
||||
// TODO: worth exporting and using in mkwinsyscall?
|
||||
|
||||
// Uint16BufferSize is the buffer size in the pool, chosen somewhat arbitrarily to accommodate
|
||||
// large path strings:
|
||||
// MAX_PATH (260) + size of volume GUID prefix (49) + null terminator = 310.
|
||||
const MinWStringCap = 310
|
||||
|
||||
// use *[]uint16 since []uint16 creates an extra allocation where the slice header
|
||||
// is copied to heap and then referenced via pointer in the interface header that sync.Pool
|
||||
// stores.
|
||||
var pathPool = sync.Pool{ // if go1.18+ adds Pool[T], use that to store []uint16 directly
|
||||
New: func() interface{} {
|
||||
b := make([]uint16, MinWStringCap)
|
||||
return &b
|
||||
},
|
||||
}
|
||||
|
||||
func newBuffer() []uint16 { return *(pathPool.Get().(*[]uint16)) }
|
||||
|
||||
// freeBuffer copies the slice header data, and puts a pointer to that in the pool.
|
||||
// This avoids taking a pointer to the slice header in WString, which can be set to nil.
|
||||
func freeBuffer(b []uint16) { pathPool.Put(&b) }
|
||||
|
||||
// WString is a wide string buffer ([]uint16) meant for storing UTF-16 encoded strings
|
||||
// for interacting with Win32 APIs.
|
||||
// Sizes are specified as uint32 and not int.
|
||||
//
|
||||
// It is not thread safe.
|
||||
type WString struct {
|
||||
// type-def allows casting to []uint16 directly, use struct to prevent that and allow adding fields in the future.
|
||||
|
||||
// raw buffer
|
||||
b []uint16
|
||||
}
|
||||
|
||||
// NewWString returns a [WString] allocated from a shared pool with an
|
||||
// initial capacity of at least [MinWStringCap].
|
||||
// Since the buffer may have been previously used, its contents are not guaranteed to be empty.
|
||||
//
|
||||
// The buffer should be freed via [WString.Free]
|
||||
func NewWString() *WString {
|
||||
return &WString{
|
||||
b: newBuffer(),
|
||||
}
|
||||
}
|
||||
|
||||
func (b *WString) Free() {
|
||||
if b.empty() {
|
||||
return
|
||||
}
|
||||
freeBuffer(b.b)
|
||||
b.b = nil
|
||||
}
|
||||
|
||||
// ResizeTo grows the buffer to at least c and returns the new capacity, freeing the
|
||||
// previous buffer back into pool.
|
||||
func (b *WString) ResizeTo(c uint32) uint32 {
|
||||
// already sufficient (or n is 0)
|
||||
if c <= b.Cap() {
|
||||
return b.Cap()
|
||||
}
|
||||
|
||||
if c <= MinWStringCap {
|
||||
c = MinWStringCap
|
||||
}
|
||||
// allocate at-least double buffer size, as is done in [bytes.Buffer] and other places
|
||||
if c <= 2*b.Cap() {
|
||||
c = 2 * b.Cap()
|
||||
}
|
||||
|
||||
b2 := make([]uint16, c)
|
||||
if !b.empty() {
|
||||
copy(b2, b.b)
|
||||
freeBuffer(b.b)
|
||||
}
|
||||
b.b = b2
|
||||
return c
|
||||
}
|
||||
|
||||
// Buffer returns the underlying []uint16 buffer.
|
||||
func (b *WString) Buffer() []uint16 {
|
||||
if b.empty() {
|
||||
return nil
|
||||
}
|
||||
return b.b
|
||||
}
|
||||
|
||||
// Pointer returns a pointer to the first uint16 in the buffer.
|
||||
// If the [WString.Free] has already been called, the pointer will be nil.
|
||||
func (b *WString) Pointer() *uint16 {
|
||||
if b.empty() {
|
||||
return nil
|
||||
}
|
||||
return &b.b[0]
|
||||
}
|
||||
|
||||
// String returns the returns the UTF-8 encoding of the UTF-16 string in the buffer.
|
||||
//
|
||||
// It assumes that the data is null-terminated.
|
||||
func (b *WString) String() string {
|
||||
// Using [windows.UTF16ToString] would require importing "golang.org/x/sys/windows"
|
||||
// and would make this code Windows-only, which makes no sense.
|
||||
// So copy UTF16ToString code into here.
|
||||
// If other windows-specific code is added, switch to [windows.UTF16ToString]
|
||||
|
||||
s := b.b
|
||||
for i, v := range s {
|
||||
if v == 0 {
|
||||
s = s[:i]
|
||||
break
|
||||
}
|
||||
}
|
||||
return string(utf16.Decode(s))
|
||||
}
|
||||
|
||||
// Cap returns the underlying buffer capacity.
|
||||
func (b *WString) Cap() uint32 {
|
||||
if b.empty() {
|
||||
return 0
|
||||
}
|
||||
return b.cap()
|
||||
}
|
||||
|
||||
func (b *WString) cap() uint32 { return uint32(cap(b.b)) }
|
||||
func (b *WString) empty() bool { return b == nil || b.cap() == 0 }
|
586
vendor/github.com/Microsoft/go-winio/pipe.go
generated
vendored
Normal file
586
vendor/github.com/Microsoft/go-winio/pipe.go
generated
vendored
Normal file
@ -0,0 +1,586 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package winio
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"runtime"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
|
||||
"github.com/Microsoft/go-winio/internal/fs"
|
||||
)
|
||||
|
||||
//sys connectNamedPipe(pipe windows.Handle, o *windows.Overlapped) (err error) = ConnectNamedPipe
|
||||
//sys createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *windows.SecurityAttributes) (handle windows.Handle, err error) [failretval==windows.InvalidHandle] = CreateNamedPipeW
|
||||
//sys disconnectNamedPipe(pipe windows.Handle) (err error) = DisconnectNamedPipe
|
||||
//sys getNamedPipeInfo(pipe windows.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) = GetNamedPipeInfo
|
||||
//sys getNamedPipeHandleState(pipe windows.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) = GetNamedPipeHandleStateW
|
||||
//sys ntCreateNamedPipeFile(pipe *windows.Handle, access ntAccessMask, oa *objectAttributes, iosb *ioStatusBlock, share ntFileShareMode, disposition ntFileCreationDisposition, options ntFileOptions, 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 PipeConn interface {
|
||||
net.Conn
|
||||
Disconnect() error
|
||||
Flush() error
|
||||
}
|
||||
|
||||
// type aliases for mkwinsyscall code
|
||||
type (
|
||||
ntAccessMask = fs.AccessMask
|
||||
ntFileShareMode = fs.FileShareMode
|
||||
ntFileCreationDisposition = fs.NTFileCreationDisposition
|
||||
ntFileOptions = fs.NTCreateOptions
|
||||
)
|
||||
|
||||
type ioStatusBlock struct {
|
||||
Status, Information uintptr
|
||||
}
|
||||
|
||||
// typedef struct _OBJECT_ATTRIBUTES {
|
||||
// ULONG Length;
|
||||
// HANDLE RootDirectory;
|
||||
// PUNICODE_STRING ObjectName;
|
||||
// ULONG Attributes;
|
||||
// PVOID SecurityDescriptor;
|
||||
// PVOID SecurityQualityOfService;
|
||||
// } OBJECT_ATTRIBUTES;
|
||||
//
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/ntdef/ns-ntdef-_object_attributes
|
||||
type objectAttributes struct {
|
||||
Length uintptr
|
||||
RootDirectory uintptr
|
||||
ObjectName *unicodeString
|
||||
Attributes uintptr
|
||||
SecurityDescriptor *securityDescriptor
|
||||
SecurityQoS uintptr
|
||||
}
|
||||
|
||||
type unicodeString struct {
|
||||
Length uint16
|
||||
MaximumLength uint16
|
||||
Buffer uintptr
|
||||
}
|
||||
|
||||
// typedef struct _SECURITY_DESCRIPTOR {
|
||||
// BYTE Revision;
|
||||
// BYTE Sbz1;
|
||||
// SECURITY_DESCRIPTOR_CONTROL Control;
|
||||
// PSID Owner;
|
||||
// PSID Group;
|
||||
// PACL Sacl;
|
||||
// PACL Dacl;
|
||||
// } SECURITY_DESCRIPTOR, *PISECURITY_DESCRIPTOR;
|
||||
//
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-security_descriptor
|
||||
type securityDescriptor struct {
|
||||
Revision byte
|
||||
Sbz1 byte
|
||||
Control uint16
|
||||
Owner uintptr
|
||||
Group uintptr
|
||||
Sacl uintptr //revive:disable-line:var-naming SACL, not Sacl
|
||||
Dacl uintptr //revive:disable-line:var-naming DACL, not Dacl
|
||||
}
|
||||
|
||||
type ntStatus int32
|
||||
|
||||
func (status ntStatus) Err() error {
|
||||
if status >= 0 {
|
||||
return nil
|
||||
}
|
||||
return rtlNtStatusToDosError(status)
|
||||
}
|
||||
|
||||
var (
|
||||
// ErrPipeListenerClosed is returned for pipe operations on listeners that have been closed.
|
||||
ErrPipeListenerClosed = net.ErrClosed
|
||||
|
||||
errPipeWriteClosed = errors.New("pipe has been closed for write")
|
||||
)
|
||||
|
||||
type win32Pipe struct {
|
||||
*win32File
|
||||
path string
|
||||
}
|
||||
|
||||
var _ PipeConn = (*win32Pipe)(nil)
|
||||
|
||||
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 {
|
||||
if err := f.SetReadDeadline(t); err != nil {
|
||||
return err
|
||||
}
|
||||
return f.SetWriteDeadline(t)
|
||||
}
|
||||
|
||||
func (f *win32Pipe) Disconnect() error {
|
||||
return disconnectNamedPipe(f.win32File.handle)
|
||||
}
|
||||
|
||||
// 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 { //nolint:errorlint
|
||||
// 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 == windows.ERROR_MORE_DATA { //nolint:errorlint // err is Errno
|
||||
// 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 (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 fs.AccessMask, impLevel PipeImpLevel) (windows.Handle, error) {
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return windows.Handle(0), ctx.Err()
|
||||
default:
|
||||
h, err := fs.CreateFile(*path,
|
||||
access,
|
||||
0, // mode
|
||||
nil, // security attributes
|
||||
fs.OPEN_EXISTING,
|
||||
fs.FILE_FLAG_OVERLAPPED|fs.SECURITY_SQOS_PRESENT|fs.FileSQSFlag(impLevel),
|
||||
0, // template file handle
|
||||
)
|
||||
if err == nil {
|
||||
return h, nil
|
||||
}
|
||||
if err != windows.ERROR_PIPE_BUSY { //nolint:errorlint // err is Errno
|
||||
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, cancel := context.WithDeadline(context.Background(), absTimeout)
|
||||
defer cancel()
|
||||
conn, err := DialPipeContext(ctx, path)
|
||||
if errors.Is(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, uint32(fs.GENERIC_READ|fs.GENERIC_WRITE))
|
||||
}
|
||||
|
||||
// PipeImpLevel is an enumeration of impersonation levels that may be set
|
||||
// when calling DialPipeAccessImpersonation.
|
||||
type PipeImpLevel uint32
|
||||
|
||||
const (
|
||||
PipeImpLevelAnonymous = PipeImpLevel(fs.SECURITY_ANONYMOUS)
|
||||
PipeImpLevelIdentification = PipeImpLevel(fs.SECURITY_IDENTIFICATION)
|
||||
PipeImpLevelImpersonation = PipeImpLevel(fs.SECURITY_IMPERSONATION)
|
||||
PipeImpLevelDelegation = PipeImpLevel(fs.SECURITY_DELEGATION)
|
||||
)
|
||||
|
||||
// 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) {
|
||||
return DialPipeAccessImpLevel(ctx, path, access, PipeImpLevelAnonymous)
|
||||
}
|
||||
|
||||
// DialPipeAccessImpLevel attempts to connect to a named pipe by `path` with
|
||||
// `access` at `impLevel` until `ctx` cancellation or timeout. The other
|
||||
// DialPipe* implementations use PipeImpLevelAnonymous.
|
||||
func DialPipeAccessImpLevel(ctx context.Context, path string, access uint32, impLevel PipeImpLevel) (net.Conn, error) {
|
||||
var err error
|
||||
var h windows.Handle
|
||||
h, err = tryDialPipe(ctx, &path, fs.AccessMask(access), impLevel)
|
||||
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 {
|
||||
windows.Close(h)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// If the pipe is in message mode, return a message byte pipe, which
|
||||
// supports CloseWrite().
|
||||
if flags&windows.PIPE_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 windows.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) (windows.Handle, error) {
|
||||
path16, err := windows.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 windows.LocalFree(windows.Handle(ntPath.Buffer)) //nolint:errcheck
|
||||
oa.ObjectName = &ntPath
|
||||
oa.Attributes = windows.OBJ_CASE_INSENSITIVE
|
||||
|
||||
// The security descriptor is only needed for the first pipe.
|
||||
if first {
|
||||
if sd != nil {
|
||||
//todo: does `sdb` need to be allocated on the heap, or can go allocate it?
|
||||
l := uint32(len(sd))
|
||||
sdb, err := windows.LocalAlloc(0, l)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("LocalAlloc for security descriptor with of length %d: %w", l, err)
|
||||
}
|
||||
defer windows.LocalFree(windows.Handle(sdb)) //nolint:errcheck
|
||||
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: %w", err)
|
||||
}
|
||||
defer windows.LocalFree(windows.Handle(dacl)) //nolint:errcheck
|
||||
|
||||
sdb := &securityDescriptor{
|
||||
Revision: 1,
|
||||
Control: windows.SE_DACL_PRESENT,
|
||||
Dacl: dacl,
|
||||
}
|
||||
oa.SecurityDescriptor = sdb
|
||||
}
|
||||
}
|
||||
|
||||
typ := uint32(windows.FILE_PIPE_REJECT_REMOTE_CLIENTS)
|
||||
if c.MessageMode {
|
||||
typ |= windows.FILE_PIPE_MESSAGE_TYPE
|
||||
}
|
||||
|
||||
disposition := fs.FILE_OPEN
|
||||
access := fs.GENERIC_READ | fs.GENERIC_WRITE | fs.SYNCHRONIZE
|
||||
if first {
|
||||
disposition = fs.FILE_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 = fs.SYNCHRONIZE
|
||||
}
|
||||
|
||||
timeout := int64(-50 * 10000) // 50ms
|
||||
|
||||
var (
|
||||
h windows.Handle
|
||||
iosb ioStatusBlock
|
||||
)
|
||||
err = ntCreateNamedPipeFile(&h,
|
||||
access,
|
||||
&oa,
|
||||
&iosb,
|
||||
fs.FILE_SHARE_READ|fs.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 {
|
||||
windows.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 { //nolint:errorlint // err is Errno
|
||||
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 != windows.ERROR_NO_DATA { //nolint:errorlint // err is Errno
|
||||
break
|
||||
}
|
||||
}
|
||||
responseCh <- acceptResponse{p, err}
|
||||
closed = err == ErrPipeListenerClosed //nolint:errorlint // err is Errno
|
||||
}
|
||||
}
|
||||
windows.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 != windows.ERROR_PIPE_CONNECTED { //nolint:errorlint // err is Errno
|
||||
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)
|
||||
}
|
232
vendor/github.com/Microsoft/go-winio/pkg/guid/guid.go
generated
vendored
Normal file
232
vendor/github.com/Microsoft/go-winio/pkg/guid/guid.go
generated
vendored
Normal file
@ -0,0 +1,232 @@
|
||||
// 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" //nolint:gosec // not used for secure application
|
||||
"encoding"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
//go:generate go run golang.org/x/tools/cmd/stringer -type=Variant -trimprefix=Variant -linecomment
|
||||
|
||||
// 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 section 4.1.1.
|
||||
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 // RFC 4122
|
||||
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
|
||||
|
||||
func (v Version) String() string {
|
||||
return strconv.FormatUint(uint64(v), 10)
|
||||
}
|
||||
|
||||
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() //nolint:gosec // not used for secure application
|
||||
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
|
||||
}
|
16
vendor/github.com/Microsoft/go-winio/pkg/guid/guid_nonwindows.go
generated
vendored
Normal file
16
vendor/github.com/Microsoft/go-winio/pkg/guid/guid_nonwindows.go
generated
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
//go:build !windows
|
||||
// +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
|
||||
}
|
13
vendor/github.com/Microsoft/go-winio/pkg/guid/guid_windows.go
generated
vendored
Normal file
13
vendor/github.com/Microsoft/go-winio/pkg/guid/guid_windows.go
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
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
|
27
vendor/github.com/Microsoft/go-winio/pkg/guid/variant_string.go
generated
vendored
Normal file
27
vendor/github.com/Microsoft/go-winio/pkg/guid/variant_string.go
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
// Code generated by "stringer -type=Variant -trimprefix=Variant -linecomment"; DO NOT EDIT.
|
||||
|
||||
package guid
|
||||
|
||||
import "strconv"
|
||||
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[VariantUnknown-0]
|
||||
_ = x[VariantNCS-1]
|
||||
_ = x[VariantRFC4122-2]
|
||||
_ = x[VariantMicrosoft-3]
|
||||
_ = x[VariantFuture-4]
|
||||
}
|
||||
|
||||
const _Variant_name = "UnknownNCSRFC 4122MicrosoftFuture"
|
||||
|
||||
var _Variant_index = [...]uint8{0, 7, 10, 18, 27, 33}
|
||||
|
||||
func (i Variant) String() string {
|
||||
if i >= Variant(len(_Variant_index)-1) {
|
||||
return "Variant(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
return _Variant_name[_Variant_index[i]:_Variant_index[i+1]]
|
||||
}
|
196
vendor/github.com/Microsoft/go-winio/privilege.go
generated
vendored
Normal file
196
vendor/github.com/Microsoft/go-winio/privilege.go
generated
vendored
Normal file
@ -0,0 +1,196 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package winio
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"sync"
|
||||
"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 windows.Handle, accessMask uint32, openAsSelf bool, token *windows.Token) (err error) = advapi32.OpenThreadToken
|
||||
//sys getCurrentThread() (h windows.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 (
|
||||
//revive:disable-next-line:var-naming ALL_CAPS
|
||||
SE_PRIVILEGE_ENABLED = windows.SE_PRIVILEGE_ENABLED
|
||||
|
||||
//revive:disable-next-line:var-naming ALL_CAPS
|
||||
ERROR_NOT_ALL_ASSIGNED windows.Errno = windows.ERROR_NOT_ALL_ASSIGNED
|
||||
|
||||
SeBackupPrivilege = "SeBackupPrivilege"
|
||||
SeRestorePrivilege = "SeRestorePrivilege"
|
||||
SeSecurityPrivilege = "SeSecurityPrivilege"
|
||||
)
|
||||
|
||||
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 := "Could not enable privilege "
|
||||
if len(e.privileges) > 1 {
|
||||
s = "Could not enable privileges "
|
||||
}
|
||||
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) {
|
||||
privileges := make([]uint64, 0, len(names))
|
||||
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.CurrentProcess()
|
||||
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 { //nolint:errorlint // err is Errno
|
||||
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(windows.SecurityImpersonation)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
var token windows.Token
|
||||
err = openThreadToken(getCurrentThread(), windows.TOKEN_ADJUST_PRIVILEGES|windows.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()
|
||||
}
|
131
vendor/github.com/Microsoft/go-winio/reparse.go
generated
vendored
Normal file
131
vendor/github.com/Microsoft/go-winio/reparse.go
generated
vendored
Normal file
@ -0,0 +1,131 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
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()
|
||||
}
|
133
vendor/github.com/Microsoft/go-winio/sd.go
generated
vendored
Normal file
133
vendor/github.com/Microsoft/go-winio/sd.go
generated
vendored
Normal file
@ -0,0 +1,133 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package winio
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
//sys lookupAccountName(systemName *uint16, accountName string, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) = advapi32.LookupAccountNameW
|
||||
//sys lookupAccountSid(systemName *uint16, sid *byte, name *uint16, nameSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) = advapi32.LookupAccountSidW
|
||||
//sys convertSidToStringSid(sid *byte, str **uint16) (err error) = advapi32.ConvertSidToStringSidW
|
||||
//sys convertStringSidToSid(str *uint16, sid **byte) (err error) = advapi32.ConvertStringSidToSidW
|
||||
|
||||
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 {
|
||||
case errors.Is(e.Err, windows.ERROR_INVALID_SID):
|
||||
s = "the security ID structure is invalid"
|
||||
case errors.Is(e.Err, windows.ERROR_NONE_MAPPED):
|
||||
s = "not found"
|
||||
default:
|
||||
s = e.Err.Error()
|
||||
}
|
||||
return "lookup account " + e.Name + ": " + s
|
||||
}
|
||||
|
||||
func (e *AccountLookupError) Unwrap() error { return e.Err }
|
||||
|
||||
type SddlConversionError struct {
|
||||
Sddl string
|
||||
Err error
|
||||
}
|
||||
|
||||
func (e *SddlConversionError) Error() string {
|
||||
return "convert " + e.Sddl + ": " + e.Err.Error()
|
||||
}
|
||||
|
||||
func (e *SddlConversionError) Unwrap() error { return e.Err }
|
||||
|
||||
// LookupSidByName looks up the SID of an account by name
|
||||
//
|
||||
//revive:disable-next-line:var-naming SID, not Sid
|
||||
func LookupSidByName(name string) (sid string, err error) {
|
||||
if name == "" {
|
||||
return "", &AccountLookupError{name, windows.ERROR_NONE_MAPPED}
|
||||
}
|
||||
|
||||
var sidSize, sidNameUse, refDomainSize uint32
|
||||
err = lookupAccountName(nil, name, nil, &sidSize, nil, &refDomainSize, &sidNameUse)
|
||||
if err != nil && err != windows.ERROR_INSUFFICIENT_BUFFER { //nolint:errorlint // err is Errno
|
||||
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 = windows.UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(strBuffer))[:])
|
||||
_, _ = windows.LocalFree(windows.Handle(unsafe.Pointer(strBuffer)))
|
||||
return sid, nil
|
||||
}
|
||||
|
||||
// LookupNameBySid looks up the name of an account by SID
|
||||
//
|
||||
//revive:disable-next-line:var-naming SID, not Sid
|
||||
func LookupNameBySid(sid string) (name string, err error) {
|
||||
if sid == "" {
|
||||
return "", &AccountLookupError{sid, windows.ERROR_NONE_MAPPED}
|
||||
}
|
||||
|
||||
sidBuffer, err := windows.UTF16PtrFromString(sid)
|
||||
if err != nil {
|
||||
return "", &AccountLookupError{sid, err}
|
||||
}
|
||||
|
||||
var sidPtr *byte
|
||||
if err = convertStringSidToSid(sidBuffer, &sidPtr); err != nil {
|
||||
return "", &AccountLookupError{sid, err}
|
||||
}
|
||||
defer windows.LocalFree(windows.Handle(unsafe.Pointer(sidPtr))) //nolint:errcheck
|
||||
|
||||
var nameSize, refDomainSize, sidNameUse uint32
|
||||
err = lookupAccountSid(nil, sidPtr, nil, &nameSize, nil, &refDomainSize, &sidNameUse)
|
||||
if err != nil && err != windows.ERROR_INSUFFICIENT_BUFFER { //nolint:errorlint // err is Errno
|
||||
return "", &AccountLookupError{sid, err}
|
||||
}
|
||||
|
||||
nameBuffer := make([]uint16, nameSize)
|
||||
refDomainBuffer := make([]uint16, refDomainSize)
|
||||
err = lookupAccountSid(nil, sidPtr, &nameBuffer[0], &nameSize, &refDomainBuffer[0], &refDomainSize, &sidNameUse)
|
||||
if err != nil {
|
||||
return "", &AccountLookupError{sid, err}
|
||||
}
|
||||
|
||||
name = windows.UTF16ToString(nameBuffer)
|
||||
return name, nil
|
||||
}
|
||||
|
||||
func SddlToSecurityDescriptor(sddl string) ([]byte, error) {
|
||||
sd, err := windows.SecurityDescriptorFromString(sddl)
|
||||
if err != nil {
|
||||
return nil, &SddlConversionError{Sddl: sddl, Err: err}
|
||||
}
|
||||
b := unsafe.Slice((*byte)(unsafe.Pointer(sd)), sd.Length())
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func SecurityDescriptorToSddl(sd []byte) (string, error) {
|
||||
if l := int(unsafe.Sizeof(windows.SECURITY_DESCRIPTOR{})); len(sd) < l {
|
||||
return "", fmt.Errorf("SecurityDescriptor (%d) smaller than expected (%d): %w", len(sd), l, windows.ERROR_INCORRECT_SIZE)
|
||||
}
|
||||
s := (*windows.SECURITY_DESCRIPTOR)(unsafe.Pointer(&sd[0]))
|
||||
return s.String(), nil
|
||||
}
|
5
vendor/github.com/Microsoft/go-winio/syscall.go
generated
vendored
Normal file
5
vendor/github.com/Microsoft/go-winio/syscall.go
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
//go:build windows
|
||||
|
||||
package winio
|
||||
|
||||
//go:generate go run github.com/Microsoft/go-winio/tools/mkwinsyscall -output zsyscall_windows.go ./*.go
|
378
vendor/github.com/Microsoft/go-winio/zsyscall_windows.go
generated
vendored
Normal file
378
vendor/github.com/Microsoft/go-winio/zsyscall_windows.go
generated
vendored
Normal file
@ -0,0 +1,378 @@
|
||||
//go:build windows
|
||||
|
||||
// Code generated by 'go generate' using "github.com/Microsoft/go-winio/tools/mkwinsyscall"; 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
|
||||
}
|
||||
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")
|
||||
procConvertSidToStringSidW = modadvapi32.NewProc("ConvertSidToStringSidW")
|
||||
procConvertStringSidToSidW = modadvapi32.NewProc("ConvertStringSidToSidW")
|
||||
procImpersonateSelf = modadvapi32.NewProc("ImpersonateSelf")
|
||||
procLookupAccountNameW = modadvapi32.NewProc("LookupAccountNameW")
|
||||
procLookupAccountSidW = modadvapi32.NewProc("LookupAccountSidW")
|
||||
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")
|
||||
procCreateIoCompletionPort = modkernel32.NewProc("CreateIoCompletionPort")
|
||||
procCreateNamedPipeW = modkernel32.NewProc("CreateNamedPipeW")
|
||||
procDisconnectNamedPipe = modkernel32.NewProc("DisconnectNamedPipe")
|
||||
procGetCurrentThread = modkernel32.NewProc("GetCurrentThread")
|
||||
procGetNamedPipeHandleStateW = modkernel32.NewProc("GetNamedPipeHandleStateW")
|
||||
procGetNamedPipeInfo = modkernel32.NewProc("GetNamedPipeInfo")
|
||||
procGetQueuedCompletionStatus = modkernel32.NewProc("GetQueuedCompletionStatus")
|
||||
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")
|
||||
)
|
||||
|
||||
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.SyscallN(procAdjustTokenPrivileges.Addr(), 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 convertSidToStringSid(sid *byte, str **uint16) (err error) {
|
||||
r1, _, e1 := syscall.SyscallN(procConvertSidToStringSidW.Addr(), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(str)))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func convertStringSidToSid(str *uint16, sid **byte) (err error) {
|
||||
r1, _, e1 := syscall.SyscallN(procConvertStringSidToSidW.Addr(), uintptr(unsafe.Pointer(str)), uintptr(unsafe.Pointer(sid)))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func impersonateSelf(level uint32) (err error) {
|
||||
r1, _, e1 := syscall.SyscallN(procImpersonateSelf.Addr(), uintptr(level))
|
||||
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.SyscallN(procLookupAccountNameW.Addr(), 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)))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func lookupAccountSid(systemName *uint16, sid *byte, name *uint16, nameSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) {
|
||||
r1, _, e1 := syscall.SyscallN(procLookupAccountSidW.Addr(), uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameSize)), uintptr(unsafe.Pointer(refDomain)), uintptr(unsafe.Pointer(refDomainSize)), uintptr(unsafe.Pointer(sidNameUse)))
|
||||
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.SyscallN(procLookupPrivilegeDisplayNameW.Addr(), uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(buffer)), uintptr(unsafe.Pointer(size)), uintptr(unsafe.Pointer(languageId)))
|
||||
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.SyscallN(procLookupPrivilegeNameW.Addr(), uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(luid)), uintptr(unsafe.Pointer(buffer)), uintptr(unsafe.Pointer(size)))
|
||||
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.SyscallN(procLookupPrivilegeValueW.Addr(), uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(luid)))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func openThreadToken(thread windows.Handle, accessMask uint32, openAsSelf bool, token *windows.Token) (err error) {
|
||||
var _p0 uint32
|
||||
if openAsSelf {
|
||||
_p0 = 1
|
||||
}
|
||||
r1, _, e1 := syscall.SyscallN(procOpenThreadToken.Addr(), uintptr(thread), uintptr(accessMask), uintptr(_p0), uintptr(unsafe.Pointer(token)))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func revertToSelf() (err error) {
|
||||
r1, _, e1 := syscall.SyscallN(procRevertToSelf.Addr())
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func backupRead(h windows.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.SyscallN(procBackupRead.Addr(), uintptr(h), uintptr(unsafe.Pointer(_p0)), uintptr(len(b)), uintptr(unsafe.Pointer(bytesRead)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(context)))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func backupWrite(h windows.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.SyscallN(procBackupWrite.Addr(), uintptr(h), uintptr(unsafe.Pointer(_p0)), uintptr(len(b)), uintptr(unsafe.Pointer(bytesWritten)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(context)))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func cancelIoEx(file windows.Handle, o *windows.Overlapped) (err error) {
|
||||
r1, _, e1 := syscall.SyscallN(procCancelIoEx.Addr(), uintptr(file), uintptr(unsafe.Pointer(o)))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func connectNamedPipe(pipe windows.Handle, o *windows.Overlapped) (err error) {
|
||||
r1, _, e1 := syscall.SyscallN(procConnectNamedPipe.Addr(), uintptr(pipe), uintptr(unsafe.Pointer(o)))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func createIoCompletionPort(file windows.Handle, port windows.Handle, key uintptr, threadCount uint32) (newport windows.Handle, err error) {
|
||||
r0, _, e1 := syscall.SyscallN(procCreateIoCompletionPort.Addr(), uintptr(file), uintptr(port), uintptr(key), uintptr(threadCount))
|
||||
newport = windows.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 *windows.SecurityAttributes) (handle windows.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 *windows.SecurityAttributes) (handle windows.Handle, err error) {
|
||||
r0, _, e1 := syscall.SyscallN(procCreateNamedPipeW.Addr(), uintptr(unsafe.Pointer(name)), uintptr(flags), uintptr(pipeMode), uintptr(maxInstances), uintptr(outSize), uintptr(inSize), uintptr(defaultTimeout), uintptr(unsafe.Pointer(sa)))
|
||||
handle = windows.Handle(r0)
|
||||
if handle == windows.InvalidHandle {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func disconnectNamedPipe(pipe windows.Handle) (err error) {
|
||||
r1, _, e1 := syscall.SyscallN(procDisconnectNamedPipe.Addr(), uintptr(pipe))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getCurrentThread() (h windows.Handle) {
|
||||
r0, _, _ := syscall.SyscallN(procGetCurrentThread.Addr())
|
||||
h = windows.Handle(r0)
|
||||
return
|
||||
}
|
||||
|
||||
func getNamedPipeHandleState(pipe windows.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) {
|
||||
r1, _, e1 := syscall.SyscallN(procGetNamedPipeHandleStateW.Addr(), uintptr(pipe), uintptr(unsafe.Pointer(state)), uintptr(unsafe.Pointer(curInstances)), uintptr(unsafe.Pointer(maxCollectionCount)), uintptr(unsafe.Pointer(collectDataTimeout)), uintptr(unsafe.Pointer(userName)), uintptr(maxUserNameSize))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getNamedPipeInfo(pipe windows.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) {
|
||||
r1, _, e1 := syscall.SyscallN(procGetNamedPipeInfo.Addr(), uintptr(pipe), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(outSize)), uintptr(unsafe.Pointer(inSize)), uintptr(unsafe.Pointer(maxInstances)))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getQueuedCompletionStatus(port windows.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) {
|
||||
r1, _, e1 := syscall.SyscallN(procGetQueuedCompletionStatus.Addr(), uintptr(port), uintptr(unsafe.Pointer(bytes)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(o)), uintptr(timeout))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func setFileCompletionNotificationModes(h windows.Handle, flags uint8) (err error) {
|
||||
r1, _, e1 := syscall.SyscallN(procSetFileCompletionNotificationModes.Addr(), uintptr(h), uintptr(flags))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func ntCreateNamedPipeFile(pipe *windows.Handle, access ntAccessMask, oa *objectAttributes, iosb *ioStatusBlock, share ntFileShareMode, disposition ntFileCreationDisposition, options ntFileOptions, typ uint32, readMode uint32, completionMode uint32, maxInstances uint32, inboundQuota uint32, outputQuota uint32, timeout *int64) (status ntStatus) {
|
||||
r0, _, _ := syscall.SyscallN(procNtCreateNamedPipeFile.Addr(), 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)))
|
||||
status = ntStatus(r0)
|
||||
return
|
||||
}
|
||||
|
||||
func rtlDefaultNpAcl(dacl *uintptr) (status ntStatus) {
|
||||
r0, _, _ := syscall.SyscallN(procRtlDefaultNpAcl.Addr(), uintptr(unsafe.Pointer(dacl)))
|
||||
status = ntStatus(r0)
|
||||
return
|
||||
}
|
||||
|
||||
func rtlDosPathNameToNtPathName(name *uint16, ntName *unicodeString, filePart uintptr, reserved uintptr) (status ntStatus) {
|
||||
r0, _, _ := syscall.SyscallN(procRtlDosPathNameToNtPathName_U.Addr(), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(ntName)), uintptr(filePart), uintptr(reserved))
|
||||
status = ntStatus(r0)
|
||||
return
|
||||
}
|
||||
|
||||
func rtlNtStatusToDosError(status ntStatus) (winerr error) {
|
||||
r0, _, _ := syscall.SyscallN(procRtlNtStatusToDosErrorNoTeb.Addr(), uintptr(status))
|
||||
if r0 != 0 {
|
||||
winerr = syscall.Errno(r0)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func wsaGetOverlappedResult(h windows.Handle, o *windows.Overlapped, bytes *uint32, wait bool, flags *uint32) (err error) {
|
||||
var _p0 uint32
|
||||
if wait {
|
||||
_p0 = 1
|
||||
}
|
||||
r1, _, e1 := syscall.SyscallN(procWSAGetOverlappedResult.Addr(), uintptr(h), uintptr(unsafe.Pointer(o)), uintptr(unsafe.Pointer(bytes)), uintptr(_p0), uintptr(unsafe.Pointer(flags)))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
2
vendor/golang.org/x/exp/AUTHORS → vendor/github.com/ProtonMail/go-crypto/AUTHORS
generated
vendored
2
vendor/golang.org/x/exp/AUTHORS → vendor/github.com/ProtonMail/go-crypto/AUTHORS
generated
vendored
@ -1,3 +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 http://tip.golang.org/AUTHORS.
|
||||
# visible at https://tip.golang.org/AUTHORS.
|
@ -1,3 +1,3 @@
|
||||
# This source code was written by the Go contributors.
|
||||
# The master list of contributors is in the main Go distribution,
|
||||
# visible at http://tip.golang.org/CONTRIBUTORS.
|
||||
# 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"},
|
||||
}
|
90
vendor/github.com/ProtonMail/go-crypto/internal/byteutil/byteutil.go
generated
vendored
Normal file
90
vendor/github.com/ProtonMail/go-crypto/internal/byteutil/byteutil.go
generated
vendored
Normal file
@ -0,0 +1,90 @@
|
||||
// Copyright (C) 2019 ProtonTech AG
|
||||
// This file contains necessary tools for the aex and ocb packages.
|
||||
//
|
||||
// These functions SHOULD NOT be used elsewhere, since they are optimized for
|
||||
// specific input nature in the EAX and OCB modes of operation.
|
||||
|
||||
package byteutil
|
||||
|
||||
// GfnDouble computes 2 * input in the field of 2^n elements.
|
||||
// The irreducible polynomial in the finite field for n=128 is
|
||||
// x^128 + x^7 + x^2 + x + 1 (equals 0x87)
|
||||
// Constant-time execution in order to avoid side-channel attacks
|
||||
func GfnDouble(input []byte) []byte {
|
||||
if len(input) != 16 {
|
||||
panic("Doubling in GFn only implemented for n = 128")
|
||||
}
|
||||
// If the first bit is zero, return 2L = L << 1
|
||||
// Else return (L << 1) xor 0^120 10000111
|
||||
shifted := ShiftBytesLeft(input)
|
||||
shifted[15] ^= ((input[0] >> 7) * 0x87)
|
||||
return shifted
|
||||
}
|
||||
|
||||
// ShiftBytesLeft outputs the byte array corresponding to x << 1 in binary.
|
||||
func ShiftBytesLeft(x []byte) []byte {
|
||||
l := len(x)
|
||||
dst := make([]byte, l)
|
||||
for i := 0; i < l-1; i++ {
|
||||
dst[i] = (x[i] << 1) | (x[i+1] >> 7)
|
||||
}
|
||||
dst[l-1] = x[l-1] << 1
|
||||
return dst
|
||||
}
|
||||
|
||||
// ShiftNBytesLeft puts in dst the byte array corresponding to x << n in binary.
|
||||
func ShiftNBytesLeft(dst, x []byte, n int) {
|
||||
// Erase first n / 8 bytes
|
||||
copy(dst, x[n/8:])
|
||||
|
||||
// Shift the remaining n % 8 bits
|
||||
bits := uint(n % 8)
|
||||
l := len(dst)
|
||||
for i := 0; i < l-1; i++ {
|
||||
dst[i] = (dst[i] << bits) | (dst[i+1] >> uint(8-bits))
|
||||
}
|
||||
dst[l-1] = dst[l-1] << bits
|
||||
|
||||
// Append trailing zeroes
|
||||
dst = append(dst, make([]byte, n/8)...)
|
||||
}
|
||||
|
||||
// XorBytesMut replaces X with X XOR Y. len(X) must be >= len(Y).
|
||||
func XorBytesMut(X, Y []byte) {
|
||||
for i := 0; i < len(Y); i++ {
|
||||
X[i] ^= Y[i]
|
||||
}
|
||||
}
|
||||
|
||||
// XorBytes puts X XOR Y into Z. len(Z) and len(X) must be >= len(Y).
|
||||
func XorBytes(Z, X, Y []byte) {
|
||||
for i := 0; i < len(Y); 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
|
||||
}
|
313
vendor/github.com/ProtonMail/go-crypto/ocb/ocb.go
generated
vendored
Normal file
313
vendor/github.com/ProtonMail/go-crypto/ocb/ocb.go
generated
vendored
Normal file
@ -0,0 +1,313 @@
|
||||
// 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"
|
||||
"math/bits"
|
||||
|
||||
"github.com/ProtonMail/go-crypto/internal/byteutil"
|
||||
)
|
||||
|
||||
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")
|
||||
}
|
||||
sep := len(plaintext)
|
||||
ret, out := byteutil.SliceForAppend(dst, sep+o.tagSize)
|
||||
tag := o.crypt(enc, out[:sep], nonce, adata, plaintext)
|
||||
copy(out[sep:], tag)
|
||||
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, sep)
|
||||
ciphertextData := ciphertext[:sep]
|
||||
tag := o.crypt(dec, out, nonce, adata, ciphertextData)
|
||||
if subtle.ConstantTimeCompare(tag, ciphertext[sep:]) == 1 {
|
||||
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 writes the resulting plain/ciphertext into Y and returns
|
||||
// the tag.
|
||||
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
|
||||
var Ktop []byte
|
||||
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]
|
||||
switch instruction {
|
||||
case enc:
|
||||
byteutil.XorBytesMut(checksum, blockX)
|
||||
byteutil.XorBytes(blockY, blockX, offset)
|
||||
o.block.Encrypt(blockY, blockY)
|
||||
byteutil.XorBytesMut(blockY, offset)
|
||||
case dec:
|
||||
byteutil.XorBytes(blockY, blockX, offset)
|
||||
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)]
|
||||
switch instruction {
|
||||
case enc:
|
||||
byteutil.XorBytesMut(checksum, chunkX)
|
||||
checksum[len(chunkX)] ^= 128
|
||||
byteutil.XorBytes(chunkY, chunkX, pad[:len(chunkX)])
|
||||
// P_* || bit(1) || zeroes(127) - len(P_*)
|
||||
case dec:
|
||||
byteutil.XorBytes(chunkY, chunkX, pad[:len(chunkX)])
|
||||
// P_* || bit(1) || zeroes(127) - len(P_*)
|
||||
byteutil.XorBytesMut(checksum, chunkY)
|
||||
checksum[len(chunkY)] ^= 128
|
||||
}
|
||||
}
|
||||
byteutil.XorBytes(tag, checksum, offset)
|
||||
byteutil.XorBytesMut(tag, o.mask.lDol)
|
||||
o.block.Encrypt(tag, tag)
|
||||
byteutil.XorBytesMut(tag, o.hash(adata))
|
||||
return tag[:o.tagSize]
|
||||
}
|
||||
|
||||
// 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"},
|
||||
}
|
25
vendor/github.com/ProtonMail/go-crypto/ocb/rfc7253_test_vectors_suite_b.go
generated
vendored
Normal file
25
vendor/github.com/ProtonMail/go-crypto/ocb/rfc7253_test_vectors_suite_b.go
generated
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
package ocb
|
||||
|
||||
// Second set of test vectors from https://tools.ietf.org/html/rfc7253
|
||||
var rfc7253TestVectorTaglen96 = struct {
|
||||
key, nonce, header, plaintext, ciphertext string
|
||||
}{"0F0E0D0C0B0A09080706050403020100",
|
||||
"BBAA9988776655443322110D",
|
||||
"000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627",
|
||||
"000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627",
|
||||
"1792A4E31E0755FB03E31B22116E6C2DDF9EFD6E33D536F1A0124B0A55BAE884ED93481529C76B6AD0C515F4D1CDD4FDAC4F02AA"}
|
||||
|
||||
var rfc7253AlgorithmTest = []struct {
|
||||
KEYLEN, TAGLEN int
|
||||
OUTPUT string
|
||||
}{
|
||||
{128, 128, "67E944D23256C5E0B6C61FA22FDF1EA2"},
|
||||
{192, 128, "F673F2C3E7174AAE7BAE986CA9F29E17"},
|
||||
{256, 128, "D90EB8E9C977C88B79DD793D7FFA161C"},
|
||||
{128, 96, "77A3D8E73589158D25D01209"},
|
||||
{192, 96, "05D56EAD2752C86BE6932C5E"},
|
||||
{256, 96, "5458359AC23B0CBA9E6330DD"},
|
||||
{128, 64, "192C9B7BD90BA06A"},
|
||||
{192, 64, "0066BC6E0EF34E24"},
|
||||
{256, 64, "7D4EA5D445501CBE"},
|
||||
}
|
153
vendor/github.com/ProtonMail/go-crypto/openpgp/aes/keywrap/keywrap.go
generated
vendored
Normal file
153
vendor/github.com/ProtonMail/go-crypto/openpgp/aes/keywrap/keywrap.go
generated
vendored
Normal file
@ -0,0 +1,153 @@
|
||||
// Copyright 2014 Matthew Endsley
|
||||
// All rights reserved
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted providing that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Package keywrap is an implementation of the RFC 3394 AES key wrapping
|
||||
// algorithm. This is used in OpenPGP with elliptic curve keys.
|
||||
package keywrap
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrWrapPlaintext is returned if the plaintext is not a multiple
|
||||
// of 64 bits.
|
||||
ErrWrapPlaintext = errors.New("keywrap: plainText must be a multiple of 64 bits")
|
||||
|
||||
// ErrUnwrapCiphertext is returned if the ciphertext is not a
|
||||
// multiple of 64 bits.
|
||||
ErrUnwrapCiphertext = errors.New("keywrap: cipherText must by a multiple of 64 bits")
|
||||
|
||||
// ErrUnwrapFailed is returned if unwrapping a key fails.
|
||||
ErrUnwrapFailed = errors.New("keywrap: failed to unwrap key")
|
||||
|
||||
// NB: the AES NewCipher call only fails if the key is an invalid length.
|
||||
|
||||
// ErrInvalidKey is returned when the AES key is invalid.
|
||||
ErrInvalidKey = errors.New("keywrap: invalid AES key")
|
||||
)
|
||||
|
||||
// Wrap a key using the RFC 3394 AES Key Wrap Algorithm.
|
||||
func Wrap(key, plainText []byte) ([]byte, error) {
|
||||
if len(plainText)%8 != 0 {
|
||||
return nil, ErrWrapPlaintext
|
||||
}
|
||||
|
||||
c, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, ErrInvalidKey
|
||||
}
|
||||
|
||||
nblocks := len(plainText) / 8
|
||||
|
||||
// 1) Initialize variables.
|
||||
var block [aes.BlockSize]byte
|
||||
// - Set A = IV, an initial value (see 2.2.3)
|
||||
for ii := 0; ii < 8; ii++ {
|
||||
block[ii] = 0xA6
|
||||
}
|
||||
|
||||
// - For i = 1 to n
|
||||
// - Set R[i] = P[i]
|
||||
intermediate := make([]byte, len(plainText))
|
||||
copy(intermediate, plainText)
|
||||
|
||||
// 2) Calculate intermediate values.
|
||||
for ii := 0; ii < 6; ii++ {
|
||||
for jj := 0; jj < nblocks; jj++ {
|
||||
// - B = AES(K, A | R[i])
|
||||
copy(block[8:], intermediate[jj*8:jj*8+8])
|
||||
c.Encrypt(block[:], block[:])
|
||||
|
||||
// - A = MSB(64, B) ^ t where t = (n*j)+1
|
||||
t := uint64(ii*nblocks + jj + 1)
|
||||
val := binary.BigEndian.Uint64(block[:8]) ^ t
|
||||
binary.BigEndian.PutUint64(block[:8], val)
|
||||
|
||||
// - R[i] = LSB(64, B)
|
||||
copy(intermediate[jj*8:jj*8+8], block[8:])
|
||||
}
|
||||
}
|
||||
|
||||
// 3) Output results.
|
||||
// - Set C[0] = A
|
||||
// - For i = 1 to n
|
||||
// - C[i] = R[i]
|
||||
return append(block[:8], intermediate...), nil
|
||||
}
|
||||
|
||||
// Unwrap a key using the RFC 3394 AES Key Wrap Algorithm.
|
||||
func Unwrap(key, cipherText []byte) ([]byte, error) {
|
||||
if len(cipherText)%8 != 0 {
|
||||
return nil, ErrUnwrapCiphertext
|
||||
}
|
||||
|
||||
c, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, ErrInvalidKey
|
||||
}
|
||||
|
||||
nblocks := len(cipherText)/8 - 1
|
||||
|
||||
// 1) Initialize variables.
|
||||
var block [aes.BlockSize]byte
|
||||
// - Set A = C[0]
|
||||
copy(block[:8], cipherText[:8])
|
||||
|
||||
// - For i = 1 to n
|
||||
// - Set R[i] = C[i]
|
||||
intermediate := make([]byte, len(cipherText)-8)
|
||||
copy(intermediate, cipherText[8:])
|
||||
|
||||
// 2) Compute intermediate values.
|
||||
for jj := 5; jj >= 0; jj-- {
|
||||
for ii := nblocks - 1; ii >= 0; ii-- {
|
||||
// - B = AES-1(K, (A ^ t) | R[i]) where t = n*j+1
|
||||
// - A = MSB(64, B)
|
||||
t := uint64(jj*nblocks + ii + 1)
|
||||
val := binary.BigEndian.Uint64(block[:8]) ^ t
|
||||
binary.BigEndian.PutUint64(block[:8], val)
|
||||
|
||||
copy(block[8:], intermediate[ii*8:ii*8+8])
|
||||
c.Decrypt(block[:], block[:])
|
||||
|
||||
// - R[i] = LSB(B, 64)
|
||||
copy(intermediate[ii*8:ii*8+8], block[8:])
|
||||
}
|
||||
}
|
||||
|
||||
// 3) Output results.
|
||||
// - If A is an appropriate initial value (see 2.2.3),
|
||||
for ii := 0; ii < 8; ii++ {
|
||||
if block[ii] != 0xA6 {
|
||||
return nil, ErrUnwrapFailed
|
||||
}
|
||||
}
|
||||
|
||||
// - For i = 1 to n
|
||||
// - P[i] = R[i]
|
||||
return intermediate, nil
|
||||
}
|
@ -4,13 +4,7 @@
|
||||
|
||||
// Package armor implements OpenPGP ASCII Armor, see RFC 4880. OpenPGP Armor is
|
||||
// very similar to PEM except that it has an additional CRC checksum.
|
||||
//
|
||||
// Deprecated: this package is unmaintained except for security fixes. New
|
||||
// applications should consider a more focused, modern alternative to OpenPGP
|
||||
// for their specific task. If you are required to interoperate with OpenPGP
|
||||
// systems and need a maintained package, consider a community fork.
|
||||
// See https://golang.org/issue/44226.
|
||||
package armor
|
||||
package armor // import "github.com/ProtonMail/go-crypto/openpgp/armor"
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
@ -18,7 +12,7 @@ import (
|
||||
"encoding/base64"
|
||||
"io"
|
||||
|
||||
"golang.org/x/crypto/openpgp/errors"
|
||||
"github.com/ProtonMail/go-crypto/openpgp/errors"
|
||||
)
|
||||
|
||||
// A Block represents an OpenPGP armored structure.
|
||||
@ -29,7 +23,7 @@ import (
|
||||
// Headers
|
||||
//
|
||||
// base64-encoded Bytes
|
||||
// '=' base64 encoded checksum
|
||||
// '=' base64 encoded checksum (optional) not checked anymore
|
||||
// -----END Type-----
|
||||
//
|
||||
// where Headers is a possibly empty sequence of Key: Value lines.
|
||||
@ -46,36 +40,15 @@ type Block struct {
|
||||
|
||||
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.
|
||||
// lineReader wraps a line based reader. It watches for the end of an armor block
|
||||
type lineReader struct {
|
||||
in *bufio.Reader
|
||||
buf []byte
|
||||
eof bool
|
||||
crc uint32
|
||||
crcSet bool
|
||||
in *bufio.Reader
|
||||
buf []byte
|
||||
eof bool
|
||||
}
|
||||
|
||||
func (l *lineReader) Read(p []byte) (n int, err error) {
|
||||
@ -104,26 +77,9 @@ func (l *lineReader) Read(p []byte) (n int, err error) {
|
||||
|
||||
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
|
||||
}
|
||||
// Don't check the checksum
|
||||
|
||||
l.eof = true
|
||||
l.crcSet = true
|
||||
return 0, io.EOF
|
||||
}
|
||||
|
||||
@ -144,23 +100,14 @@ func (l *lineReader) Read(p []byte) (n int, err error) {
|
||||
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.
|
||||
// openpgpReader passes Read calls to the underlying base64 decoder.
|
||||
type openpgpReader struct {
|
||||
lReader *lineReader
|
||||
b64Reader io.Reader
|
||||
currentCRC uint32
|
||||
lReader *lineReader
|
||||
b64Reader io.Reader
|
||||
}
|
||||
|
||||
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 != r.currentCRC&crc24Mask {
|
||||
return 0, ArmorCorrupt
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@ -215,16 +162,19 @@ TryNextBlock:
|
||||
break
|
||||
}
|
||||
|
||||
i := bytes.Index(line, []byte(": "))
|
||||
i := bytes.Index(line, []byte(":"))
|
||||
if i == -1 {
|
||||
goto TryNextBlock
|
||||
}
|
||||
lastKey = string(line[:i])
|
||||
p.Header[lastKey] = string(line[i+2:])
|
||||
var value string
|
||||
if len(line) > i+2 {
|
||||
value = string(line[i+2:])
|
||||
}
|
||||
p.Header[lastKey] = value
|
||||
}
|
||||
|
||||
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
|
@ -7,6 +7,7 @@ package armor
|
||||
import (
|
||||
"encoding/base64"
|
||||
"io"
|
||||
"sort"
|
||||
)
|
||||
|
||||
var armorHeaderSep = []byte(": ")
|
||||
@ -14,6 +15,23 @@ var blockEnd = []byte("\n=")
|
||||
var newline = []byte("\n")
|
||||
var armorEndOfLineOut = []byte("-----\n")
|
||||
|
||||
const crc24Init = 0xb704ce
|
||||
const crc24Poly = 0x1864cfb
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// writeSlices writes its arguments to the given Writer.
|
||||
func writeSlices(out io.Writer, slices ...[]byte) (err error) {
|
||||
for _, s := range slices {
|
||||
@ -99,15 +117,18 @@ func (l *lineBreaker) Close() (err error) {
|
||||
//
|
||||
// encoding -> base64 encoder -> lineBreaker -> out
|
||||
type encoding struct {
|
||||
out io.Writer
|
||||
breaker *lineBreaker
|
||||
b64 io.WriteCloser
|
||||
crc uint32
|
||||
blockType []byte
|
||||
out io.Writer
|
||||
breaker *lineBreaker
|
||||
b64 io.WriteCloser
|
||||
crc uint32
|
||||
crcEnabled bool
|
||||
blockType []byte
|
||||
}
|
||||
|
||||
func (e *encoding) Write(data []byte) (n int, err error) {
|
||||
e.crc = crc24(e.crc, data)
|
||||
if e.crcEnabled {
|
||||
e.crc = crc24(e.crc, data)
|
||||
}
|
||||
return e.b64.Write(data)
|
||||
}
|
||||
|
||||
@ -118,28 +139,36 @@ func (e *encoding) Close() (err error) {
|
||||
}
|
||||
e.breaker.Close()
|
||||
|
||||
var checksumBytes [3]byte
|
||||
checksumBytes[0] = byte(e.crc >> 16)
|
||||
checksumBytes[1] = byte(e.crc >> 8)
|
||||
checksumBytes[2] = byte(e.crc)
|
||||
if e.crcEnabled {
|
||||
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[:])
|
||||
var b64ChecksumBytes [4]byte
|
||||
base64.StdEncoding.Encode(b64ChecksumBytes[:], checksumBytes[:])
|
||||
|
||||
return writeSlices(e.out, blockEnd, b64ChecksumBytes[:], newline, armorEnd, e.blockType, armorEndOfLine)
|
||||
return writeSlices(e.out, blockEnd, b64ChecksumBytes[:], newline, armorEnd, e.blockType, armorEndOfLine)
|
||||
}
|
||||
return writeSlices(e.out, 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) {
|
||||
func encode(out io.Writer, blockType string, headers map[string]string, checksum bool) (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)
|
||||
keys := make([]string, len(headers))
|
||||
i := 0
|
||||
for k := range headers {
|
||||
keys[i] = k
|
||||
i++
|
||||
}
|
||||
sort.Strings(keys)
|
||||
for _, k := range keys {
|
||||
err = writeSlices(out, []byte(k), armorHeaderSep, []byte(headers[k]), newline)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@ -151,11 +180,27 @@ func Encode(out io.Writer, blockType string, headers map[string]string) (w io.Wr
|
||||
}
|
||||
|
||||
e := &encoding{
|
||||
out: out,
|
||||
breaker: newLineBreaker(out, 64),
|
||||
crc: crc24Init,
|
||||
blockType: bType,
|
||||
out: out,
|
||||
breaker: newLineBreaker(out, 64),
|
||||
blockType: bType,
|
||||
crc: crc24Init,
|
||||
crcEnabled: checksum,
|
||||
}
|
||||
e.b64 = base64.NewEncoder(base64.StdEncoding, e.breaker)
|
||||
return e, nil
|
||||
}
|
||||
|
||||
// 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) {
|
||||
return encode(out, blockType, headers, true)
|
||||
}
|
||||
|
||||
// EncodeWithChecksumOption returns a WriteCloser which will encode the data written to it in
|
||||
// OpenPGP armor and provides the option to include a checksum.
|
||||
// When forming ASCII Armor, the CRC24 footer SHOULD NOT be generated,
|
||||
// unless interoperability with implementations that require the CRC24 footer
|
||||
// to be present is a concern.
|
||||
func EncodeWithChecksumOption(out io.Writer, blockType string, headers map[string]string, doChecksum bool) (w io.WriteCloser, err error) {
|
||||
return encode(out, blockType, headers, doChecksum)
|
||||
}
|
@ -4,7 +4,10 @@
|
||||
|
||||
package openpgp
|
||||
|
||||
import "hash"
|
||||
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.
|
||||
@ -19,28 +22,37 @@ type canonicalTextHash struct {
|
||||
|
||||
var newline = []byte{'\r', '\n'}
|
||||
|
||||
func (cth *canonicalTextHash) Write(buf []byte) (int, error) {
|
||||
func writeCanonical(cw io.Writer, buf []byte, s *int) (int, error) {
|
||||
start := 0
|
||||
|
||||
for i, c := range buf {
|
||||
switch cth.s {
|
||||
switch *s {
|
||||
case 0:
|
||||
if c == '\r' {
|
||||
cth.s = 1
|
||||
*s = 1
|
||||
} else if c == '\n' {
|
||||
cth.h.Write(buf[start:i])
|
||||
cth.h.Write(newline)
|
||||
if _, err := cw.Write(buf[start:i]); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if _, err := cw.Write(newline); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
start = i + 1
|
||||
}
|
||||
case 1:
|
||||
cth.s = 0
|
||||
*s = 0
|
||||
}
|
||||
}
|
||||
|
||||
cth.h.Write(buf[start:])
|
||||
if _, err := cw.Write(buf[start:]); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
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)
|
||||
}
|
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
|
||||
}
|
||||
if _, err := param.Write(fingerprint[:]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 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())
|
||||
}
|
115
vendor/github.com/ProtonMail/go-crypto/openpgp/ed25519/ed25519.go
generated
vendored
Normal file
115
vendor/github.com/ProtonMail/go-crypto/openpgp/ed25519/ed25519.go
generated
vendored
Normal file
@ -0,0 +1,115 @@
|
||||
// Package ed25519 implements the ed25519 signature algorithm for OpenPGP
|
||||
// as defined in the Open PGP crypto refresh.
|
||||
package ed25519
|
||||
|
||||
import (
|
||||
"crypto/subtle"
|
||||
"io"
|
||||
|
||||
"github.com/ProtonMail/go-crypto/openpgp/errors"
|
||||
ed25519lib "github.com/cloudflare/circl/sign/ed25519"
|
||||
)
|
||||
|
||||
const (
|
||||
// PublicKeySize is the size, in bytes, of public keys in this package.
|
||||
PublicKeySize = ed25519lib.PublicKeySize
|
||||
// SeedSize is the size, in bytes, of private key seeds.
|
||||
// The private key representation used by RFC 8032.
|
||||
SeedSize = ed25519lib.SeedSize
|
||||
// SignatureSize is the size, in bytes, of signatures generated and verified by this package.
|
||||
SignatureSize = ed25519lib.SignatureSize
|
||||
)
|
||||
|
||||
type PublicKey struct {
|
||||
// Point represents the elliptic curve point of the public key.
|
||||
Point []byte
|
||||
}
|
||||
|
||||
type PrivateKey struct {
|
||||
PublicKey
|
||||
// Key the private key representation by RFC 8032,
|
||||
// encoded as seed | pub key point.
|
||||
Key []byte
|
||||
}
|
||||
|
||||
// NewPublicKey creates a new empty ed25519 public key.
|
||||
func NewPublicKey() *PublicKey {
|
||||
return &PublicKey{}
|
||||
}
|
||||
|
||||
// NewPrivateKey creates a new empty private key referencing the public key.
|
||||
func NewPrivateKey(key PublicKey) *PrivateKey {
|
||||
return &PrivateKey{
|
||||
PublicKey: key,
|
||||
}
|
||||
}
|
||||
|
||||
// Seed returns the ed25519 private key secret seed.
|
||||
// The private key representation by RFC 8032.
|
||||
func (pk *PrivateKey) Seed() []byte {
|
||||
return pk.Key[:SeedSize]
|
||||
}
|
||||
|
||||
// MarshalByteSecret returns the underlying 32 byte seed of the private key.
|
||||
func (pk *PrivateKey) MarshalByteSecret() []byte {
|
||||
return pk.Seed()
|
||||
}
|
||||
|
||||
// UnmarshalByteSecret computes the private key from the secret seed
|
||||
// and stores it in the private key object.
|
||||
func (sk *PrivateKey) UnmarshalByteSecret(seed []byte) error {
|
||||
sk.Key = ed25519lib.NewKeyFromSeed(seed)
|
||||
return nil
|
||||
}
|
||||
|
||||
// GenerateKey generates a fresh private key with the provided randomness source.
|
||||
func GenerateKey(rand io.Reader) (*PrivateKey, error) {
|
||||
publicKey, privateKey, err := ed25519lib.GenerateKey(rand)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
privateKeyOut := new(PrivateKey)
|
||||
privateKeyOut.PublicKey.Point = publicKey[:]
|
||||
privateKeyOut.Key = privateKey[:]
|
||||
return privateKeyOut, nil
|
||||
}
|
||||
|
||||
// Sign signs a message with the ed25519 algorithm.
|
||||
// priv MUST be a valid key! Check this with Validate() before use.
|
||||
func Sign(priv *PrivateKey, message []byte) ([]byte, error) {
|
||||
return ed25519lib.Sign(priv.Key, message), nil
|
||||
}
|
||||
|
||||
// Verify verifies an ed25519 signature.
|
||||
func Verify(pub *PublicKey, message []byte, signature []byte) bool {
|
||||
return ed25519lib.Verify(pub.Point, message, signature)
|
||||
}
|
||||
|
||||
// Validate checks if the ed25519 private key is valid.
|
||||
func Validate(priv *PrivateKey) error {
|
||||
expectedPrivateKey := ed25519lib.NewKeyFromSeed(priv.Seed())
|
||||
if subtle.ConstantTimeCompare(priv.Key, expectedPrivateKey) == 0 {
|
||||
return errors.KeyInvalidError("ed25519: invalid ed25519 secret")
|
||||
}
|
||||
if subtle.ConstantTimeCompare(priv.PublicKey.Point, expectedPrivateKey[SeedSize:]) == 0 {
|
||||
return errors.KeyInvalidError("ed25519: invalid ed25519 public key")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ENCODING/DECODING signature:
|
||||
|
||||
// WriteSignature encodes and writes an ed25519 signature to writer.
|
||||
func WriteSignature(writer io.Writer, signature []byte) error {
|
||||
_, err := writer.Write(signature)
|
||||
return err
|
||||
}
|
||||
|
||||
// ReadSignature decodes an ed25519 signature from a reader.
|
||||
func ReadSignature(reader io.Reader) ([]byte, error) {
|
||||
signature := make([]byte, SignatureSize)
|
||||
if _, err := io.ReadFull(reader, signature); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return signature, nil
|
||||
}
|
119
vendor/github.com/ProtonMail/go-crypto/openpgp/ed448/ed448.go
generated
vendored
Normal file
119
vendor/github.com/ProtonMail/go-crypto/openpgp/ed448/ed448.go
generated
vendored
Normal file
@ -0,0 +1,119 @@
|
||||
// Package ed448 implements the ed448 signature algorithm for OpenPGP
|
||||
// as defined in the Open PGP crypto refresh.
|
||||
package ed448
|
||||
|
||||
import (
|
||||
"crypto/subtle"
|
||||
"io"
|
||||
|
||||
"github.com/ProtonMail/go-crypto/openpgp/errors"
|
||||
ed448lib "github.com/cloudflare/circl/sign/ed448"
|
||||
)
|
||||
|
||||
const (
|
||||
// PublicKeySize is the size, in bytes, of public keys in this package.
|
||||
PublicKeySize = ed448lib.PublicKeySize
|
||||
// SeedSize is the size, in bytes, of private key seeds.
|
||||
// The private key representation used by RFC 8032.
|
||||
SeedSize = ed448lib.SeedSize
|
||||
// SignatureSize is the size, in bytes, of signatures generated and verified by this package.
|
||||
SignatureSize = ed448lib.SignatureSize
|
||||
)
|
||||
|
||||
type PublicKey struct {
|
||||
// Point represents the elliptic curve point of the public key.
|
||||
Point []byte
|
||||
}
|
||||
|
||||
type PrivateKey struct {
|
||||
PublicKey
|
||||
// Key the private key representation by RFC 8032,
|
||||
// encoded as seed | public key point.
|
||||
Key []byte
|
||||
}
|
||||
|
||||
// NewPublicKey creates a new empty ed448 public key.
|
||||
func NewPublicKey() *PublicKey {
|
||||
return &PublicKey{}
|
||||
}
|
||||
|
||||
// NewPrivateKey creates a new empty private key referencing the public key.
|
||||
func NewPrivateKey(key PublicKey) *PrivateKey {
|
||||
return &PrivateKey{
|
||||
PublicKey: key,
|
||||
}
|
||||
}
|
||||
|
||||
// Seed returns the ed448 private key secret seed.
|
||||
// The private key representation by RFC 8032.
|
||||
func (pk *PrivateKey) Seed() []byte {
|
||||
return pk.Key[:SeedSize]
|
||||
}
|
||||
|
||||
// MarshalByteSecret returns the underlying seed of the private key.
|
||||
func (pk *PrivateKey) MarshalByteSecret() []byte {
|
||||
return pk.Seed()
|
||||
}
|
||||
|
||||
// UnmarshalByteSecret computes the private key from the secret seed
|
||||
// and stores it in the private key object.
|
||||
func (sk *PrivateKey) UnmarshalByteSecret(seed []byte) error {
|
||||
sk.Key = ed448lib.NewKeyFromSeed(seed)
|
||||
return nil
|
||||
}
|
||||
|
||||
// GenerateKey generates a fresh private key with the provided randomness source.
|
||||
func GenerateKey(rand io.Reader) (*PrivateKey, error) {
|
||||
publicKey, privateKey, err := ed448lib.GenerateKey(rand)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
privateKeyOut := new(PrivateKey)
|
||||
privateKeyOut.PublicKey.Point = publicKey[:]
|
||||
privateKeyOut.Key = privateKey[:]
|
||||
return privateKeyOut, nil
|
||||
}
|
||||
|
||||
// Sign signs a message with the ed448 algorithm.
|
||||
// priv MUST be a valid key! Check this with Validate() before use.
|
||||
func Sign(priv *PrivateKey, message []byte) ([]byte, error) {
|
||||
// Ed448 is used with the empty string as a context string.
|
||||
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-08#section-13.7
|
||||
return ed448lib.Sign(priv.Key, message, ""), nil
|
||||
}
|
||||
|
||||
// Verify verifies a ed448 signature
|
||||
func Verify(pub *PublicKey, message []byte, signature []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-08#section-13.7
|
||||
return ed448lib.Verify(pub.Point, message, signature, "")
|
||||
}
|
||||
|
||||
// Validate checks if the ed448 private key is valid
|
||||
func Validate(priv *PrivateKey) error {
|
||||
expectedPrivateKey := ed448lib.NewKeyFromSeed(priv.Seed())
|
||||
if subtle.ConstantTimeCompare(priv.Key, expectedPrivateKey) == 0 {
|
||||
return errors.KeyInvalidError("ed448: invalid ed448 secret")
|
||||
}
|
||||
if subtle.ConstantTimeCompare(priv.PublicKey.Point, expectedPrivateKey[SeedSize:]) == 0 {
|
||||
return errors.KeyInvalidError("ed448: invalid ed448 public key")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ENCODING/DECODING signature:
|
||||
|
||||
// WriteSignature encodes and writes an ed448 signature to writer.
|
||||
func WriteSignature(writer io.Writer, signature []byte) error {
|
||||
_, err := writer.Write(signature)
|
||||
return err
|
||||
}
|
||||
|
||||
// ReadSignature decodes an ed448 signature from a reader.
|
||||
func ReadSignature(reader io.Reader) ([]byte, error) {
|
||||
signature := make([]byte, SignatureSize)
|
||||
if _, err := io.ReadFull(reader, signature); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return signature, nil
|
||||
}
|
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)
|
||||
}
|
@ -10,13 +10,7 @@
|
||||
// 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.
|
||||
//
|
||||
// Deprecated: this package was only provided to support ElGamal encryption in
|
||||
// OpenPGP. The golang.org/x/crypto/openpgp package is now deprecated (see
|
||||
// https://golang.org/issue/44226), and ElGamal in the OpenPGP ecosystem has
|
||||
// compatibility and security issues (see https://eprint.iacr.org/2021/923).
|
||||
// Moreover, this package doesn't protect against side-channel attacks.
|
||||
package elgamal
|
||||
package elgamal // import "github.com/ProtonMail/go-crypto/openpgp/elgamal"
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
200
vendor/github.com/ProtonMail/go-crypto/openpgp/errors/errors.go
generated
vendored
Normal file
200
vendor/github.com/ProtonMail/go-crypto/openpgp/errors/errors.go
generated
vendored
Normal file
@ -0,0 +1,200 @@
|
||||
// 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 (
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrDecryptSessionKeyParsing is a generic error message for parsing errors in decrypted data
|
||||
// to reduce the risk of oracle attacks.
|
||||
ErrDecryptSessionKeyParsing = DecryptWithSessionKeyError("parsing error")
|
||||
// ErrAEADTagVerification is returned if one of the tag verifications in SEIPDv2 fails
|
||||
ErrAEADTagVerification error = DecryptWithSessionKeyError("AEAD tag verification failed")
|
||||
// ErrMDCHashMismatch
|
||||
ErrMDCHashMismatch error = SignatureError("MDC hash mismatch")
|
||||
// ErrMDCMissing
|
||||
ErrMDCMissing error = SignatureError("MDC packet not found")
|
||||
)
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// A DecryptWithSessionKeyError is returned when a failure occurs when reading from symmetrically decrypted data or
|
||||
// an authentication tag verification fails.
|
||||
// Such an error indicates that the supplied session key is likely wrong or the data got corrupted.
|
||||
type DecryptWithSessionKeyError string
|
||||
|
||||
func (s DecryptWithSessionKeyError) Error() string {
|
||||
return "openpgp: decryption with session key failed: " + string(s)
|
||||
}
|
||||
|
||||
// HandleSensitiveParsingError handles parsing errors when reading data from potentially decrypted data.
|
||||
// The function makes parsing errors generic to reduce the risk of oracle attacks in SEIPDv1.
|
||||
func HandleSensitiveParsingError(err error, decrypted bool) error {
|
||||
if !decrypted {
|
||||
// Data was not encrypted so we return the inner error.
|
||||
return err
|
||||
}
|
||||
// The data is read from a stream that decrypts using a session key;
|
||||
// therefore, we need to handle parsing errors appropriately.
|
||||
// This is essential to mitigate the risk of oracle attacks.
|
||||
if decError, ok := err.(*DecryptWithSessionKeyError); ok {
|
||||
return decError
|
||||
}
|
||||
if decError, ok := err.(DecryptWithSessionKeyError); ok {
|
||||
return decError
|
||||
}
|
||||
return ErrDecryptSessionKeyParsing
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
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 ErrSignatureOlderThanKey error = signatureOlderThanKeyError(0)
|
||||
|
||||
type signatureOlderThanKeyError int
|
||||
|
||||
func (ske signatureOlderThanKeyError) Error() string {
|
||||
return "openpgp: signature is older than the key"
|
||||
}
|
||||
|
||||
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 WeakAlgorithmError string
|
||||
|
||||
func (e WeakAlgorithmError) Error() string {
|
||||
return "openpgp: weak algorithms are rejected: " + string(e)
|
||||
}
|
||||
|
||||
type UnknownPacketTypeError uint8
|
||||
|
||||
func (upte UnknownPacketTypeError) Error() string {
|
||||
return "openpgp: unknown packet type: " + strconv.Itoa(int(upte))
|
||||
}
|
||||
|
||||
type CriticalUnknownPacketTypeError uint8
|
||||
|
||||
func (upte CriticalUnknownPacketTypeError) Error() string {
|
||||
return "openpgp: unknown critical 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)
|
||||
}
|
||||
|
||||
// ErrMalformedMessage results when the packet sequence is incorrect
|
||||
type ErrMalformedMessage string
|
||||
|
||||
func (dke ErrMalformedMessage) Error() string {
|
||||
return "openpgp: malformed message " + string(dke)
|
||||
}
|
||||
|
||||
// ErrEncryptionKeySelection is returned if encryption key selection fails (v2 API).
|
||||
type ErrEncryptionKeySelection struct {
|
||||
PrimaryKeyId string
|
||||
PrimaryKeyErr error
|
||||
EncSelectionKeyId *string
|
||||
EncSelectionErr error
|
||||
}
|
||||
|
||||
func (eks ErrEncryptionKeySelection) Error() string {
|
||||
prefix := fmt.Sprintf("openpgp: key selection for primary key %s:", eks.PrimaryKeyId)
|
||||
if eks.PrimaryKeyErr != nil {
|
||||
return fmt.Sprintf("%s invalid primary key: %s", prefix, eks.PrimaryKeyErr)
|
||||
}
|
||||
if eks.EncSelectionKeyId != nil {
|
||||
return fmt.Sprintf("%s invalid encryption key %s: %s", prefix, *eks.EncSelectionKeyId, eks.EncSelectionErr)
|
||||
}
|
||||
return fmt.Sprintf("%s no encryption key: %s", prefix, eks.EncSelectionErr)
|
||||
}
|
24
vendor/github.com/ProtonMail/go-crypto/openpgp/hash.go
generated
vendored
Normal file
24
vendor/github.com/ProtonMail/go-crypto/openpgp/hash.go
generated
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
package openpgp
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
|
||||
"github.com/ProtonMail/go-crypto/openpgp/internal/algorithm"
|
||||
)
|
||||
|
||||
// HashIdToHash returns a crypto.Hash which corresponds to the given OpenPGP
|
||||
// hash id.
|
||||
func HashIdToHash(id byte) (h crypto.Hash, ok bool) {
|
||||
return algorithm.HashIdToHash(id)
|
||||
}
|
||||
|
||||
// HashIdToString returns the name of the hash function corresponding to the
|
||||
// given OpenPGP hash id.
|
||||
func HashIdToString(id byte) (name string, ok bool) {
|
||||
return algorithm.HashIdToString(id)
|
||||
}
|
||||
|
||||
// HashToHashId returns an OpenPGP hash id which corresponds the given Hash.
|
||||
func HashToHashId(h crypto.Hash) (id byte, ok bool) {
|
||||
return algorithm.HashToHashId(h)
|
||||
}
|
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(3)
|
||||
)
|
||||
|
||||
// TagLength returns the length in bytes of authentication tags.
|
||||
func (mode AEADMode) TagLength() int {
|
||||
switch mode {
|
||||
case AEADModeEAX:
|
||||
return 16
|
||||
case AEADModeOCB:
|
||||
return 16
|
||||
case AEADModeGCM:
|
||||
return 16
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
// NonceLength returns the length in bytes of nonces.
|
||||
func (mode AEADMode) NonceLength() int {
|
||||
switch mode {
|
||||
case AEADModeEAX:
|
||||
return 16
|
||||
case AEADModeOCB:
|
||||
return 15
|
||||
case AEADModeGCM:
|
||||
return 12
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
// New returns a fresh instance of the given mode
|
||||
func (mode AEADMode) New(block cipher.Block) (alg cipher.AEAD) {
|
||||
var err error
|
||||
switch mode {
|
||||
case AEADModeEAX:
|
||||
alg, err = eax.NewEAX(block)
|
||||
case AEADModeOCB:
|
||||
alg, err = ocb.NewOCB(block)
|
||||
case AEADModeGCM:
|
||||
alg, err = cipher.NewGCM(block)
|
||||
}
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
return alg
|
||||
}
|
97
vendor/github.com/ProtonMail/go-crypto/openpgp/internal/algorithm/cipher.go
generated
vendored
Normal file
97
vendor/github.com/ProtonMail/go-crypto/openpgp/internal/algorithm/cipher.go
generated
vendored
Normal file
@ -0,0 +1,97 @@
|
||||
// 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)
|
||||
}
|
||||
|
||||
// KeySize returns the key size, in bytes, of cipher.
|
||||
func (cipher CipherFunction) KeySize() int {
|
||||
switch cipher {
|
||||
case CAST5:
|
||||
return cast5.KeySize
|
||||
case AES128:
|
||||
return 16
|
||||
case AES192, TripleDES:
|
||||
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
|
||||
}
|
143
vendor/github.com/ProtonMail/go-crypto/openpgp/internal/algorithm/hash.go
generated
vendored
Normal file
143
vendor/github.com/ProtonMail/go-crypto/openpgp/internal/algorithm/hash.go
generated
vendored
Normal file
@ -0,0 +1,143 @@
|
||||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package algorithm
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"fmt"
|
||||
"hash"
|
||||
)
|
||||
|
||||
// Hash is an official hash function algorithm. See RFC 4880, section 9.4.
|
||||
type Hash interface {
|
||||
// Id returns the algorithm ID, as a byte, of Hash.
|
||||
Id() uint8
|
||||
// Available reports whether the given hash function is linked into the binary.
|
||||
Available() bool
|
||||
// HashFunc simply returns the value of h so that Hash implements SignerOpts.
|
||||
HashFunc() crypto.Hash
|
||||
// New returns a new hash.Hash calculating the given hash function. New
|
||||
// panics if the hash function is not linked into the binary.
|
||||
New() hash.Hash
|
||||
// Size returns the length, in bytes, of a digest resulting from the given
|
||||
// hash function. It doesn't require that the hash function in question be
|
||||
// linked into the program.
|
||||
Size() int
|
||||
// String is the name of the hash function corresponding to the given
|
||||
// OpenPGP hash id.
|
||||
String() string
|
||||
}
|
||||
|
||||
// The following vars mirror the crypto/Hash supported hash functions.
|
||||
var (
|
||||
SHA1 Hash = cryptoHash{2, crypto.SHA1}
|
||||
SHA256 Hash = cryptoHash{8, crypto.SHA256}
|
||||
SHA384 Hash = cryptoHash{9, crypto.SHA384}
|
||||
SHA512 Hash = cryptoHash{10, crypto.SHA512}
|
||||
SHA224 Hash = cryptoHash{11, crypto.SHA224}
|
||||
SHA3_256 Hash = cryptoHash{12, crypto.SHA3_256}
|
||||
SHA3_512 Hash = cryptoHash{14, crypto.SHA3_512}
|
||||
)
|
||||
|
||||
// HashById represents the different hash functions specified for OpenPGP. See
|
||||
// http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-14
|
||||
var (
|
||||
HashById = map[uint8]Hash{
|
||||
SHA256.Id(): SHA256,
|
||||
SHA384.Id(): SHA384,
|
||||
SHA512.Id(): SHA512,
|
||||
SHA224.Id(): SHA224,
|
||||
SHA3_256.Id(): SHA3_256,
|
||||
SHA3_512.Id(): SHA3_512,
|
||||
}
|
||||
)
|
||||
|
||||
// cryptoHash contains pairs relating OpenPGP's hash identifier with
|
||||
// Go's crypto.Hash type. See RFC 4880, section 9.4.
|
||||
type cryptoHash struct {
|
||||
id uint8
|
||||
crypto.Hash
|
||||
}
|
||||
|
||||
// Id returns the algorithm ID, as a byte, of cryptoHash.
|
||||
func (h cryptoHash) Id() uint8 {
|
||||
return h.id
|
||||
}
|
||||
|
||||
var hashNames = map[uint8]string{
|
||||
SHA256.Id(): "SHA256",
|
||||
SHA384.Id(): "SHA384",
|
||||
SHA512.Id(): "SHA512",
|
||||
SHA224.Id(): "SHA224",
|
||||
SHA3_256.Id(): "SHA3-256",
|
||||
SHA3_512.Id(): "SHA3-512",
|
||||
}
|
||||
|
||||
func (h cryptoHash) String() string {
|
||||
s, ok := hashNames[h.id]
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("Unsupported hash function %d", h.id))
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// HashIdToHash returns a crypto.Hash which corresponds to the given OpenPGP
|
||||
// hash id.
|
||||
func HashIdToHash(id byte) (h crypto.Hash, ok bool) {
|
||||
if hash, ok := HashById[id]; ok {
|
||||
return hash.HashFunc(), true
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// HashIdToHashWithSha1 returns a crypto.Hash which corresponds to the given OpenPGP
|
||||
// hash id, allowing sha1.
|
||||
func HashIdToHashWithSha1(id byte) (h crypto.Hash, ok bool) {
|
||||
if hash, ok := HashById[id]; ok {
|
||||
return hash.HashFunc(), true
|
||||
}
|
||||
|
||||
if id == SHA1.Id() {
|
||||
return SHA1.HashFunc(), true
|
||||
}
|
||||
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// HashIdToString returns the name of the hash function corresponding to the
|
||||
// given OpenPGP hash id.
|
||||
func HashIdToString(id byte) (name string, ok bool) {
|
||||
if hash, ok := HashById[id]; ok {
|
||||
return hash.String(), true
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
// HashToHashId returns an OpenPGP hash id which corresponds the given Hash.
|
||||
func HashToHashId(h crypto.Hash) (id byte, ok bool) {
|
||||
for id, hash := range HashById {
|
||||
if hash.HashFunc() == h {
|
||||
return id, true
|
||||
}
|
||||
}
|
||||
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// HashToHashIdWithSha1 returns an OpenPGP hash id which corresponds the given Hash,
|
||||
// allowing instances of SHA1
|
||||
func HashToHashIdWithSha1(h crypto.Hash) (id byte, ok bool) {
|
||||
for id, hash := range HashById {
|
||||
if hash.HashFunc() == h {
|
||||
return id, true
|
||||
}
|
||||
}
|
||||
|
||||
if h == SHA1.HashFunc() {
|
||||
return SHA1.Id(), true
|
||||
}
|
||||
|
||||
return 0, false
|
||||
}
|
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]
|
||||
}
|
||||
}
|
143
vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/curve_info.go
generated
vendored
Normal file
143
vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/curve_info.go
generated
vendored
Normal file
@ -0,0 +1,143 @@
|
||||
// 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"
|
||||
)
|
||||
|
||||
const Curve25519GenName = "Curve25519"
|
||||
|
||||
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: Curve25519GenName,
|
||||
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: Curve25519GenName,
|
||||
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
|
||||
}
|
120
vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/ed25519.go
generated
vendored
Normal file
120
vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/ed25519.go
generated
vendored
Normal file
@ -0,0 +1,120 @@
|
||||
// Package ecc implements a generic interface for ECDH, ECDSA, and EdDSA.
|
||||
package ecc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"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 {
|
||||
privateKeyCap, privateKeyLen, publicKeyLen := cap(privateKey), len(privateKey), len(publicKey)
|
||||
|
||||
if privateKeyCap >= privateKeyLen+publicKeyLen &&
|
||||
bytes.Equal(privateKey[privateKeyLen:privateKeyLen+publicKeyLen], publicKey) {
|
||||
return privateKey[:privateKeyLen+publicKeyLen]
|
||||
}
|
||||
|
||||
return append(privateKey[:privateKeyLen:privateKeyLen], 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
|
||||
}
|
119
vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/ed448.go
generated
vendored
Normal file
119
vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/ed448.go
generated
vendored
Normal file
@ -0,0 +1,119 @@
|
||||
// Package ecc implements a generic interface for ECDH, ECDSA, and EdDSA.
|
||||
package ecc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"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 {
|
||||
privateKeyCap, privateKeyLen, publicKeyLen := cap(privateKey), len(privateKey), len(publicKey)
|
||||
|
||||
if privateKeyCap >= privateKeyLen+publicKeyLen &&
|
||||
bytes.Equal(privateKey[privateKeyLen:privateKeyLen+publicKeyLen], publicKey) {
|
||||
return privateKey[:privateKeyLen+publicKeyLen]
|
||||
}
|
||||
|
||||
return append(privateKey[:privateKeyLen:privateKeyLen], 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)
|
||||
}
|
107
vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/x448.go
generated
vendored
Normal file
107
vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/x448.go
generated
vendored
Normal file
@ -0,0 +1,107 @@
|
||||
// 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)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
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
|
||||
}
|
456
vendor/github.com/ProtonMail/go-crypto/openpgp/key_generation.go
generated
vendored
Normal file
456
vendor/github.com/ProtonMail/go-crypto/openpgp/key_generation.go
generated
vendored
Normal file
@ -0,0 +1,456 @@
|
||||
// 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/ed25519"
|
||||
"github.com/ProtonMail/go-crypto/openpgp/ed448"
|
||||
"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"
|
||||
"github.com/ProtonMail/go-crypto/openpgp/x25519"
|
||||
"github.com/ProtonMail/go-crypto/openpgp/x448"
|
||||
)
|
||||
|
||||
// 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.V6() {
|
||||
if err := primary.UpgradeToV6(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
e := &Entity{
|
||||
PrimaryKey: &primary.PublicKey,
|
||||
PrivateKey: primary,
|
||||
Identities: make(map[string]*Identity),
|
||||
Subkeys: []Subkey{},
|
||||
Signatures: []*packet.Signature{},
|
||||
}
|
||||
|
||||
if config.V6() {
|
||||
// In v6 keys algorithm preferences should be stored in direct key signatures
|
||||
selfSignature := createSignaturePacket(&primary.PublicKey, packet.SigTypeDirectSignature, config)
|
||||
err = writeKeyProperties(selfSignature, creationTime, keyLifetimeSecs, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = selfSignature.SignDirectKeyBinding(&primary.PublicKey, primary, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
e.Signatures = append(e.Signatures, selfSignature)
|
||||
e.SelfSignature = selfSignature
|
||||
}
|
||||
|
||||
err = e.addUserId(name, comment, email, config, creationTime, keyLifetimeSecs, !config.V6())
|
||||
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, !config.V6())
|
||||
}
|
||||
|
||||
func writeKeyProperties(selfSignature *packet.Signature, creationTime time.Time, keyLifetimeSecs uint32, config *packet.Config) error {
|
||||
advertiseAead := config.AEAD() != nil
|
||||
|
||||
selfSignature.CreationTime = creationTime
|
||||
selfSignature.KeyLifetimeSecs = &keyLifetimeSecs
|
||||
selfSignature.FlagsValid = true
|
||||
selfSignature.FlagSign = true
|
||||
selfSignature.FlagCertify = true
|
||||
selfSignature.SEIPDv1 = true // true by default, see 5.8 vs. 5.14
|
||||
selfSignature.SEIPDv2 = advertiseAead
|
||||
|
||||
// Set the PreferredHash for the SelfSignature from the packet.Config.
|
||||
// If it is not the must-implement algorithm from rfc4880bis, append that.
|
||||
hash, ok := algorithm.HashToHashId(config.Hash())
|
||||
if !ok {
|
||||
return errors.UnsupportedError("unsupported preferred hash function")
|
||||
}
|
||||
|
||||
selfSignature.PreferredHash = []uint8{hash}
|
||||
if config.Hash() != crypto.SHA256 {
|
||||
selfSignature.PreferredHash = append(selfSignature.PreferredHash, hashToHashId(crypto.SHA256))
|
||||
}
|
||||
|
||||
// Likewise for DefaultCipher.
|
||||
selfSignature.PreferredSymmetric = []uint8{uint8(config.Cipher())}
|
||||
if config.Cipher() != packet.CipherAES128 {
|
||||
selfSignature.PreferredSymmetric = append(selfSignature.PreferredSymmetric, uint8(packet.CipherAES128))
|
||||
}
|
||||
|
||||
// We set CompressionNone as the preferred compression algorithm because
|
||||
// of compression side channel attacks, then append the configured
|
||||
// DefaultCompressionAlgo if any is set (to signal support for cases
|
||||
// where the application knows that using compression is safe).
|
||||
selfSignature.PreferredCompression = []uint8{uint8(packet.CompressionNone)}
|
||||
if config.Compression() != packet.CompressionNone {
|
||||
selfSignature.PreferredCompression = append(selfSignature.PreferredCompression, uint8(config.Compression()))
|
||||
}
|
||||
|
||||
if advertiseAead {
|
||||
// Get the preferred AEAD mode from the packet.Config.
|
||||
// If it is not the must-implement algorithm from rfc9580, append that.
|
||||
modes := []uint8{uint8(config.AEAD().Mode())}
|
||||
if config.AEAD().Mode() != packet.AEADModeOCB {
|
||||
modes = append(modes, uint8(packet.AEADModeOCB))
|
||||
}
|
||||
|
||||
// For preferred (AES256, GCM), we'll generate (AES256, GCM), (AES256, OCB), (AES128, GCM), (AES128, OCB)
|
||||
for _, cipher := range selfSignature.PreferredSymmetric {
|
||||
for _, mode := range modes {
|
||||
selfSignature.PreferredCipherSuites = append(selfSignature.PreferredCipherSuites, [2]uint8{cipher, mode})
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Entity) addUserId(name, comment, email string, config *packet.Config, creationTime time.Time, keyLifetimeSecs uint32, writeProperties bool) error {
|
||||
uid := packet.NewUserId(name, comment, email)
|
||||
if uid == nil {
|
||||
return errors.InvalidArgumentError("user id field contained invalid characters")
|
||||
}
|
||||
|
||||
if _, ok := t.Identities[uid.Id]; ok {
|
||||
return errors.InvalidArgumentError("user id exist")
|
||||
}
|
||||
|
||||
primary := t.PrivateKey
|
||||
isPrimaryId := len(t.Identities) == 0
|
||||
selfSignature := createSignaturePacket(&primary.PublicKey, packet.SigTypePositiveCert, config)
|
||||
if writeProperties {
|
||||
err := writeKeyProperties(selfSignature, creationTime, keyLifetimeSecs, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
selfSignature.IsPrimaryId = &isPrimaryId
|
||||
|
||||
// User ID binding signature
|
||||
err := selfSignature.SignUserId(uid.Id, &primary.PublicKey, primary, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
t.Identities[uid.Id] = &Identity{
|
||||
Name: uid.Id,
|
||||
UserId: uid,
|
||||
SelfSignature: selfSignature,
|
||||
Signatures: []*packet.Signature{selfSignature},
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddSigningSubkey adds a signing keypair as a subkey to the Entity.
|
||||
// If config is nil, sensible defaults will be used.
|
||||
func (e *Entity) AddSigningSubkey(config *packet.Config) error {
|
||||
creationTime := config.Now()
|
||||
keyLifetimeSecs := config.KeyLifetime()
|
||||
|
||||
subPrivRaw, err := newSigner(config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sub := packet.NewSignerPrivateKey(creationTime, subPrivRaw)
|
||||
sub.IsSubkey = true
|
||||
if config.V6() {
|
||||
if err := sub.UpgradeToV6(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
subkey := Subkey{
|
||||
PublicKey: &sub.PublicKey,
|
||||
PrivateKey: sub,
|
||||
}
|
||||
subkey.Sig = createSignaturePacket(e.PrimaryKey, packet.SigTypeSubkeyBinding, config)
|
||||
subkey.Sig.CreationTime = creationTime
|
||||
subkey.Sig.KeyLifetimeSecs = &keyLifetimeSecs
|
||||
subkey.Sig.FlagsValid = true
|
||||
subkey.Sig.FlagSign = true
|
||||
subkey.Sig.EmbeddedSignature = createSignaturePacket(subkey.PublicKey, packet.SigTypePrimaryKeyBinding, config)
|
||||
subkey.Sig.EmbeddedSignature.CreationTime = creationTime
|
||||
|
||||
err = subkey.Sig.EmbeddedSignature.CrossSignKey(subkey.PublicKey, e.PrimaryKey, subkey.PrivateKey, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = subkey.Sig.SignKey(subkey.PublicKey, e.PrivateKey, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
e.Subkeys = append(e.Subkeys, subkey)
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddEncryptionSubkey adds an encryption keypair as a subkey to the Entity.
|
||||
// If config is nil, sensible defaults will be used.
|
||||
func (e *Entity) AddEncryptionSubkey(config *packet.Config) error {
|
||||
creationTime := config.Now()
|
||||
keyLifetimeSecs := config.KeyLifetime()
|
||||
return e.addEncryptionSubkey(config, creationTime, keyLifetimeSecs)
|
||||
}
|
||||
|
||||
func (e *Entity) addEncryptionSubkey(config *packet.Config, creationTime time.Time, keyLifetimeSecs uint32) error {
|
||||
subPrivRaw, err := newDecrypter(config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sub := packet.NewDecrypterPrivateKey(creationTime, subPrivRaw)
|
||||
sub.IsSubkey = true
|
||||
if config.V6() {
|
||||
if err := sub.UpgradeToV6(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
subkey := Subkey{
|
||||
PublicKey: &sub.PublicKey,
|
||||
PrivateKey: sub,
|
||||
}
|
||||
subkey.Sig = createSignaturePacket(e.PrimaryKey, packet.SigTypeSubkeyBinding, config)
|
||||
subkey.Sig.CreationTime = creationTime
|
||||
subkey.Sig.KeyLifetimeSecs = &keyLifetimeSecs
|
||||
subkey.Sig.FlagsValid = true
|
||||
subkey.Sig.FlagEncryptStorage = true
|
||||
subkey.Sig.FlagEncryptCommunications = true
|
||||
|
||||
err = subkey.Sig.SignKey(subkey.PublicKey, e.PrivateKey, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
e.Subkeys = append(e.Subkeys, subkey)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Generates a signing key
|
||||
func newSigner(config *packet.Config) (signer interface{}, err error) {
|
||||
switch config.PublicKeyAlgorithm() {
|
||||
case packet.PubKeyAlgoRSA:
|
||||
bits := config.RSAModulusBits()
|
||||
if bits < 1024 {
|
||||
return nil, errors.InvalidArgumentError("bits must be >= 1024")
|
||||
}
|
||||
if config != nil && len(config.RSAPrimes) >= 2 {
|
||||
primes := config.RSAPrimes[0:2]
|
||||
config.RSAPrimes = config.RSAPrimes[2:]
|
||||
return generateRSAKeyWithPrimes(config.Random(), 2, bits, primes)
|
||||
}
|
||||
return rsa.GenerateKey(config.Random(), bits)
|
||||
case packet.PubKeyAlgoEdDSA:
|
||||
if config.V6() {
|
||||
// Implementations MUST NOT accept or generate v6 key material
|
||||
// using the deprecated OIDs.
|
||||
return nil, errors.InvalidArgumentError("EdDSALegacy cannot be used for v6 keys")
|
||||
}
|
||||
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
|
||||
case packet.PubKeyAlgoEd25519:
|
||||
priv, err := ed25519.GenerateKey(config.Random())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return priv, nil
|
||||
case packet.PubKeyAlgoEd448:
|
||||
priv, err := ed448.GenerateKey(config.Random())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return priv, nil
|
||||
default:
|
||||
return nil, errors.InvalidArgumentError("unsupported public key algorithm")
|
||||
}
|
||||
}
|
||||
|
||||
// Generates an encryption/decryption key
|
||||
func newDecrypter(config *packet.Config) (decrypter interface{}, err error) {
|
||||
switch config.PublicKeyAlgorithm() {
|
||||
case packet.PubKeyAlgoRSA:
|
||||
bits := config.RSAModulusBits()
|
||||
if bits < 1024 {
|
||||
return nil, errors.InvalidArgumentError("bits must be >= 1024")
|
||||
}
|
||||
if config != nil && len(config.RSAPrimes) >= 2 {
|
||||
primes := config.RSAPrimes[0:2]
|
||||
config.RSAPrimes = config.RSAPrimes[2:]
|
||||
return generateRSAKeyWithPrimes(config.Random(), 2, bits, primes)
|
||||
}
|
||||
return rsa.GenerateKey(config.Random(), bits)
|
||||
case packet.PubKeyAlgoEdDSA, packet.PubKeyAlgoECDSA:
|
||||
fallthrough // When passing EdDSA or ECDSA, we generate an ECDH subkey
|
||||
case packet.PubKeyAlgoECDH:
|
||||
if config.V6() &&
|
||||
(config.CurveName() == packet.Curve25519 ||
|
||||
config.CurveName() == packet.Curve448) {
|
||||
// Implementations MUST NOT accept or generate v6 key material
|
||||
// using the deprecated OIDs.
|
||||
return nil, errors.InvalidArgumentError("ECDH with Curve25519/448 legacy cannot be used for v6 keys")
|
||||
}
|
||||
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)
|
||||
case packet.PubKeyAlgoEd25519, packet.PubKeyAlgoX25519: // When passing Ed25519, we generate an x25519 subkey
|
||||
return x25519.GenerateKey(config.Random())
|
||||
case packet.PubKeyAlgoEd448, packet.PubKeyAlgoX448: // When passing Ed448, we generate an x448 subkey
|
||||
return x448.GenerateKey(config.Random())
|
||||
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 pre-populated 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
|
||||
}
|
901
vendor/github.com/ProtonMail/go-crypto/openpgp/keys.go
generated
vendored
Normal file
901
vendor/github.com/ProtonMail/go-crypto/openpgp/keys.go
generated
vendored
Normal file
@ -0,0 +1,901 @@
|
||||
// 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"
|
||||
"fmt"
|
||||
"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
|
||||
SelfSignature *packet.Signature // Direct-key self signature of the PrimaryKey (contains primary key properties in v6)
|
||||
Signatures []*packet.Signature // all (potentially unverified) self-signatures, revocations, and third-party signatures
|
||||
}
|
||||
|
||||
// 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...
|
||||
primarySelfSignature, primaryIdentity := e.PrimarySelfSignature()
|
||||
if primarySelfSignature == nil || // no self-signature found
|
||||
e.PrimaryKey.KeyExpired(primarySelfSignature, now) || // primary key has expired
|
||||
e.Revoked(now) || // primary key has been revoked
|
||||
primarySelfSignature.SigExpired(now) || // user ID or or direct self-signature has expired
|
||||
(primaryIdentity != nil && primaryIdentity.Revoked(now)) { // user ID has been revoked (for v4 keys)
|
||||
return Key{}, false
|
||||
}
|
||||
|
||||
// Iterate the keys to find the newest, unexpired one
|
||||
candidateSubkey := -1
|
||||
var maxTime time.Time
|
||||
for i, subkey := range e.Subkeys {
|
||||
if subkey.Sig.FlagsValid &&
|
||||
subkey.Sig.FlagEncryptCommunications &&
|
||||
subkey.PublicKey.PubKeyAlgo.CanEncrypt() &&
|
||||
!subkey.PublicKey.KeyExpired(subkey.Sig, now) &&
|
||||
!subkey.Sig.SigExpired(now) &&
|
||||
!subkey.Revoked(now) &&
|
||||
(maxTime.IsZero() || subkey.Sig.CreationTime.After(maxTime)) {
|
||||
candidateSubkey = i
|
||||
maxTime = subkey.Sig.CreationTime
|
||||
}
|
||||
}
|
||||
|
||||
if candidateSubkey != -1 {
|
||||
subkey := e.Subkeys[candidateSubkey]
|
||||
return Key{e, subkey.PublicKey, subkey.PrivateKey, subkey.Sig, subkey.Revocations}, true
|
||||
}
|
||||
|
||||
// If we don't have any subkeys for encryption and the primary key
|
||||
// is marked as OK to encrypt with, then we can use it.
|
||||
if primarySelfSignature.FlagsValid && primarySelfSignature.FlagEncryptCommunications &&
|
||||
e.PrimaryKey.PubKeyAlgo.CanEncrypt() {
|
||||
return Key{e, e.PrimaryKey, e.PrivateKey, primarySelfSignature, 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...
|
||||
primarySelfSignature, primaryIdentity := e.PrimarySelfSignature()
|
||||
if primarySelfSignature == nil || // no self-signature found
|
||||
e.PrimaryKey.KeyExpired(primarySelfSignature, now) || // primary key has expired
|
||||
e.Revoked(now) || // primary key has been revoked
|
||||
primarySelfSignature.SigExpired(now) || // user ID or direct self-signature has expired
|
||||
(primaryIdentity != nil && primaryIdentity.Revoked(now)) { // user ID has been revoked (for v4 keys)
|
||||
return Key{}, false
|
||||
}
|
||||
|
||||
// Iterate the keys to find the newest, unexpired one
|
||||
candidateSubkey := -1
|
||||
var maxTime time.Time
|
||||
for idx, subkey := range e.Subkeys {
|
||||
if subkey.Sig.FlagsValid &&
|
||||
(flags&packet.KeyFlagCertify == 0 || subkey.Sig.FlagCertify) &&
|
||||
(flags&packet.KeyFlagSign == 0 || subkey.Sig.FlagSign) &&
|
||||
subkey.PublicKey.PubKeyAlgo.CanSign() &&
|
||||
!subkey.PublicKey.KeyExpired(subkey.Sig, now) &&
|
||||
!subkey.Sig.SigExpired(now) &&
|
||||
!subkey.Revoked(now) &&
|
||||
(maxTime.IsZero() || subkey.Sig.CreationTime.After(maxTime)) &&
|
||||
(id == 0 || subkey.PublicKey.KeyId == id) {
|
||||
candidateSubkey = idx
|
||||
maxTime = subkey.Sig.CreationTime
|
||||
}
|
||||
}
|
||||
|
||||
if candidateSubkey != -1 {
|
||||
subkey := e.Subkeys[candidateSubkey]
|
||||
return Key{e, subkey.PublicKey, subkey.PrivateKey, subkey.Sig, subkey.Revocations}, true
|
||||
}
|
||||
|
||||
// If we don't have any subkeys for signing and the primary key
|
||||
// is marked as OK to sign with, then we can use it.
|
||||
if primarySelfSignature.FlagsValid &&
|
||||
(flags&packet.KeyFlagCertify == 0 || primarySelfSignature.FlagCertify) &&
|
||||
(flags&packet.KeyFlagSign == 0 || primarySelfSignature.FlagSign) &&
|
||||
e.PrimaryKey.PubKeyAlgo.CanSign() &&
|
||||
(id == 0 || e.PrimaryKey.KeyId == id) {
|
||||
return Key{e, e.PrimaryKey, e.PrivateKey, primarySelfSignature, e.Revocations}, true
|
||||
}
|
||||
|
||||
// No keys with a valid Signing Flag or no keys matched the id passed in
|
||||
return Key{}, false
|
||||
}
|
||||
|
||||
func revoked(revocations []*packet.Signature, now time.Time) bool {
|
||||
for _, revocation := range revocations {
|
||||
if revocation.RevocationReason != nil && *revocation.RevocationReason == packet.KeyCompromised {
|
||||
// If the key is compromised, the key is considered revoked even before the revocation date.
|
||||
return true
|
||||
}
|
||||
if !revocation.SigExpired(now) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Revoked returns whether the entity has any direct key revocation signatures.
|
||||
// Note that third-party revocation signatures are not supported.
|
||||
// Note also that Identity and Subkey revocation should be checked separately.
|
||||
func (e *Entity) Revoked(now time.Time) bool {
|
||||
return revoked(e.Revocations, now)
|
||||
}
|
||||
|
||||
// EncryptPrivateKeys encrypts all non-encrypted keys in the entity with the same key
|
||||
// derived from the provided passphrase. Public keys and dummy keys are ignored,
|
||||
// and don't cause an error to be returned.
|
||||
func (e *Entity) EncryptPrivateKeys(passphrase []byte, config *packet.Config) error {
|
||||
var keysToEncrypt []*packet.PrivateKey
|
||||
// Add entity private key to encrypt.
|
||||
if e.PrivateKey != nil && !e.PrivateKey.Dummy() && !e.PrivateKey.Encrypted {
|
||||
keysToEncrypt = append(keysToEncrypt, e.PrivateKey)
|
||||
}
|
||||
|
||||
// Add subkeys to encrypt.
|
||||
for _, sub := range e.Subkeys {
|
||||
if sub.PrivateKey != nil && !sub.PrivateKey.Dummy() && !sub.PrivateKey.Encrypted {
|
||||
keysToEncrypt = append(keysToEncrypt, sub.PrivateKey)
|
||||
}
|
||||
}
|
||||
return packet.EncryptPrivateKeys(keysToEncrypt, passphrase, config)
|
||||
}
|
||||
|
||||
// DecryptPrivateKeys decrypts all encrypted keys in the entity with the given passphrase.
|
||||
// Avoids recomputation of similar s2k key derivations. Public keys and dummy keys are ignored,
|
||||
// and don't cause an error to be returned.
|
||||
func (e *Entity) DecryptPrivateKeys(passphrase []byte) error {
|
||||
var keysToDecrypt []*packet.PrivateKey
|
||||
// Add entity private key to decrypt.
|
||||
if e.PrivateKey != nil && !e.PrivateKey.Dummy() && e.PrivateKey.Encrypted {
|
||||
keysToDecrypt = append(keysToDecrypt, e.PrivateKey)
|
||||
}
|
||||
|
||||
// Add subkeys to decrypt.
|
||||
for _, sub := range e.Subkeys {
|
||||
if sub.PrivateKey != nil && !sub.PrivateKey.Dummy() && sub.PrivateKey.Encrypted {
|
||||
keysToDecrypt = append(keysToDecrypt, sub.PrivateKey)
|
||||
}
|
||||
}
|
||||
return packet.DecryptPrivateKeys(keysToDecrypt, passphrase)
|
||||
}
|
||||
|
||||
// Revoked returns whether the identity has been revoked by a self-signature.
|
||||
// Note that third-party revocation signatures are not supported.
|
||||
func (i *Identity) Revoked(now time.Time) bool {
|
||||
return revoked(i.Revocations, now)
|
||||
}
|
||||
|
||||
// Revoked returns whether the subkey has been revoked by a self-signature.
|
||||
// Note that third-party revocation signatures are not supported.
|
||||
func (s *Subkey) Revoked(now time.Time) bool {
|
||||
return revoked(s.Revocations, now)
|
||||
}
|
||||
|
||||
// Revoked returns whether the key or subkey has been revoked by a self-signature.
|
||||
// Note that third-party revocation signatures are not supported.
|
||||
// Note also that Identity revocation should be checked separately.
|
||||
// Normally, it's not necessary to call this function, except on keys returned by
|
||||
// KeysById or KeysByIdUsage.
|
||||
func (key *Key) Revoked(now time.Time) bool {
|
||||
return revoked(key.Revocations, now)
|
||||
}
|
||||
|
||||
// An EntityList contains one or more Entities.
|
||||
type EntityList []*Entity
|
||||
|
||||
// KeysById returns the set of keys that have the given key id.
|
||||
func (el EntityList) KeysById(id uint64) (keys []Key) {
|
||||
for _, e := range el {
|
||||
if e.PrimaryKey.KeyId == id {
|
||||
selfSig, _ := e.PrimarySelfSignature()
|
||||
keys = append(keys, Key{e, e.PrimaryKey, e.PrivateKey, selfSig, e.Revocations})
|
||||
}
|
||||
|
||||
for _, subKey := range e.Subkeys {
|
||||
if subKey.PublicKey.KeyId == id {
|
||||
keys = append(keys, Key{e, subKey.PublicKey, subKey.PrivateKey, subKey.Sig, subKey.Revocations})
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// KeysByIdAndUsage returns the set of keys with the given id that also meet
|
||||
// the key usage given by requiredUsage. The requiredUsage is expressed as
|
||||
// the bitwise-OR of packet.KeyFlag* values.
|
||||
func (el EntityList) KeysByIdUsage(id uint64, requiredUsage byte) (keys []Key) {
|
||||
for _, key := range el.KeysById(id) {
|
||||
if requiredUsage != 0 {
|
||||
if key.SelfSignature == nil || !key.SelfSignature.FlagsValid {
|
||||
continue
|
||||
}
|
||||
|
||||
var usage byte
|
||||
if key.SelfSignature.FlagCertify {
|
||||
usage |= packet.KeyFlagCertify
|
||||
}
|
||||
if key.SelfSignature.FlagSign {
|
||||
usage |= packet.KeyFlagSign
|
||||
}
|
||||
if key.SelfSignature.FlagEncryptCommunications {
|
||||
usage |= packet.KeyFlagEncryptCommunications
|
||||
}
|
||||
if key.SelfSignature.FlagEncryptStorage {
|
||||
usage |= packet.KeyFlagEncryptStorage
|
||||
}
|
||||
if usage&requiredUsage != requiredUsage {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
keys = append(keys, key)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DecryptionKeys returns all private keys that are valid for decryption.
|
||||
func (el EntityList) DecryptionKeys() (keys []Key) {
|
||||
for _, e := range el {
|
||||
for _, subKey := range e.Subkeys {
|
||||
if subKey.PrivateKey != nil && subKey.Sig.FlagsValid && (subKey.Sig.FlagEncryptStorage || subKey.Sig.FlagEncryptCommunications) {
|
||||
keys = append(keys, Key{e, subKey.PublicKey, subKey.PrivateKey, subKey.Sig, subKey.Revocations})
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// ReadArmoredKeyRing reads one or more public/private keys from an armor keyring file.
|
||||
func ReadArmoredKeyRing(r io.Reader) (EntityList, error) {
|
||||
block, err := armor.Decode(r)
|
||||
if err == io.EOF {
|
||||
return nil, errors.InvalidArgumentError("no armored data found")
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if block.Type != PublicKeyType && block.Type != PrivateKeyType {
|
||||
return nil, errors.InvalidArgumentError("expected public or private key block, got: " + block.Type)
|
||||
}
|
||||
|
||||
return ReadKeyRing(block.Body)
|
||||
}
|
||||
|
||||
// ReadKeyRing reads one or more public/private keys. Unsupported keys are
|
||||
// ignored as long as at least a single valid key is found.
|
||||
func ReadKeyRing(r io.Reader) (el EntityList, err error) {
|
||||
packets := packet.NewReader(r)
|
||||
var lastUnsupportedError error
|
||||
|
||||
for {
|
||||
var e *Entity
|
||||
e, err = ReadEntity(packets)
|
||||
if err != nil {
|
||||
// TODO: warn about skipped unsupported/unreadable keys
|
||||
if _, ok := err.(errors.UnsupportedError); ok {
|
||||
lastUnsupportedError = err
|
||||
err = readToNextPublicKey(packets)
|
||||
} else if _, ok := err.(errors.StructuralError); ok {
|
||||
// Skip unreadable, badly-formatted keys
|
||||
lastUnsupportedError = err
|
||||
err = readToNextPublicKey(packets)
|
||||
}
|
||||
if err == io.EOF {
|
||||
err = nil
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
el = nil
|
||||
break
|
||||
}
|
||||
} else {
|
||||
el = append(el, e)
|
||||
}
|
||||
}
|
||||
|
||||
if len(el) == 0 && err == nil {
|
||||
err = lastUnsupportedError
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// readToNextPublicKey reads packets until the start of the entity and leaves
|
||||
// the first packet of the new entity in the Reader.
|
||||
func readToNextPublicKey(packets *packet.Reader) (err error) {
|
||||
var p packet.Packet
|
||||
for {
|
||||
p, err = packets.Next()
|
||||
if err == io.EOF {
|
||||
return
|
||||
} else if err != nil {
|
||||
if _, ok := err.(errors.UnsupportedError); ok {
|
||||
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
|
||||
var directSignatures []*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 {
|
||||
directSignatures = append(directSignatures, pkt)
|
||||
}
|
||||
// Else, ignoring the signature as it does not follow anything
|
||||
// we would know to attach it to.
|
||||
case *packet.PrivateKey:
|
||||
if !pkt.IsSubkey {
|
||||
packets.Unread(p)
|
||||
break EachPacket
|
||||
}
|
||||
err = addSubkey(e, packets, &pkt.PublicKey, pkt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case *packet.PublicKey:
|
||||
if !pkt.IsSubkey {
|
||||
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 && e.PrimaryKey.Version < 6 {
|
||||
return nil, errors.StructuralError(fmt.Sprintf("v%d entity without any identities", e.PrimaryKey.Version))
|
||||
}
|
||||
|
||||
// An implementation MUST ensure that a valid direct-key signature is present before using a v6 key.
|
||||
if e.PrimaryKey.Version == 6 {
|
||||
if len(directSignatures) == 0 {
|
||||
return nil, errors.StructuralError("v6 entity without a valid direct-key signature")
|
||||
}
|
||||
// Select main direct key signature.
|
||||
var mainDirectKeySelfSignature *packet.Signature
|
||||
for _, directSignature := range directSignatures {
|
||||
if directSignature.SigType == packet.SigTypeDirectSignature &&
|
||||
directSignature.CheckKeyIdOrFingerprint(e.PrimaryKey) &&
|
||||
(mainDirectKeySelfSignature == nil ||
|
||||
directSignature.CreationTime.After(mainDirectKeySelfSignature.CreationTime)) {
|
||||
mainDirectKeySelfSignature = directSignature
|
||||
}
|
||||
}
|
||||
if mainDirectKeySelfSignature == nil {
|
||||
return nil, errors.StructuralError("no valid direct-key self-signature for v6 primary key found")
|
||||
}
|
||||
// Check that the main self-signature is valid.
|
||||
err = e.PrimaryKey.VerifyDirectKeySignature(mainDirectKeySelfSignature)
|
||||
if err != nil {
|
||||
return nil, errors.StructuralError("invalid direct-key self-signature for v6 primary key")
|
||||
}
|
||||
e.SelfSignature = mainDirectKeySelfSignature
|
||||
e.Signatures = directSignatures
|
||||
}
|
||||
|
||||
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 _, directSignature := range e.Signatures {
|
||||
err := directSignature.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 _, directSignature := range e.Signatures {
|
||||
err := directSignature.Serialize(w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, ident := range e.Identities {
|
||||
err = ident.UserId.Serialize(w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, sig := range ident.Signatures {
|
||||
err = sig.Serialize(w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, subkey := range e.Subkeys {
|
||||
err = subkey.PublicKey.Serialize(w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, revocation := range subkey.Revocations {
|
||||
err := revocation.Serialize(w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
err = subkey.Sig.Serialize(w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SignIdentity adds a signature to e, from signer, attesting that identity is
|
||||
// associated with e. The provided identity must already be an element of
|
||||
// e.Identities and the private key of signer must have been decrypted if
|
||||
// necessary.
|
||||
// If config is nil, sensible defaults will be used.
|
||||
func (e *Entity) SignIdentity(identity string, signer *Entity, config *packet.Config) error {
|
||||
certificationKey, ok := signer.CertificationKey(config.Now())
|
||||
if !ok {
|
||||
return errors.InvalidArgumentError("no valid certification key found")
|
||||
}
|
||||
|
||||
if certificationKey.PrivateKey.Encrypted {
|
||||
return errors.InvalidArgumentError("signing Entity's private key must be decrypted")
|
||||
}
|
||||
|
||||
ident, ok := e.Identities[identity]
|
||||
if !ok {
|
||||
return errors.InvalidArgumentError("given identity string not found in Entity")
|
||||
}
|
||||
|
||||
sig := createSignaturePacket(certificationKey.PublicKey, packet.SigTypeGenericCert, config)
|
||||
|
||||
signingUserID := config.SigningUserId()
|
||||
if signingUserID != "" {
|
||||
if _, ok := signer.Identities[signingUserID]; !ok {
|
||||
return errors.InvalidArgumentError("signer identity string not found in signer Entity")
|
||||
}
|
||||
sig.SignerUserId = &signingUserID
|
||||
}
|
||||
|
||||
if err := sig.SignUserId(identity, e.PrimaryKey, certificationKey.PrivateKey, config); err != nil {
|
||||
return err
|
||||
}
|
||||
ident.Signatures = append(ident.Signatures, sig)
|
||||
return nil
|
||||
}
|
||||
|
||||
// RevokeKey generates a key revocation signature (packet.SigTypeKeyRevocation) with the
|
||||
// specified reason code and text (RFC4880 section-5.2.3.23).
|
||||
// If config is nil, sensible defaults will be used.
|
||||
func (e *Entity) RevokeKey(reason packet.ReasonForRevocation, reasonText string, config *packet.Config) error {
|
||||
revSig := createSignaturePacket(e.PrimaryKey, packet.SigTypeKeyRevocation, config)
|
||||
revSig.RevocationReason = &reason
|
||||
revSig.RevocationReasonText = reasonText
|
||||
|
||||
if err := revSig.RevokeKey(e.PrimaryKey, e.PrivateKey, config); err != nil {
|
||||
return err
|
||||
}
|
||||
e.Revocations = append(e.Revocations, revSig)
|
||||
return nil
|
||||
}
|
||||
|
||||
// RevokeSubkey generates a subkey revocation signature (packet.SigTypeSubkeyRevocation) for
|
||||
// a subkey with the specified reason code and text (RFC4880 section-5.2.3.23).
|
||||
// If config is nil, sensible defaults will be used.
|
||||
func (e *Entity) RevokeSubkey(sk *Subkey, reason packet.ReasonForRevocation, reasonText string, config *packet.Config) error {
|
||||
if err := e.PrimaryKey.VerifyKeySignature(sk.PublicKey, sk.Sig); err != nil {
|
||||
return errors.InvalidArgumentError("given subkey is not associated with this key")
|
||||
}
|
||||
|
||||
revSig := createSignaturePacket(e.PrimaryKey, packet.SigTypeSubkeyRevocation, config)
|
||||
revSig.RevocationReason = &reason
|
||||
revSig.RevocationReasonText = reasonText
|
||||
|
||||
if err := revSig.RevokeSubkey(sk.PublicKey, e.PrivateKey, config); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sk.Revocations = append(sk.Revocations, revSig)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Entity) primaryDirectSignature() *packet.Signature {
|
||||
return e.SelfSignature
|
||||
}
|
||||
|
||||
// PrimarySelfSignature searches the entity for the self-signature that stores key preferences.
|
||||
// For V4 keys, returns the self-signature of the primary identity, and the identity.
|
||||
// For V6 keys, returns the latest valid direct-key self-signature, and no identity (nil).
|
||||
// This self-signature is to be used to check the key expiration,
|
||||
// algorithm preferences, and so on.
|
||||
func (e *Entity) PrimarySelfSignature() (*packet.Signature, *Identity) {
|
||||
if e.PrimaryKey.Version == 6 {
|
||||
return e.primaryDirectSignature(), nil
|
||||
}
|
||||
primaryIdentity := e.PrimaryIdentity()
|
||||
if primaryIdentity == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return primaryIdentity.SelfSignature, primaryIdentity
|
||||
}
|
538
vendor/github.com/ProtonMail/go-crypto/openpgp/keys_test_data.go
generated
vendored
Normal file
538
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
67
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/aead_config.go
generated
vendored
Normal file
67
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/aead_config.go
generated
vendored
Normal file
@ -0,0 +1,67 @@
|
||||
// Copyright (C) 2019 ProtonTech AG
|
||||
|
||||
package packet
|
||||
|
||||
import "math/bits"
|
||||
|
||||
// CipherSuite contains a combination of Cipher and Mode
|
||||
type CipherSuite struct {
|
||||
// The cipher function
|
||||
Cipher CipherFunction
|
||||
// The AEAD mode of operation.
|
||||
Mode AEADMode
|
||||
}
|
||||
|
||||
// AEADConfig collects a number of AEAD parameters along with sensible defaults.
|
||||
// A nil AEADConfig is valid and results in all default values.
|
||||
type AEADConfig struct {
|
||||
// The AEAD mode of operation.
|
||||
DefaultMode AEADMode
|
||||
// Amount of octets in each chunk of data
|
||||
ChunkSize uint64
|
||||
}
|
||||
|
||||
// Mode returns the AEAD mode of operation.
|
||||
func (conf *AEADConfig) Mode() AEADMode {
|
||||
// If no preference is specified, OCB is used (which is mandatory to implement).
|
||||
if conf == nil || conf.DefaultMode == 0 {
|
||||
return AEADModeOCB
|
||||
}
|
||||
|
||||
mode := conf.DefaultMode
|
||||
if mode != AEADModeEAX && mode != AEADModeOCB && mode != AEADModeGCM {
|
||||
panic("AEAD mode unsupported")
|
||||
}
|
||||
return mode
|
||||
}
|
||||
|
||||
// ChunkSizeByte returns the byte indicating the chunk size. The effective
|
||||
// chunk size is computed with the formula uint64(1) << (chunkSizeByte + 6)
|
||||
// limit to 16 = 4 MiB
|
||||
// https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-07.html#section-5.13.2
|
||||
func (conf *AEADConfig) ChunkSizeByte() byte {
|
||||
if conf == nil || conf.ChunkSize == 0 {
|
||||
return 12 // 1 << (12 + 6) == 262144 bytes
|
||||
}
|
||||
|
||||
chunkSize := conf.ChunkSize
|
||||
exponent := bits.Len64(chunkSize) - 1
|
||||
switch {
|
||||
case exponent < 6:
|
||||
exponent = 6
|
||||
case exponent > 16:
|
||||
exponent = 16
|
||||
}
|
||||
|
||||
return byte(exponent - 6)
|
||||
}
|
||||
|
||||
// decodeAEADChunkSize returns the effective chunk size. In 32-bit systems, the
|
||||
// maximum returned value is 1 << 30.
|
||||
func decodeAEADChunkSize(c byte) int {
|
||||
size := uint64(1 << (c + 6))
|
||||
if size != uint64(int(size)) {
|
||||
return 1 << 30
|
||||
}
|
||||
return int(size)
|
||||
}
|
250
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/aead_crypter.go
generated
vendored
Normal file
250
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/aead_crypter.go
generated
vendored
Normal file
@ -0,0 +1,250 @@
|
||||
// Copyright (C) 2019 ProtonTech AG
|
||||
|
||||
package packet
|
||||
|
||||
import (
|
||||
"crypto/cipher"
|
||||
"encoding/binary"
|
||||
"io"
|
||||
|
||||
"github.com/ProtonMail/go-crypto/openpgp/errors"
|
||||
)
|
||||
|
||||
// aeadCrypter is an AEAD opener/sealer, its configuration, and data for en/decryption.
|
||||
type aeadCrypter struct {
|
||||
aead cipher.AEAD
|
||||
chunkSize int
|
||||
nonce []byte
|
||||
associatedData []byte // Chunk-independent associated data
|
||||
chunkIndex []byte // Chunk counter
|
||||
packetTag packetType // SEIP packet (v2) or AEAD Encrypted Data packet
|
||||
bytesProcessed int // Amount of plaintext bytes encrypted/decrypted
|
||||
}
|
||||
|
||||
// computeNonce takes the incremental index and computes an eXclusive OR with
|
||||
// the least significant 8 bytes of the receivers' initial nonce (see sec.
|
||||
// 5.16.1 and 5.16.2). It returns the resulting nonce.
|
||||
func (wo *aeadCrypter) computeNextNonce() (nonce []byte) {
|
||||
if wo.packetTag == packetTypeSymmetricallyEncryptedIntegrityProtected {
|
||||
return wo.nonce
|
||||
}
|
||||
|
||||
nonce = make([]byte, len(wo.nonce))
|
||||
copy(nonce, wo.nonce)
|
||||
offset := len(wo.nonce) - 8
|
||||
for i := 0; i < 8; i++ {
|
||||
nonce[i+offset] ^= wo.chunkIndex[i]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// incrementIndex performs an integer increment by 1 of the integer represented by the
|
||||
// slice, modifying it accordingly.
|
||||
func (wo *aeadCrypter) incrementIndex() error {
|
||||
index := wo.chunkIndex
|
||||
if len(index) == 0 {
|
||||
return errors.AEADError("Index has length 0")
|
||||
}
|
||||
for i := len(index) - 1; i >= 0; i-- {
|
||||
if index[i] < 255 {
|
||||
index[i]++
|
||||
return nil
|
||||
}
|
||||
index[i] = 0
|
||||
}
|
||||
return errors.AEADError("cannot further increment index")
|
||||
}
|
||||
|
||||
// aeadDecrypter reads and decrypts bytes. It buffers extra decrypted bytes when
|
||||
// necessary, similar to aeadEncrypter.
|
||||
type aeadDecrypter struct {
|
||||
aeadCrypter // Embedded ciphertext opener
|
||||
reader io.Reader // 'reader' is a partialLengthReader
|
||||
chunkBytes []byte
|
||||
peekedBytes []byte // Used to detect last chunk
|
||||
buffer []byte // Buffered decrypted bytes
|
||||
}
|
||||
|
||||
// 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 len(ar.buffer) > 0 {
|
||||
n = copy(dst, ar.buffer)
|
||||
ar.buffer = ar.buffer[n:]
|
||||
return
|
||||
}
|
||||
|
||||
// Read a chunk
|
||||
tagLen := ar.aead.Overhead()
|
||||
copy(ar.chunkBytes, ar.peekedBytes) // Copy bytes peeked in previous chunk or in initialization
|
||||
bytesRead, errRead := io.ReadFull(ar.reader, ar.chunkBytes[tagLen:])
|
||||
if errRead != nil && errRead != io.EOF && errRead != io.ErrUnexpectedEOF {
|
||||
return 0, errRead
|
||||
}
|
||||
|
||||
if bytesRead > 0 {
|
||||
ar.peekedBytes = ar.chunkBytes[bytesRead:bytesRead+tagLen]
|
||||
|
||||
decrypted, errChunk := ar.openChunk(ar.chunkBytes[:bytesRead])
|
||||
if errChunk != nil {
|
||||
return 0, errChunk
|
||||
}
|
||||
|
||||
// Return decrypted bytes, buffering if necessary
|
||||
n = copy(dst, decrypted)
|
||||
ar.buffer = decrypted[n:]
|
||||
return
|
||||
}
|
||||
|
||||
return 0, io.EOF
|
||||
}
|
||||
|
||||
// Close checks the final authentication tag of the stream.
|
||||
// In the future, this function could also be used to wipe the reader
|
||||
// and peeked & decrypted bytes, if necessary.
|
||||
func (ar *aeadDecrypter) Close() (err error) {
|
||||
errChunk := ar.validateFinalTag(ar.peekedBytes)
|
||||
if errChunk != nil {
|
||||
return errChunk
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// openChunk decrypts and checks integrity of an encrypted chunk, returning
|
||||
// the underlying plaintext and an error. It accesses peeked bytes from next
|
||||
// chunk, to identify the last chunk and decrypt/validate accordingly.
|
||||
func (ar *aeadDecrypter) openChunk(data []byte) ([]byte, error) {
|
||||
adata := ar.associatedData
|
||||
if ar.aeadCrypter.packetTag == packetTypeAEADEncrypted {
|
||||
adata = append(ar.associatedData, ar.chunkIndex...)
|
||||
}
|
||||
|
||||
nonce := ar.computeNextNonce()
|
||||
plainChunk, err := ar.aead.Open(data[:0:len(data)], nonce, data, adata)
|
||||
if err != nil {
|
||||
return nil, errors.ErrAEADTagVerification
|
||||
}
|
||||
ar.bytesProcessed += len(plainChunk)
|
||||
if err = ar.aeadCrypter.incrementIndex(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return plainChunk, nil
|
||||
}
|
||||
|
||||
// Checks the summary tag. It takes into account the total decrypted bytes into
|
||||
// the associated data. It returns an error, or nil if the tag is valid.
|
||||
func (ar *aeadDecrypter) validateFinalTag(tag []byte) error {
|
||||
// Associated: tag, version, cipher, aead, chunk size, ...
|
||||
amountBytes := make([]byte, 8)
|
||||
binary.BigEndian.PutUint64(amountBytes, uint64(ar.bytesProcessed))
|
||||
|
||||
adata := ar.associatedData
|
||||
if ar.aeadCrypter.packetTag == packetTypeAEADEncrypted {
|
||||
// ... index ...
|
||||
adata = append(ar.associatedData, ar.chunkIndex...)
|
||||
}
|
||||
|
||||
// ... and total number of encrypted octets
|
||||
adata = append(adata, amountBytes...)
|
||||
nonce := ar.computeNextNonce()
|
||||
if _, err := ar.aead.Open(nil, nonce, tag, adata); err != nil {
|
||||
return errors.ErrAEADTagVerification
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// aeadEncrypter encrypts and writes bytes. It encrypts when necessary according
|
||||
// to the AEAD block size, and buffers the extra encrypted bytes for next write.
|
||||
type aeadEncrypter struct {
|
||||
aeadCrypter // Embedded plaintext sealer
|
||||
writer io.WriteCloser // 'writer' is a partialLengthWriter
|
||||
chunkBytes []byte
|
||||
offset int
|
||||
}
|
||||
|
||||
// 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) {
|
||||
for n != len(plaintextBytes) {
|
||||
copied := copy(aw.chunkBytes[aw.offset:aw.chunkSize], plaintextBytes[n:])
|
||||
n += copied
|
||||
aw.offset += copied
|
||||
|
||||
if aw.offset == aw.chunkSize {
|
||||
encryptedChunk, err := aw.sealChunk(aw.chunkBytes[:aw.offset])
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
_, err = aw.writer.Write(encryptedChunk)
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
aw.offset = 0
|
||||
}
|
||||
}
|
||||
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.offset > 0 || aw.bytesProcessed == 0 {
|
||||
lastEncryptedChunk, err := aw.sealChunk(aw.chunkBytes[:aw.offset])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = aw.writer.Write(lastEncryptedChunk)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// Compute final tag (associated data: packet tag, version, cipher, aead,
|
||||
// chunk size...
|
||||
adata := aw.associatedData
|
||||
|
||||
if aw.aeadCrypter.packetTag == packetTypeAEADEncrypted {
|
||||
// ... index ...
|
||||
adata = append(aw.associatedData, aw.chunkIndex...)
|
||||
}
|
||||
|
||||
// ... and total number of encrypted octets
|
||||
amountBytes := make([]byte, 8)
|
||||
binary.BigEndian.PutUint64(amountBytes, uint64(aw.bytesProcessed))
|
||||
adata = append(adata, amountBytes...)
|
||||
|
||||
nonce := aw.computeNextNonce()
|
||||
finalTag := aw.aead.Seal(nil, nonce, nil, adata)
|
||||
_, err = aw.writer.Write(finalTag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return aw.writer.Close()
|
||||
}
|
||||
|
||||
// sealChunk Encrypts and authenticates the given chunk.
|
||||
func (aw *aeadEncrypter) sealChunk(data []byte) ([]byte, error) {
|
||||
if len(data) > aw.chunkSize {
|
||||
return nil, errors.AEADError("chunk exceeds maximum length")
|
||||
}
|
||||
if aw.associatedData == nil {
|
||||
return nil, errors.AEADError("can't seal without headers")
|
||||
}
|
||||
adata := aw.associatedData
|
||||
if aw.aeadCrypter.packetTag == packetTypeAEADEncrypted {
|
||||
adata = append(aw.associatedData, aw.chunkIndex...)
|
||||
}
|
||||
|
||||
nonce := aw.computeNextNonce()
|
||||
encrypted := aw.aead.Seal(data[:0], nonce, data, adata)
|
||||
aw.bytesProcessed += len(data)
|
||||
if err := aw.aeadCrypter.incrementIndex(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return encrypted, nil
|
||||
}
|
100
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/aead_encrypted.go
generated
vendored
Normal file
100
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/aead_encrypted.go
generated
vendored
Normal file
@ -0,0 +1,100 @@
|
||||
// Copyright (C) 2019 ProtonTech AG
|
||||
|
||||
package packet
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/ProtonMail/go-crypto/openpgp/errors"
|
||||
"github.com/ProtonMail/go-crypto/openpgp/internal/algorithm"
|
||||
)
|
||||
|
||||
// AEADEncrypted represents an AEAD Encrypted Packet.
|
||||
// See https://www.ietf.org/archive/id/draft-koch-openpgp-2015-rfc4880bis-00.html#name-aead-encrypted-data-packet-t
|
||||
type AEADEncrypted struct {
|
||||
cipher CipherFunction
|
||||
mode AEADMode
|
||||
chunkSizeByte byte
|
||||
Contents io.Reader // Encrypted chunks and tags
|
||||
initialNonce []byte // Referred to as IV in RFC4880-bis
|
||||
}
|
||||
|
||||
// Only currently defined version
|
||||
const aeadEncryptedVersion = 1
|
||||
|
||||
func (ae *AEADEncrypted) parse(buf io.Reader) error {
|
||||
headerData := make([]byte, 4)
|
||||
if n, err := io.ReadFull(buf, headerData); n < 4 {
|
||||
return errors.AEADError("could not read aead header:" + err.Error())
|
||||
}
|
||||
// Read initial nonce
|
||||
mode := AEADMode(headerData[2])
|
||||
nonceLen := mode.IvLength()
|
||||
|
||||
// This packet supports only EAX and OCB
|
||||
// https://www.ietf.org/archive/id/draft-koch-openpgp-2015-rfc4880bis-00.html#name-aead-encrypted-data-packet-t
|
||||
if nonceLen == 0 || mode > AEADModeOCB {
|
||||
return errors.AEADError("unknown mode")
|
||||
}
|
||||
|
||||
initialNonce := make([]byte, nonceLen)
|
||||
if n, err := io.ReadFull(buf, initialNonce); n < nonceLen {
|
||||
return errors.AEADError("could not read aead nonce:" + err.Error())
|
||||
}
|
||||
ae.Contents = buf
|
||||
ae.initialNonce = initialNonce
|
||||
c := headerData[1]
|
||||
if _, ok := algorithm.CipherById[c]; !ok {
|
||||
return errors.UnsupportedError("unknown cipher: " + string(c))
|
||||
}
|
||||
ae.cipher = CipherFunction(c)
|
||||
ae.mode = mode
|
||||
ae.chunkSizeByte = headerData[3]
|
||||
return nil
|
||||
}
|
||||
|
||||
// Decrypt returns a io.ReadCloser from which decrypted bytes can be read, or
|
||||
// an error.
|
||||
func (ae *AEADEncrypted) Decrypt(ciph CipherFunction, key []byte) (io.ReadCloser, error) {
|
||||
return ae.decrypt(key)
|
||||
}
|
||||
|
||||
// decrypt prepares an aeadCrypter and returns a ReadCloser from which
|
||||
// decrypted bytes can be read (see aeadDecrypter.Read()).
|
||||
func (ae *AEADEncrypted) decrypt(key []byte) (io.ReadCloser, error) {
|
||||
blockCipher := ae.cipher.new(key)
|
||||
aead := ae.mode.new(blockCipher)
|
||||
// Carry the first tagLen bytes
|
||||
chunkSize := decodeAEADChunkSize(ae.chunkSizeByte)
|
||||
tagLen := ae.mode.TagLength()
|
||||
chunkBytes := make([]byte, chunkSize+tagLen*2)
|
||||
peekedBytes := chunkBytes[chunkSize+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())
|
||||
}
|
||||
|
||||
return &aeadDecrypter{
|
||||
aeadCrypter: aeadCrypter{
|
||||
aead: aead,
|
||||
chunkSize: chunkSize,
|
||||
nonce: ae.initialNonce,
|
||||
associatedData: ae.associatedData(),
|
||||
chunkIndex: make([]byte, 8),
|
||||
packetTag: packetTypeAEADEncrypted,
|
||||
},
|
||||
reader: ae.Contents,
|
||||
chunkBytes: chunkBytes,
|
||||
peekedBytes: peekedBytes,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// associatedData for chunks: tag, version, cipher, mode, chunk size byte
|
||||
func (ae *AEADEncrypted) associatedData() []byte {
|
||||
return []byte{
|
||||
0xD4,
|
||||
aeadEncryptedVersion,
|
||||
byte(ae.cipher),
|
||||
byte(ae.mode),
|
||||
ae.chunkSizeByte}
|
||||
}
|
@ -8,9 +8,10 @@ import (
|
||||
"compress/bzip2"
|
||||
"compress/flate"
|
||||
"compress/zlib"
|
||||
"golang.org/x/crypto/openpgp/errors"
|
||||
"io"
|
||||
"strconv"
|
||||
|
||||
"github.com/ProtonMail/go-crypto/openpgp/errors"
|
||||
)
|
||||
|
||||
// Compressed represents a compressed OpenPGP packet. The decompressed contents
|
||||
@ -39,6 +40,37 @@ type CompressionConfig struct {
|
||||
Level int
|
||||
}
|
||||
|
||||
// decompressionReader ensures that the whole compression packet is read.
|
||||
type decompressionReader struct {
|
||||
compressed io.Reader
|
||||
decompressed io.ReadCloser
|
||||
readAll bool
|
||||
}
|
||||
|
||||
func newDecompressionReader(r io.Reader, decompressor io.ReadCloser) *decompressionReader {
|
||||
return &decompressionReader{
|
||||
compressed: r,
|
||||
decompressed: decompressor,
|
||||
}
|
||||
}
|
||||
|
||||
func (dr *decompressionReader) Read(data []byte) (n int, err error) {
|
||||
if dr.readAll {
|
||||
return 0, io.EOF
|
||||
}
|
||||
n, err = dr.decompressed.Read(data)
|
||||
if err == io.EOF {
|
||||
dr.readAll = true
|
||||
// Close the decompressor.
|
||||
if errDec := dr.decompressed.Close(); errDec != nil {
|
||||
return n, errDec
|
||||
}
|
||||
// Consume all remaining data from the compressed packet.
|
||||
consumeAll(dr.compressed)
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (c *Compressed) parse(r io.Reader) error {
|
||||
var buf [1]byte
|
||||
_, err := readFull(r, buf[:])
|
||||
@ -47,12 +79,18 @@ func (c *Compressed) parse(r io.Reader) error {
|
||||
}
|
||||
|
||||
switch buf[0] {
|
||||
case 0:
|
||||
c.Body = r
|
||||
case 1:
|
||||
c.Body = flate.NewReader(r)
|
||||
c.Body = newDecompressionReader(r, flate.NewReader(r))
|
||||
case 2:
|
||||
c.Body, err = zlib.NewReader(r)
|
||||
decompressor, err := zlib.NewReader(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.Body = newDecompressionReader(r, decompressor)
|
||||
case 3:
|
||||
c.Body = bzip2.NewReader(r)
|
||||
c.Body = newDecompressionReader(r, io.NopCloser(bzip2.NewReader(r)))
|
||||
default:
|
||||
err = errors.UnsupportedError("unknown compression algorithm: " + strconv.Itoa(int(buf[0])))
|
||||
}
|
||||
@ -60,7 +98,7 @@ func (c *Compressed) parse(r io.Reader) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// compressedWriteCloser represents the serialized compression stream
|
||||
// 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.
|
422
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/config.go
generated
vendored
Normal file
422
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/config.go
generated
vendored
Normal file
@ -0,0 +1,422 @@
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package packet
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/rand"
|
||||
"io"
|
||||
"math/big"
|
||||
"time"
|
||||
|
||||
"github.com/ProtonMail/go-crypto/openpgp/s2k"
|
||||
)
|
||||
|
||||
var (
|
||||
defaultRejectPublicKeyAlgorithms = map[PublicKeyAlgorithm]bool{
|
||||
PubKeyAlgoElGamal: true,
|
||||
PubKeyAlgoDSA: true,
|
||||
}
|
||||
defaultRejectHashAlgorithms = map[crypto.Hash]bool{
|
||||
crypto.MD5: true,
|
||||
crypto.RIPEMD160: true,
|
||||
}
|
||||
defaultRejectMessageHashAlgorithms = map[crypto.Hash]bool{
|
||||
crypto.SHA1: true,
|
||||
crypto.MD5: true,
|
||||
crypto.RIPEMD160: true,
|
||||
}
|
||||
defaultRejectCurves = map[Curve]bool{
|
||||
CurveSecP256k1: true,
|
||||
}
|
||||
)
|
||||
|
||||
// A global feature flag to indicate v5 support.
|
||||
// Can be set via a build tag, e.g.: `go build -tags v5 ./...`
|
||||
// If the build tag is missing config_v5.go will set it to true.
|
||||
//
|
||||
// Disables parsing of v5 keys and v5 signatures.
|
||||
// These are non-standard entities, which in the crypto-refresh have been superseded
|
||||
// by v6 keys, v6 signatures and SEIPDv2 encrypted data, respectively.
|
||||
var V5Disabled = false
|
||||
|
||||
// Config collects a number of parameters along with sensible defaults.
|
||||
// A nil *Config is valid and results in all default values.
|
||||
type Config struct {
|
||||
// Rand provides the source of entropy.
|
||||
// If nil, the crypto/rand Reader is used.
|
||||
Rand io.Reader
|
||||
// DefaultHash is the default hash function to be used.
|
||||
// If zero, SHA-256 is used.
|
||||
DefaultHash crypto.Hash
|
||||
// DefaultCipher is the cipher to be used.
|
||||
// If zero, AES-128 is used.
|
||||
DefaultCipher CipherFunction
|
||||
// Time returns the current time as the number of seconds since the
|
||||
// epoch. If Time is nil, time.Now is used.
|
||||
Time func() time.Time
|
||||
// DefaultCompressionAlgo is the compression algorithm to be
|
||||
// applied to the plaintext before encryption. If zero, no
|
||||
// compression is done.
|
||||
DefaultCompressionAlgo CompressionAlgo
|
||||
// CompressionConfig configures the compression settings.
|
||||
CompressionConfig *CompressionConfig
|
||||
// S2K (String to Key) config, used for key derivation in the context of secret key encryption
|
||||
// and password-encrypted data.
|
||||
// If nil, the default configuration is used
|
||||
S2KConfig *s2k.Config
|
||||
// Iteration count for Iterated S2K (String to Key).
|
||||
// Only used if sk2.Mode is nil.
|
||||
// This value is duplicated here from s2k.Config for backwards compatibility.
|
||||
// It determines the strength of the passphrase stretching when
|
||||
// the said passphrase is hashed to produce a key. S2KCount
|
||||
// should be between 65536 and 65011712, inclusive. If Config
|
||||
// is nil or S2KCount is 0, the value 16777216 used. Not all
|
||||
// values in the above range can be represented. S2KCount will
|
||||
// be rounded up to the next representable value if it cannot
|
||||
// be encoded exactly. When set, it is strongly encrouraged to
|
||||
// use a value that is at least 65536. See RFC 4880 Section
|
||||
// 3.7.1.3.
|
||||
//
|
||||
// Deprecated: SK2Count should be configured in S2KConfig instead.
|
||||
S2KCount int
|
||||
// RSABits is the number of bits in new RSA keys made with NewEntity.
|
||||
// If zero, then 2048 bit keys are created.
|
||||
RSABits int
|
||||
// The public key algorithm to use - will always create a signing primary
|
||||
// key and encryption subkey.
|
||||
Algorithm PublicKeyAlgorithm
|
||||
// Some known primes that are optionally prepopulated by the caller
|
||||
RSAPrimes []*big.Int
|
||||
// Curve configures the desired packet.Curve if the Algorithm is PubKeyAlgoECDSA,
|
||||
// PubKeyAlgoEdDSA, or PubKeyAlgoECDH. If empty Curve25519 is used.
|
||||
Curve Curve
|
||||
// AEADConfig configures the use of the new AEAD Encrypted Data Packet,
|
||||
// defined in the draft of the next version of the OpenPGP specification.
|
||||
// If a non-nil AEADConfig is passed, usage of this packet is enabled. By
|
||||
// default, it is disabled. See the documentation of AEADConfig for more
|
||||
// configuration options related to AEAD.
|
||||
// **Note: using this option may break compatibility with other OpenPGP
|
||||
// implementations, as well as future versions of this library.**
|
||||
AEADConfig *AEADConfig
|
||||
// V6Keys configures version 6 key generation. If false, this package still
|
||||
// supports version 6 keys, but produces version 4 keys.
|
||||
V6Keys bool
|
||||
// Minimum RSA key size allowed for key generation and message signing, verification and encryption.
|
||||
MinRSABits uint16
|
||||
// Reject insecure algorithms, only works with v2 api
|
||||
RejectPublicKeyAlgorithms map[PublicKeyAlgorithm]bool
|
||||
RejectHashAlgorithms map[crypto.Hash]bool
|
||||
RejectMessageHashAlgorithms map[crypto.Hash]bool
|
||||
RejectCurves map[Curve]bool
|
||||
// "The validity period of the key. This is the number of seconds after
|
||||
// the key creation time that the key expires. If this is not present
|
||||
// or has a value of zero, the key never expires. This is found only on
|
||||
// a self-signature.""
|
||||
// https://tools.ietf.org/html/rfc4880#section-5.2.3.6
|
||||
KeyLifetimeSecs uint32
|
||||
// "The validity period of the signature. This is the number of seconds
|
||||
// after the signature creation time that the signature expires. If
|
||||
// this is not present or has a value of zero, it never expires."
|
||||
// https://tools.ietf.org/html/rfc4880#section-5.2.3.10
|
||||
SigLifetimeSecs uint32
|
||||
// SigningKeyId is used to specify the signing key to use (by Key ID).
|
||||
// By default, the signing key is selected automatically, preferring
|
||||
// signing subkeys if available.
|
||||
SigningKeyId uint64
|
||||
// SigningIdentity is used to specify a user ID (packet Signer's User ID, type 28)
|
||||
// when producing a generic certification signature onto an existing user ID.
|
||||
// The identity must be present in the signer Entity.
|
||||
SigningIdentity string
|
||||
// InsecureAllowUnauthenticatedMessages controls, whether it is tolerated to read
|
||||
// encrypted messages without Modification Detection Code (MDC).
|
||||
// MDC is mandated by the IETF OpenPGP Crypto Refresh draft and has long been implemented
|
||||
// in most OpenPGP implementations. Messages without MDC are considered unnecessarily
|
||||
// insecure and should be prevented whenever possible.
|
||||
// In case one needs to deal with messages from very old OpenPGP implementations, there
|
||||
// might be no other way than to tolerate the missing MDC. Setting this flag, allows this
|
||||
// mode of operation. It should be considered a measure of last resort.
|
||||
InsecureAllowUnauthenticatedMessages bool
|
||||
// InsecureAllowDecryptionWithSigningKeys allows decryption with keys marked as signing keys in the v2 API.
|
||||
// This setting is potentially insecure, but it is needed as some libraries
|
||||
// ignored key flags when selecting a key for encryption.
|
||||
// Not relevant for the v1 API, as all keys were allowed in decryption.
|
||||
InsecureAllowDecryptionWithSigningKeys bool
|
||||
// KnownNotations is a map of Notation Data names to bools, which controls
|
||||
// the notation names that are allowed to be present in critical Notation Data
|
||||
// signature subpackets.
|
||||
KnownNotations map[string]bool
|
||||
// SignatureNotations is a list of Notations to be added to any signatures.
|
||||
SignatureNotations []*Notation
|
||||
// CheckIntendedRecipients controls, whether the OpenPGP Intended Recipient Fingerprint feature
|
||||
// should be enabled for encryption and decryption.
|
||||
// (See https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-intended-recipient-fingerpr).
|
||||
// When the flag is set, encryption produces Intended Recipient Fingerprint signature sub-packets and decryption
|
||||
// checks whether the key it was encrypted to is one of the included fingerprints in the signature.
|
||||
// If the flag is disabled, no Intended Recipient Fingerprint sub-packets are created or checked.
|
||||
// The default behavior, when the config or flag is nil, is to enable the feature.
|
||||
CheckIntendedRecipients *bool
|
||||
// CacheSessionKey controls if decryption should return the session key used for decryption.
|
||||
// If the flag is set, the session key is cached in the message details struct.
|
||||
CacheSessionKey bool
|
||||
// CheckPacketSequence is a flag that controls if the pgp message reader should strictly check
|
||||
// that the packet sequence conforms with the grammar mandated by rfc4880.
|
||||
// The default behavior, when the config or flag is nil, is to check the packet sequence.
|
||||
CheckPacketSequence *bool
|
||||
// NonDeterministicSignaturesViaNotation is a flag to enable randomization of signatures.
|
||||
// If true, a salt notation is used to randomize signatures generated by v4 and v5 keys
|
||||
// (v6 signatures are always non-deterministic, by design).
|
||||
// This protects EdDSA signatures from potentially leaking the secret key in case of faults (i.e. bitflips) which, in principle, could occur
|
||||
// during the signing computation. It is added to signatures of any algo for simplicity, and as it may also serve as protection in case of
|
||||
// weaknesses in the hash algo, potentially hindering e.g. some chosen-prefix attacks.
|
||||
// The default behavior, when the config or flag is nil, is to enable the feature.
|
||||
NonDeterministicSignaturesViaNotation *bool
|
||||
|
||||
// InsecureAllowAllKeyFlagsWhenMissing determines how a key without valid key flags is handled.
|
||||
// When set to true, a key without flags is treated as if all flags are enabled.
|
||||
// This behavior is consistent with GPG.
|
||||
InsecureAllowAllKeyFlagsWhenMissing bool
|
||||
}
|
||||
|
||||
func (c *Config) Random() io.Reader {
|
||||
if c == nil || c.Rand == nil {
|
||||
return rand.Reader
|
||||
}
|
||||
return c.Rand
|
||||
}
|
||||
|
||||
func (c *Config) Hash() crypto.Hash {
|
||||
if c == nil || uint(c.DefaultHash) == 0 {
|
||||
return crypto.SHA256
|
||||
}
|
||||
return c.DefaultHash
|
||||
}
|
||||
|
||||
func (c *Config) Cipher() CipherFunction {
|
||||
if c == nil || uint8(c.DefaultCipher) == 0 {
|
||||
return CipherAES128
|
||||
}
|
||||
return c.DefaultCipher
|
||||
}
|
||||
|
||||
func (c *Config) Now() time.Time {
|
||||
if c == nil || c.Time == nil {
|
||||
return time.Now().Truncate(time.Second)
|
||||
}
|
||||
return c.Time().Truncate(time.Second)
|
||||
}
|
||||
|
||||
// KeyLifetime returns the validity period of the key.
|
||||
func (c *Config) KeyLifetime() uint32 {
|
||||
if c == nil {
|
||||
return 0
|
||||
}
|
||||
return c.KeyLifetimeSecs
|
||||
}
|
||||
|
||||
// SigLifetime returns the validity period of the signature.
|
||||
func (c *Config) SigLifetime() uint32 {
|
||||
if c == nil {
|
||||
return 0
|
||||
}
|
||||
return c.SigLifetimeSecs
|
||||
}
|
||||
|
||||
func (c *Config) Compression() CompressionAlgo {
|
||||
if c == nil {
|
||||
return CompressionNone
|
||||
}
|
||||
return c.DefaultCompressionAlgo
|
||||
}
|
||||
|
||||
func (c *Config) RSAModulusBits() int {
|
||||
if c == nil || c.RSABits == 0 {
|
||||
return 2048
|
||||
}
|
||||
return c.RSABits
|
||||
}
|
||||
|
||||
func (c *Config) PublicKeyAlgorithm() PublicKeyAlgorithm {
|
||||
if c == nil || c.Algorithm == 0 {
|
||||
return PubKeyAlgoRSA
|
||||
}
|
||||
return c.Algorithm
|
||||
}
|
||||
|
||||
func (c *Config) CurveName() Curve {
|
||||
if c == nil || c.Curve == "" {
|
||||
return Curve25519
|
||||
}
|
||||
return c.Curve
|
||||
}
|
||||
|
||||
// Deprecated: The hash iterations should now be queried via the S2K() method.
|
||||
func (c *Config) PasswordHashIterations() int {
|
||||
if c == nil || c.S2KCount == 0 {
|
||||
return 0
|
||||
}
|
||||
return c.S2KCount
|
||||
}
|
||||
|
||||
func (c *Config) S2K() *s2k.Config {
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
// for backwards compatibility
|
||||
if c.S2KCount > 0 && c.S2KConfig == nil {
|
||||
return &s2k.Config{
|
||||
S2KCount: c.S2KCount,
|
||||
}
|
||||
}
|
||||
return c.S2KConfig
|
||||
}
|
||||
|
||||
func (c *Config) AEAD() *AEADConfig {
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
return c.AEADConfig
|
||||
}
|
||||
|
||||
func (c *Config) SigningKey() uint64 {
|
||||
if c == nil {
|
||||
return 0
|
||||
}
|
||||
return c.SigningKeyId
|
||||
}
|
||||
|
||||
func (c *Config) SigningUserId() string {
|
||||
if c == nil {
|
||||
return ""
|
||||
}
|
||||
return c.SigningIdentity
|
||||
}
|
||||
|
||||
func (c *Config) AllowUnauthenticatedMessages() bool {
|
||||
if c == nil {
|
||||
return false
|
||||
}
|
||||
return c.InsecureAllowUnauthenticatedMessages
|
||||
}
|
||||
|
||||
func (c *Config) AllowDecryptionWithSigningKeys() bool {
|
||||
if c == nil {
|
||||
return false
|
||||
}
|
||||
return c.InsecureAllowDecryptionWithSigningKeys
|
||||
}
|
||||
|
||||
func (c *Config) KnownNotation(notationName string) bool {
|
||||
if c == nil {
|
||||
return false
|
||||
}
|
||||
return c.KnownNotations[notationName]
|
||||
}
|
||||
|
||||
func (c *Config) Notations() []*Notation {
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
return c.SignatureNotations
|
||||
}
|
||||
|
||||
func (c *Config) V6() bool {
|
||||
if c == nil {
|
||||
return false
|
||||
}
|
||||
return c.V6Keys
|
||||
}
|
||||
|
||||
func (c *Config) IntendedRecipients() bool {
|
||||
if c == nil || c.CheckIntendedRecipients == nil {
|
||||
return true
|
||||
}
|
||||
return *c.CheckIntendedRecipients
|
||||
}
|
||||
|
||||
func (c *Config) RetrieveSessionKey() bool {
|
||||
if c == nil {
|
||||
return false
|
||||
}
|
||||
return c.CacheSessionKey
|
||||
}
|
||||
|
||||
func (c *Config) MinimumRSABits() uint16 {
|
||||
if c == nil || c.MinRSABits == 0 {
|
||||
return 2047
|
||||
}
|
||||
return c.MinRSABits
|
||||
}
|
||||
|
||||
func (c *Config) RejectPublicKeyAlgorithm(alg PublicKeyAlgorithm) bool {
|
||||
var rejectedAlgorithms map[PublicKeyAlgorithm]bool
|
||||
if c == nil || c.RejectPublicKeyAlgorithms == nil {
|
||||
// Default
|
||||
rejectedAlgorithms = defaultRejectPublicKeyAlgorithms
|
||||
} else {
|
||||
rejectedAlgorithms = c.RejectPublicKeyAlgorithms
|
||||
}
|
||||
return rejectedAlgorithms[alg]
|
||||
}
|
||||
|
||||
func (c *Config) RejectHashAlgorithm(hash crypto.Hash) bool {
|
||||
var rejectedAlgorithms map[crypto.Hash]bool
|
||||
if c == nil || c.RejectHashAlgorithms == nil {
|
||||
// Default
|
||||
rejectedAlgorithms = defaultRejectHashAlgorithms
|
||||
} else {
|
||||
rejectedAlgorithms = c.RejectHashAlgorithms
|
||||
}
|
||||
return rejectedAlgorithms[hash]
|
||||
}
|
||||
|
||||
func (c *Config) RejectMessageHashAlgorithm(hash crypto.Hash) bool {
|
||||
var rejectedAlgorithms map[crypto.Hash]bool
|
||||
if c == nil || c.RejectMessageHashAlgorithms == nil {
|
||||
// Default
|
||||
rejectedAlgorithms = defaultRejectMessageHashAlgorithms
|
||||
} else {
|
||||
rejectedAlgorithms = c.RejectMessageHashAlgorithms
|
||||
}
|
||||
return rejectedAlgorithms[hash]
|
||||
}
|
||||
|
||||
func (c *Config) RejectCurve(curve Curve) bool {
|
||||
var rejectedCurve map[Curve]bool
|
||||
if c == nil || c.RejectCurves == nil {
|
||||
// Default
|
||||
rejectedCurve = defaultRejectCurves
|
||||
} else {
|
||||
rejectedCurve = c.RejectCurves
|
||||
}
|
||||
return rejectedCurve[curve]
|
||||
}
|
||||
|
||||
func (c *Config) StrictPacketSequence() bool {
|
||||
if c == nil || c.CheckPacketSequence == nil {
|
||||
return true
|
||||
}
|
||||
return *c.CheckPacketSequence
|
||||
}
|
||||
|
||||
func (c *Config) RandomizeSignaturesViaNotation() bool {
|
||||
if c == nil || c.NonDeterministicSignaturesViaNotation == nil {
|
||||
return true
|
||||
}
|
||||
return *c.NonDeterministicSignaturesViaNotation
|
||||
}
|
||||
|
||||
func (c *Config) AllowAllKeyFlagsWhenMissing() bool {
|
||||
if c == nil {
|
||||
return false
|
||||
}
|
||||
return c.InsecureAllowAllKeyFlagsWhenMissing
|
||||
}
|
||||
|
||||
// BoolPointer is a helper function to set a boolean pointer in the Config.
|
||||
// e.g., config.CheckPacketSequence = BoolPointer(true)
|
||||
func BoolPointer(value bool) *bool {
|
||||
return &value
|
||||
}
|
7
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/config_v5.go
generated
vendored
Normal file
7
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/config_v5.go
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
//go:build !v5
|
||||
|
||||
package packet
|
||||
|
||||
func init() {
|
||||
V5Disabled = true
|
||||
}
|
584
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/encrypted_key.go
generated
vendored
Normal file
584
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/encrypted_key.go
generated
vendored
Normal file
@ -0,0 +1,584 @@
|
||||
// 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/rsa"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"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"
|
||||
"github.com/ProtonMail/go-crypto/openpgp/x25519"
|
||||
"github.com/ProtonMail/go-crypto/openpgp/x448"
|
||||
)
|
||||
|
||||
// EncryptedKey represents a public-key encrypted session key. See RFC 4880,
|
||||
// section 5.1.
|
||||
type EncryptedKey struct {
|
||||
Version int
|
||||
KeyId uint64
|
||||
KeyVersion int // v6
|
||||
KeyFingerprint []byte // v6
|
||||
Algo PublicKeyAlgorithm
|
||||
CipherFunc CipherFunction // only valid after a successful Decrypt for a v3 packet
|
||||
Key []byte // only valid after a successful Decrypt
|
||||
|
||||
encryptedMPI1, encryptedMPI2 encoding.Field
|
||||
ephemeralPublicX25519 *x25519.PublicKey // used for x25519
|
||||
ephemeralPublicX448 *x448.PublicKey // used for x448
|
||||
encryptedSession []byte // used for x25519 and x448
|
||||
}
|
||||
|
||||
func (e *EncryptedKey) parse(r io.Reader) (err error) {
|
||||
var buf [8]byte
|
||||
_, err = readFull(r, buf[:versionSize])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
e.Version = int(buf[0])
|
||||
if e.Version != 3 && e.Version != 6 {
|
||||
return errors.UnsupportedError("unknown EncryptedKey version " + strconv.Itoa(int(buf[0])))
|
||||
}
|
||||
if e.Version == 6 {
|
||||
//Read a one-octet size of the following two fields.
|
||||
if _, err = readFull(r, buf[:1]); err != nil {
|
||||
return
|
||||
}
|
||||
// The size may also be zero, and the key version and
|
||||
// fingerprint omitted for an "anonymous recipient"
|
||||
if buf[0] != 0 {
|
||||
// non-anonymous case
|
||||
_, err = readFull(r, buf[:versionSize])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
e.KeyVersion = int(buf[0])
|
||||
if e.KeyVersion != 4 && e.KeyVersion != 6 {
|
||||
return errors.UnsupportedError("unknown public key version " + strconv.Itoa(e.KeyVersion))
|
||||
}
|
||||
var fingerprint []byte
|
||||
if e.KeyVersion == 6 {
|
||||
fingerprint = make([]byte, fingerprintSizeV6)
|
||||
} else if e.KeyVersion == 4 {
|
||||
fingerprint = make([]byte, fingerprintSize)
|
||||
}
|
||||
_, err = readFull(r, fingerprint)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
e.KeyFingerprint = fingerprint
|
||||
if e.KeyVersion == 6 {
|
||||
e.KeyId = binary.BigEndian.Uint64(e.KeyFingerprint[:keyIdSize])
|
||||
} else if e.KeyVersion == 4 {
|
||||
e.KeyId = binary.BigEndian.Uint64(e.KeyFingerprint[fingerprintSize-keyIdSize : fingerprintSize])
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_, err = readFull(r, buf[:8])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
e.KeyId = binary.BigEndian.Uint64(buf[:keyIdSize])
|
||||
}
|
||||
|
||||
_, err = readFull(r, buf[:1])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
e.Algo = PublicKeyAlgorithm(buf[0])
|
||||
var cipherFunction byte
|
||||
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
|
||||
}
|
||||
case PubKeyAlgoX25519:
|
||||
e.ephemeralPublicX25519, e.encryptedSession, cipherFunction, err = x25519.DecodeFields(r, e.Version == 6)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
case PubKeyAlgoX448:
|
||||
e.ephemeralPublicX448, e.encryptedSession, cipherFunction, err = x448.DecodeFields(r, e.Version == 6)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
if e.Version < 6 {
|
||||
switch e.Algo {
|
||||
case PubKeyAlgoX25519, PubKeyAlgoX448:
|
||||
e.CipherFunc = CipherFunction(cipherFunction)
|
||||
// Check for validiy is in the Decrypt method
|
||||
}
|
||||
}
|
||||
|
||||
_, err = consumeAll(r)
|
||||
return
|
||||
}
|
||||
|
||||
// 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.Version < 6 && 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.Version == 6 && e.KeyVersion != 0 && !bytes.Equal(e.KeyFingerprint, priv.Fingerprint) {
|
||||
return errors.InvalidArgumentError("cannot decrypt encrypted session key for key fingerprint " + hex.EncodeToString(e.KeyFingerprint) + " with private key fingerprint " + hex.EncodeToString(priv.Fingerprint))
|
||||
}
|
||||
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()
|
||||
fp := priv.PublicKey.Fingerprint[:]
|
||||
if priv.PublicKey.Version == 5 {
|
||||
// For v5 the, the fingerprint must be restricted to 20 bytes
|
||||
fp = fp[:20]
|
||||
}
|
||||
b, err = ecdh.Decrypt(priv.PrivateKey.(*ecdh.PrivateKey), vsG, m, oid, fp)
|
||||
case PubKeyAlgoX25519:
|
||||
b, err = x25519.Decrypt(priv.PrivateKey.(*x25519.PrivateKey), e.ephemeralPublicX25519, e.encryptedSession)
|
||||
case PubKeyAlgoX448:
|
||||
b, err = x448.Decrypt(priv.PrivateKey.(*x448.PrivateKey), e.ephemeralPublicX448, e.encryptedSession)
|
||||
default:
|
||||
err = errors.InvalidArgumentError("cannot decrypt encrypted session key with private key of type " + strconv.Itoa(int(priv.PubKeyAlgo)))
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var key []byte
|
||||
switch priv.PubKeyAlgo {
|
||||
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoElGamal, PubKeyAlgoECDH:
|
||||
keyOffset := 0
|
||||
if e.Version < 6 {
|
||||
e.CipherFunc = CipherFunction(b[0])
|
||||
keyOffset = 1
|
||||
if !e.CipherFunc.IsSupported() {
|
||||
return errors.UnsupportedError("unsupported encryption function")
|
||||
}
|
||||
}
|
||||
key, err = decodeChecksumKey(b[keyOffset:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case PubKeyAlgoX25519, PubKeyAlgoX448:
|
||||
if e.Version < 6 {
|
||||
switch e.CipherFunc {
|
||||
case CipherAES128, CipherAES192, CipherAES256:
|
||||
break
|
||||
default:
|
||||
return errors.StructuralError("v3 PKESK mandates AES as cipher function for x25519 and x448")
|
||||
}
|
||||
}
|
||||
key = b[:]
|
||||
default:
|
||||
return errors.UnsupportedError("unsupported algorithm for decryption")
|
||||
}
|
||||
e.Key = key
|
||||
return nil
|
||||
}
|
||||
|
||||
// Serialize writes the encrypted key packet, e, to w.
|
||||
func (e *EncryptedKey) Serialize(w io.Writer) error {
|
||||
var encodedLength int
|
||||
switch e.Algo {
|
||||
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
|
||||
encodedLength = int(e.encryptedMPI1.EncodedLength())
|
||||
case PubKeyAlgoElGamal:
|
||||
encodedLength = int(e.encryptedMPI1.EncodedLength()) + int(e.encryptedMPI2.EncodedLength())
|
||||
case PubKeyAlgoECDH:
|
||||
encodedLength = int(e.encryptedMPI1.EncodedLength()) + int(e.encryptedMPI2.EncodedLength())
|
||||
case PubKeyAlgoX25519:
|
||||
encodedLength = x25519.EncodedFieldsLength(e.encryptedSession, e.Version == 6)
|
||||
case PubKeyAlgoX448:
|
||||
encodedLength = x448.EncodedFieldsLength(e.encryptedSession, e.Version == 6)
|
||||
default:
|
||||
return errors.InvalidArgumentError("don't know how to serialize encrypted key type " + strconv.Itoa(int(e.Algo)))
|
||||
}
|
||||
|
||||
packetLen := versionSize /* version */ + keyIdSize /* key id */ + algorithmSize /* algo */ + encodedLength
|
||||
if e.Version == 6 {
|
||||
packetLen = versionSize /* version */ + algorithmSize /* algo */ + encodedLength + keyVersionSize /* key version */
|
||||
if e.KeyVersion == 6 {
|
||||
packetLen += fingerprintSizeV6
|
||||
} else if e.KeyVersion == 4 {
|
||||
packetLen += fingerprintSize
|
||||
}
|
||||
}
|
||||
|
||||
err := serializeHeader(w, packetTypeEncryptedKey, packetLen)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = w.Write([]byte{byte(e.Version)})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if e.Version == 6 {
|
||||
_, err = w.Write([]byte{byte(e.KeyVersion)})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// The key version number may also be zero,
|
||||
// and the fingerprint omitted
|
||||
if e.KeyVersion != 0 {
|
||||
_, err = w.Write(e.KeyFingerprint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Write KeyID
|
||||
err = binary.Write(w, binary.BigEndian, e.KeyId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
_, err = w.Write([]byte{byte(e.Algo)})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
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
|
||||
case PubKeyAlgoX25519:
|
||||
err := x25519.EncodeFields(w, e.ephemeralPublicX25519, e.encryptedSession, byte(e.CipherFunc), e.Version == 6)
|
||||
return err
|
||||
case PubKeyAlgoX448:
|
||||
err := x448.EncodeFields(w, e.ephemeralPublicX448, e.encryptedSession, byte(e.CipherFunc), e.Version == 6)
|
||||
return err
|
||||
default:
|
||||
panic("internal error")
|
||||
}
|
||||
}
|
||||
|
||||
// SerializeEncryptedKeyAEAD serializes an encrypted key packet to w that contains
|
||||
// key, encrypted to pub.
|
||||
// If aeadSupported is set, PKESK v6 is used, otherwise v3.
|
||||
// Note: aeadSupported MUST match the value passed to SerializeSymmetricallyEncrypted.
|
||||
// If config is nil, sensible defaults will be used.
|
||||
func SerializeEncryptedKeyAEAD(w io.Writer, pub *PublicKey, cipherFunc CipherFunction, aeadSupported bool, key []byte, config *Config) error {
|
||||
return SerializeEncryptedKeyAEADwithHiddenOption(w, pub, cipherFunc, aeadSupported, key, false, config)
|
||||
}
|
||||
|
||||
// SerializeEncryptedKeyAEADwithHiddenOption serializes an encrypted key packet to w that contains
|
||||
// key, encrypted to pub.
|
||||
// Offers the hidden flag option to indicated if the PKESK packet should include a wildcard KeyID.
|
||||
// If aeadSupported is set, PKESK v6 is used, otherwise v3.
|
||||
// Note: aeadSupported MUST match the value passed to SerializeSymmetricallyEncrypted.
|
||||
// If config is nil, sensible defaults will be used.
|
||||
func SerializeEncryptedKeyAEADwithHiddenOption(w io.Writer, pub *PublicKey, cipherFunc CipherFunction, aeadSupported bool, key []byte, hidden bool, config *Config) error {
|
||||
var buf [36]byte // max possible header size is v6
|
||||
lenHeaderWritten := versionSize
|
||||
version := 3
|
||||
|
||||
if aeadSupported {
|
||||
version = 6
|
||||
}
|
||||
// An implementation MUST NOT generate ElGamal v6 PKESKs.
|
||||
if version == 6 && pub.PubKeyAlgo == PubKeyAlgoElGamal {
|
||||
return errors.InvalidArgumentError("ElGamal v6 PKESK are not allowed")
|
||||
}
|
||||
// In v3 PKESKs, for x25519 and x448, mandate using AES
|
||||
if version == 3 && (pub.PubKeyAlgo == PubKeyAlgoX25519 || pub.PubKeyAlgo == PubKeyAlgoX448) {
|
||||
switch cipherFunc {
|
||||
case CipherAES128, CipherAES192, CipherAES256:
|
||||
break
|
||||
default:
|
||||
return errors.InvalidArgumentError("v3 PKESK mandates AES for x25519 and x448")
|
||||
}
|
||||
}
|
||||
|
||||
buf[0] = byte(version)
|
||||
|
||||
// If hidden is set, the key should be hidden
|
||||
// An implementation MAY accept or use a Key ID of all zeros,
|
||||
// or a key version of zero and no key fingerprint, to hide the intended decryption key.
|
||||
// See Section 5.1.8. in the open pgp crypto refresh
|
||||
if version == 6 {
|
||||
if !hidden {
|
||||
// A one-octet size of the following two fields.
|
||||
buf[1] = byte(keyVersionSize + len(pub.Fingerprint))
|
||||
// A one octet key version number.
|
||||
buf[2] = byte(pub.Version)
|
||||
lenHeaderWritten += keyVersionSize + 1
|
||||
// The fingerprint of the public key
|
||||
copy(buf[lenHeaderWritten:lenHeaderWritten+len(pub.Fingerprint)], pub.Fingerprint)
|
||||
lenHeaderWritten += len(pub.Fingerprint)
|
||||
} else {
|
||||
// The size may also be zero, and the key version
|
||||
// and fingerprint omitted for an "anonymous recipient"
|
||||
buf[1] = 0
|
||||
lenHeaderWritten += 1
|
||||
}
|
||||
} else {
|
||||
if !hidden {
|
||||
binary.BigEndian.PutUint64(buf[versionSize:(versionSize+keyIdSize)], pub.KeyId)
|
||||
}
|
||||
lenHeaderWritten += keyIdSize
|
||||
}
|
||||
buf[lenHeaderWritten] = byte(pub.PubKeyAlgo)
|
||||
lenHeaderWritten += algorithmSize
|
||||
|
||||
var keyBlock []byte
|
||||
switch pub.PubKeyAlgo {
|
||||
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoElGamal, PubKeyAlgoECDH:
|
||||
lenKeyBlock := len(key) + 2
|
||||
if version < 6 {
|
||||
lenKeyBlock += 1 // cipher type included
|
||||
}
|
||||
keyBlock = make([]byte, lenKeyBlock)
|
||||
keyOffset := 0
|
||||
if version < 6 {
|
||||
keyBlock[0] = byte(cipherFunc)
|
||||
keyOffset = 1
|
||||
}
|
||||
encodeChecksumKey(keyBlock[keyOffset:], key)
|
||||
case PubKeyAlgoX25519, PubKeyAlgoX448:
|
||||
// algorithm is added in plaintext below
|
||||
keyBlock = key
|
||||
}
|
||||
|
||||
switch pub.PubKeyAlgo {
|
||||
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
|
||||
return serializeEncryptedKeyRSA(w, config.Random(), buf[:lenHeaderWritten], pub.PublicKey.(*rsa.PublicKey), keyBlock)
|
||||
case PubKeyAlgoElGamal:
|
||||
return serializeEncryptedKeyElGamal(w, config.Random(), buf[:lenHeaderWritten], pub.PublicKey.(*elgamal.PublicKey), keyBlock)
|
||||
case PubKeyAlgoECDH:
|
||||
return serializeEncryptedKeyECDH(w, config.Random(), buf[:lenHeaderWritten], pub.PublicKey.(*ecdh.PublicKey), keyBlock, pub.oid, pub.Fingerprint)
|
||||
case PubKeyAlgoX25519:
|
||||
return serializeEncryptedKeyX25519(w, config.Random(), buf[:lenHeaderWritten], pub.PublicKey.(*x25519.PublicKey), keyBlock, byte(cipherFunc), version)
|
||||
case PubKeyAlgoX448:
|
||||
return serializeEncryptedKeyX448(w, config.Random(), buf[:lenHeaderWritten], pub.PublicKey.(*x448.PublicKey), keyBlock, byte(cipherFunc), version)
|
||||
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)))
|
||||
}
|
||||
|
||||
// SerializeEncryptedKey serializes an encrypted key packet to w that contains
|
||||
// key, encrypted to pub.
|
||||
// PKESKv6 is used if config.AEAD() is not nil.
|
||||
// If config is nil, sensible defaults will be used.
|
||||
// Deprecated: Use SerializeEncryptedKeyAEAD instead.
|
||||
func SerializeEncryptedKey(w io.Writer, pub *PublicKey, cipherFunc CipherFunction, key []byte, config *Config) error {
|
||||
return SerializeEncryptedKeyAEAD(w, pub, cipherFunc, config.AEAD() != nil, key, config)
|
||||
}
|
||||
|
||||
// SerializeEncryptedKeyWithHiddenOption serializes an encrypted key packet to w that contains
|
||||
// key, encrypted to pub. PKESKv6 is used if config.AEAD() is not nil.
|
||||
// The hidden option controls if the packet should be anonymous, i.e., omit key metadata.
|
||||
// If config is nil, sensible defaults will be used.
|
||||
// Deprecated: Use SerializeEncryptedKeyAEADwithHiddenOption instead.
|
||||
func SerializeEncryptedKeyWithHiddenOption(w io.Writer, pub *PublicKey, cipherFunc CipherFunction, key []byte, hidden bool, config *Config) error {
|
||||
return SerializeEncryptedKeyAEADwithHiddenOption(w, pub, cipherFunc, config.AEAD() != nil, key, hidden, config)
|
||||
}
|
||||
|
||||
func serializeEncryptedKeyRSA(w io.Writer, rand io.Reader, header []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 := len(header) /* 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 []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 := len(header) /* 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 []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 := len(header) /* 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
|
||||
}
|
||||
|
||||
func serializeEncryptedKeyX25519(w io.Writer, rand io.Reader, header []byte, pub *x25519.PublicKey, keyBlock []byte, cipherFunc byte, version int) error {
|
||||
ephemeralPublicX25519, ciphertext, err := x25519.Encrypt(rand, pub, keyBlock)
|
||||
if err != nil {
|
||||
return errors.InvalidArgumentError("x25519 encryption failed: " + err.Error())
|
||||
}
|
||||
|
||||
packetLen := len(header) /* header length */
|
||||
packetLen += x25519.EncodedFieldsLength(ciphertext, version == 6)
|
||||
|
||||
err = serializeHeader(w, packetTypeEncryptedKey, packetLen)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = w.Write(header[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return x25519.EncodeFields(w, ephemeralPublicX25519, ciphertext, cipherFunc, version == 6)
|
||||
}
|
||||
|
||||
func serializeEncryptedKeyX448(w io.Writer, rand io.Reader, header []byte, pub *x448.PublicKey, keyBlock []byte, cipherFunc byte, version int) error {
|
||||
ephemeralPublicX448, ciphertext, err := x448.Encrypt(rand, pub, keyBlock)
|
||||
if err != nil {
|
||||
return errors.InvalidArgumentError("x448 encryption failed: " + err.Error())
|
||||
}
|
||||
|
||||
packetLen := len(header) /* header length */
|
||||
packetLen += x448.EncodedFieldsLength(ciphertext, version == 6)
|
||||
|
||||
err = serializeHeader(w, packetTypeEncryptedKey, packetLen)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = w.Write(header[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return x448.EncodeFields(w, ephemeralPublicX448, ciphertext, cipherFunc, version == 6)
|
||||
}
|
||||
|
||||
func checksumKeyMaterial(key []byte) uint16 {
|
||||
var checksum uint16
|
||||
for _, v := range key {
|
||||
checksum += uint16(v)
|
||||
}
|
||||
return checksum
|
||||
}
|
||||
|
||||
func decodeChecksumKey(msg []byte) (key []byte, err error) {
|
||||
key = msg[:len(msg)-2]
|
||||
expectedChecksum := uint16(msg[len(msg)-2])<<8 | uint16(msg[len(msg)-1])
|
||||
checksum := checksumKeyMaterial(key)
|
||||
if checksum != expectedChecksum {
|
||||
err = errors.StructuralError("session key checksum is incorrect")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func encodeChecksumKey(buffer []byte, key []byte) {
|
||||
copy(buffer, key)
|
||||
checksum := checksumKeyMaterial(key)
|
||||
buffer[len(key)] = byte(checksum >> 8)
|
||||
buffer[len(key)+1] = byte(checksum)
|
||||
}
|
@ -11,6 +11,7 @@ import (
|
||||
|
||||
// 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.
|
||||
@ -31,7 +32,8 @@ func (l *LiteralData) parse(r io.Reader) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
l.IsBinary = buf[0] == 'b'
|
||||
l.Format = buf[0]
|
||||
l.IsBinary = l.Format == 'b'
|
||||
fileNameLen := int(buf[1])
|
||||
|
||||
_, err = readFull(r, buf[:fileNameLen])
|
||||
@ -56,9 +58,9 @@ func (l *LiteralData) parse(r io.Reader) (err error) {
|
||||
// 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'
|
||||
buf[0] = 'b'
|
||||
if !isBinary {
|
||||
buf[0] = 'u'
|
||||
}
|
||||
if len(fileName) > 255 {
|
||||
fileName = fileName[:255]
|
33
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/marker.go
generated
vendored
Normal file
33
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/marker.go
generated
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
package packet
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/ProtonMail/go-crypto/openpgp/errors"
|
||||
)
|
||||
|
||||
type Marker struct{}
|
||||
|
||||
const markerString = "PGP"
|
||||
|
||||
// parse just checks if the packet contains "PGP".
|
||||
func (m *Marker) parse(reader io.Reader) error {
|
||||
var buffer [3]byte
|
||||
if _, err := io.ReadFull(reader, buffer[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
if string(buffer[:]) != markerString {
|
||||
return errors.StructuralError("invalid marker packet")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SerializeMarker writes a marker packet to writer.
|
||||
func SerializeMarker(writer io.Writer) error {
|
||||
err := serializeHeader(writer, packetTypeMarker, len(markerString))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = writer.Write([]byte(markerString))
|
||||
return err
|
||||
}
|
29
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/notation.go
generated
vendored
Normal file
29
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/notation.go
generated
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
package packet
|
||||
|
||||
// Notation type represents a Notation Data subpacket
|
||||
// see https://tools.ietf.org/html/rfc4880#section-5.2.3.16
|
||||
type Notation struct {
|
||||
Name string
|
||||
Value []byte
|
||||
IsCritical bool
|
||||
IsHumanReadable bool
|
||||
}
|
||||
|
||||
func (notation *Notation) getData() []byte {
|
||||
nameData := []byte(notation.Name)
|
||||
nameLen := len(nameData)
|
||||
valueLen := len(notation.Value)
|
||||
|
||||
data := make([]byte, 8+nameLen+valueLen)
|
||||
if notation.IsHumanReadable {
|
||||
data[0] = 0x80
|
||||
}
|
||||
|
||||
data[4] = byte(nameLen >> 8)
|
||||
data[5] = byte(nameLen)
|
||||
data[6] = byte(valueLen >> 8)
|
||||
data[7] = byte(valueLen)
|
||||
copy(data[8:8+nameLen], nameData)
|
||||
copy(data[8+nameLen:], notation.Value)
|
||||
return data
|
||||
}
|
@ -85,8 +85,7 @@ type ocfbDecrypter struct {
|
||||
// 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. If an incorrect key is detected then nil is returned. On
|
||||
// successful exit, blockSize+2 bytes of decrypted data are written into
|
||||
// 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 {
|
||||
@ -112,11 +111,6 @@ func NewOCFBDecrypter(block cipher.Block, prefix []byte, resync OCFBResyncOption
|
||||
prefixCopy[blockSize] ^= x.fre[0]
|
||||
prefixCopy[blockSize+1] ^= x.fre[1]
|
||||
|
||||
if prefixCopy[blockSize-2] != prefixCopy[blockSize] ||
|
||||
prefixCopy[blockSize-1] != prefixCopy[blockSize+1] {
|
||||
return nil
|
||||
}
|
||||
|
||||
if resync {
|
||||
block.Encrypt(x.fre, prefix[2:])
|
||||
} else {
|
157
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/one_pass_signature.go
generated
vendored
Normal file
157
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/one_pass_signature.go
generated
vendored
Normal file
@ -0,0 +1,157 @@
|
||||
// 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"
|
||||
"io"
|
||||
"strconv"
|
||||
|
||||
"github.com/ProtonMail/go-crypto/openpgp/errors"
|
||||
"github.com/ProtonMail/go-crypto/openpgp/internal/algorithm"
|
||||
)
|
||||
|
||||
// OnePassSignature represents a one-pass signature packet. See RFC 4880,
|
||||
// section 5.4.
|
||||
type OnePassSignature struct {
|
||||
Version int
|
||||
SigType SignatureType
|
||||
Hash crypto.Hash
|
||||
PubKeyAlgo PublicKeyAlgorithm
|
||||
KeyId uint64
|
||||
IsLast bool
|
||||
Salt []byte // v6 only
|
||||
KeyFingerprint []byte // v6 only
|
||||
}
|
||||
|
||||
func (ops *OnePassSignature) parse(r io.Reader) (err error) {
|
||||
var buf [8]byte
|
||||
// Read: version | signature type | hash algorithm | public-key algorithm
|
||||
_, err = readFull(r, buf[:4])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if buf[0] != 3 && buf[0] != 6 {
|
||||
return errors.UnsupportedError("one-pass-signature packet version " + strconv.Itoa(int(buf[0])))
|
||||
}
|
||||
ops.Version = int(buf[0])
|
||||
|
||||
var ok bool
|
||||
ops.Hash, ok = algorithm.HashIdToHashWithSha1(buf[2])
|
||||
if !ok {
|
||||
return errors.UnsupportedError("hash function: " + strconv.Itoa(int(buf[2])))
|
||||
}
|
||||
|
||||
ops.SigType = SignatureType(buf[1])
|
||||
ops.PubKeyAlgo = PublicKeyAlgorithm(buf[3])
|
||||
|
||||
if ops.Version == 6 {
|
||||
// Only for v6, a variable-length field containing the salt
|
||||
_, err = readFull(r, buf[:1])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
saltLength := int(buf[0])
|
||||
var expectedSaltLength int
|
||||
expectedSaltLength, err = SaltLengthForHash(ops.Hash)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if saltLength != expectedSaltLength {
|
||||
err = errors.StructuralError("unexpected salt size for the given hash algorithm")
|
||||
return
|
||||
}
|
||||
salt := make([]byte, expectedSaltLength)
|
||||
_, err = readFull(r, salt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
ops.Salt = salt
|
||||
|
||||
// Only for v6 packets, 32 octets of the fingerprint of the signing key.
|
||||
fingerprint := make([]byte, 32)
|
||||
_, err = readFull(r, fingerprint)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
ops.KeyFingerprint = fingerprint
|
||||
ops.KeyId = binary.BigEndian.Uint64(ops.KeyFingerprint[:8])
|
||||
} else {
|
||||
_, err = readFull(r, buf[:8])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
ops.KeyId = binary.BigEndian.Uint64(buf[:8])
|
||||
}
|
||||
|
||||
_, err = readFull(r, buf[:1])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
ops.IsLast = buf[0] != 0
|
||||
return
|
||||
}
|
||||
|
||||
// Serialize marshals the given OnePassSignature to w.
|
||||
func (ops *OnePassSignature) Serialize(w io.Writer) error {
|
||||
//v3 length 1+1+1+1+8+1 =
|
||||
packetLength := 13
|
||||
if ops.Version == 6 {
|
||||
// v6 length 1+1+1+1+1+len(salt)+32+1 =
|
||||
packetLength = 38 + len(ops.Salt)
|
||||
}
|
||||
|
||||
if err := serializeHeader(w, packetTypeOnePassSignature, packetLength); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var buf [8]byte
|
||||
buf[0] = byte(ops.Version)
|
||||
buf[1] = uint8(ops.SigType)
|
||||
var ok bool
|
||||
buf[2], ok = algorithm.HashToHashIdWithSha1(ops.Hash)
|
||||
if !ok {
|
||||
return errors.UnsupportedError("hash type: " + strconv.Itoa(int(ops.Hash)))
|
||||
}
|
||||
buf[3] = uint8(ops.PubKeyAlgo)
|
||||
|
||||
_, err := w.Write(buf[:4])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if ops.Version == 6 {
|
||||
// write salt for v6 signatures
|
||||
_, err := w.Write([]byte{uint8(len(ops.Salt))})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = w.Write(ops.Salt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// write fingerprint v6 signatures
|
||||
_, err = w.Write(ops.KeyFingerprint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
binary.BigEndian.PutUint64(buf[:8], ops.KeyId)
|
||||
_, err := w.Write(buf[:8])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
isLast := []byte{byte(0)}
|
||||
if ops.IsLast {
|
||||
isLast[0] = 1
|
||||
}
|
||||
|
||||
_, err = w.Write(isLast)
|
||||
return err
|
||||
}
|
@ -8,7 +8,7 @@ import (
|
||||
"bytes"
|
||||
"io"
|
||||
|
||||
"golang.org/x/crypto/openpgp/errors"
|
||||
"github.com/ProtonMail/go-crypto/openpgp/errors"
|
||||
)
|
||||
|
||||
// OpaquePacket represents an OpenPGP packet as raw, unparsed data. This is
|
||||
@ -83,8 +83,9 @@ func (or *OpaqueReader) Next() (op *OpaquePacket, err error) {
|
||||
// OpaqueSubpacket represents an unparsed OpenPGP subpacket,
|
||||
// as found in signature and user attribute packets.
|
||||
type OpaqueSubpacket struct {
|
||||
SubType uint8
|
||||
Contents []byte
|
||||
SubType uint8
|
||||
EncodedLength []byte // Store the original encoded length for signature verifications.
|
||||
Contents []byte
|
||||
}
|
||||
|
||||
// OpaqueSubpackets extracts opaque, unparsed OpenPGP subpackets from
|
||||
@ -108,6 +109,7 @@ func OpaqueSubpackets(contents []byte) (result []*OpaqueSubpacket, err error) {
|
||||
func nextSubpacket(contents []byte) (subHeaderLen int, subPacket *OpaqueSubpacket, err error) {
|
||||
// RFC 4880, section 5.2.3.1
|
||||
var subLen uint32
|
||||
var encodedLength []byte
|
||||
if len(contents) < 1 {
|
||||
goto Truncated
|
||||
}
|
||||
@ -118,6 +120,7 @@ func nextSubpacket(contents []byte) (subHeaderLen int, subPacket *OpaqueSubpacke
|
||||
if len(contents) < subHeaderLen {
|
||||
goto Truncated
|
||||
}
|
||||
encodedLength = contents[0:1]
|
||||
subLen = uint32(contents[0])
|
||||
contents = contents[1:]
|
||||
case contents[0] < 255:
|
||||
@ -125,6 +128,7 @@ func nextSubpacket(contents []byte) (subHeaderLen int, subPacket *OpaqueSubpacke
|
||||
if len(contents) < subHeaderLen {
|
||||
goto Truncated
|
||||
}
|
||||
encodedLength = contents[0:2]
|
||||
subLen = uint32(contents[0]-192)<<8 + uint32(contents[1]) + 192
|
||||
contents = contents[2:]
|
||||
default:
|
||||
@ -132,16 +136,19 @@ func nextSubpacket(contents []byte) (subHeaderLen int, subPacket *OpaqueSubpacke
|
||||
if len(contents) < subHeaderLen {
|
||||
goto Truncated
|
||||
}
|
||||
encodedLength = contents[0:5]
|
||||
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.EncodedLength = encodedLength
|
||||
subPacket.Contents = contents[1:subLen]
|
||||
return
|
||||
Truncated:
|
||||
@ -151,7 +158,9 @@ Truncated:
|
||||
|
||||
func (osp *OpaqueSubpacket) Serialize(w io.Writer) (err error) {
|
||||
buf := make([]byte, 6)
|
||||
n := serializeSubpacketLength(buf, len(osp.Contents)+1)
|
||||
copy(buf, osp.EncodedLength)
|
||||
n := len(osp.EncodedLength)
|
||||
|
||||
buf[n] = osp.SubType
|
||||
if _, err = w.Write(buf[:n+1]); err != nil {
|
||||
return
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user