Compare commits
24 Commits
working-ve
...
master
Author | SHA1 | Date | |
---|---|---|---|
7843062488 | |||
|
3ffa8f032c | ||
|
10665881bc | ||
|
d2bec612a7 | ||
|
832a8568f4 | ||
|
77a9941a0e | ||
|
a3ede7c686 | ||
|
5834e066f3 | ||
|
aadc4f0790 | ||
|
9de60652bf | ||
|
dbde9b3cab | ||
|
df6f5b4973 | ||
|
c78f6aa535 | ||
|
9a090ca397 | ||
|
e231769f84 | ||
|
ec95aba8d2 | ||
|
6d7d83a6ff | ||
|
2cbbc2940d | ||
|
11f3648401 | ||
|
103108cdac | ||
|
dfbcce84ae | ||
|
3871351ace | ||
|
5afa2c0f9a | ||
|
e766f580bb |
37
.github/workflows/go.yml
vendored
Normal file
37
.github/workflows/go.yml
vendored
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
name: Go
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
build:
|
||||||
|
name: Build
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
|
||||||
|
- name: Set up Go 1.12
|
||||||
|
uses: actions/setup-go@v1
|
||||||
|
with:
|
||||||
|
go-version: 1.12
|
||||||
|
id: go
|
||||||
|
|
||||||
|
- name: Setup GOPATH
|
||||||
|
run: mkdir -p /home/runner/go/bin
|
||||||
|
|
||||||
|
- name: Install Go's dep dependency manager
|
||||||
|
run: sudo apt-get install -y go-dep
|
||||||
|
|
||||||
|
- name: Check out code into the Go module directory
|
||||||
|
uses: actions/checkout@v1
|
||||||
|
|
||||||
|
- name: Get dependencies
|
||||||
|
run: |
|
||||||
|
go get -v -t -d ./...
|
||||||
|
if [ -f Gopkg.toml ]; then
|
||||||
|
curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
|
||||||
|
dep ensure
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: go build -v .
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -3,3 +3,4 @@ config.yaml
|
|||||||
vendor/
|
vendor/
|
||||||
*.log
|
*.log
|
||||||
*.tar.gz
|
*.tar.gz
|
||||||
|
*.bak
|
373
LICENSE
Normal file
373
LICENSE
Normal file
@ -0,0 +1,373 @@
|
|||||||
|
Mozilla Public License Version 2.0
|
||||||
|
==================================
|
||||||
|
|
||||||
|
1. Definitions
|
||||||
|
--------------
|
||||||
|
|
||||||
|
1.1. "Contributor"
|
||||||
|
means each individual or legal entity that creates, contributes to
|
||||||
|
the creation of, or owns Covered Software.
|
||||||
|
|
||||||
|
1.2. "Contributor Version"
|
||||||
|
means the combination of the Contributions of others (if any) used
|
||||||
|
by a Contributor and that particular Contributor's Contribution.
|
||||||
|
|
||||||
|
1.3. "Contribution"
|
||||||
|
means Covered Software of a particular Contributor.
|
||||||
|
|
||||||
|
1.4. "Covered Software"
|
||||||
|
means Source Code Form to which the initial Contributor has attached
|
||||||
|
the notice in Exhibit A, the Executable Form of such Source Code
|
||||||
|
Form, and Modifications of such Source Code Form, in each case
|
||||||
|
including portions thereof.
|
||||||
|
|
||||||
|
1.5. "Incompatible With Secondary Licenses"
|
||||||
|
means
|
||||||
|
|
||||||
|
(a) that the initial Contributor has attached the notice described
|
||||||
|
in Exhibit B to the Covered Software; or
|
||||||
|
|
||||||
|
(b) that the Covered Software was made available under the terms of
|
||||||
|
version 1.1 or earlier of the License, but not also under the
|
||||||
|
terms of a Secondary License.
|
||||||
|
|
||||||
|
1.6. "Executable Form"
|
||||||
|
means any form of the work other than Source Code Form.
|
||||||
|
|
||||||
|
1.7. "Larger Work"
|
||||||
|
means a work that combines Covered Software with other material, in
|
||||||
|
a separate file or files, that is not Covered Software.
|
||||||
|
|
||||||
|
1.8. "License"
|
||||||
|
means this document.
|
||||||
|
|
||||||
|
1.9. "Licensable"
|
||||||
|
means having the right to grant, to the maximum extent possible,
|
||||||
|
whether at the time of the initial grant or subsequently, any and
|
||||||
|
all of the rights conveyed by this License.
|
||||||
|
|
||||||
|
1.10. "Modifications"
|
||||||
|
means any of the following:
|
||||||
|
|
||||||
|
(a) any file in Source Code Form that results from an addition to,
|
||||||
|
deletion from, or modification of the contents of Covered
|
||||||
|
Software; or
|
||||||
|
|
||||||
|
(b) any new file in Source Code Form that contains any Covered
|
||||||
|
Software.
|
||||||
|
|
||||||
|
1.11. "Patent Claims" of a Contributor
|
||||||
|
means any patent claim(s), including without limitation, method,
|
||||||
|
process, and apparatus claims, in any patent Licensable by such
|
||||||
|
Contributor that would be infringed, but for the grant of the
|
||||||
|
License, by the making, using, selling, offering for sale, having
|
||||||
|
made, import, or transfer of either its Contributions or its
|
||||||
|
Contributor Version.
|
||||||
|
|
||||||
|
1.12. "Secondary License"
|
||||||
|
means either the GNU General Public License, Version 2.0, the GNU
|
||||||
|
Lesser General Public License, Version 2.1, the GNU Affero General
|
||||||
|
Public License, Version 3.0, or any later versions of those
|
||||||
|
licenses.
|
||||||
|
|
||||||
|
1.13. "Source Code Form"
|
||||||
|
means the form of the work preferred for making modifications.
|
||||||
|
|
||||||
|
1.14. "You" (or "Your")
|
||||||
|
means an individual or a legal entity exercising rights under this
|
||||||
|
License. For legal entities, "You" includes any entity that
|
||||||
|
controls, is controlled by, or is under common control with You. For
|
||||||
|
purposes of this definition, "control" means (a) the power, direct
|
||||||
|
or indirect, to cause the direction or management of such entity,
|
||||||
|
whether by contract or otherwise, or (b) ownership of more than
|
||||||
|
fifty percent (50%) of the outstanding shares or beneficial
|
||||||
|
ownership of such entity.
|
||||||
|
|
||||||
|
2. License Grants and Conditions
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
2.1. Grants
|
||||||
|
|
||||||
|
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||||
|
non-exclusive license:
|
||||||
|
|
||||||
|
(a) under intellectual property rights (other than patent or trademark)
|
||||||
|
Licensable by such Contributor to use, reproduce, make available,
|
||||||
|
modify, display, perform, distribute, and otherwise exploit its
|
||||||
|
Contributions, either on an unmodified basis, with Modifications, or
|
||||||
|
as part of a Larger Work; and
|
||||||
|
|
||||||
|
(b) under Patent Claims of such Contributor to make, use, sell, offer
|
||||||
|
for sale, have made, import, and otherwise transfer either its
|
||||||
|
Contributions or its Contributor Version.
|
||||||
|
|
||||||
|
2.2. Effective Date
|
||||||
|
|
||||||
|
The licenses granted in Section 2.1 with respect to any Contribution
|
||||||
|
become effective for each Contribution on the date the Contributor first
|
||||||
|
distributes such Contribution.
|
||||||
|
|
||||||
|
2.3. Limitations on Grant Scope
|
||||||
|
|
||||||
|
The licenses granted in this Section 2 are the only rights granted under
|
||||||
|
this License. No additional rights or licenses will be implied from the
|
||||||
|
distribution or licensing of Covered Software under this License.
|
||||||
|
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||||
|
Contributor:
|
||||||
|
|
||||||
|
(a) for any code that a Contributor has removed from Covered Software;
|
||||||
|
or
|
||||||
|
|
||||||
|
(b) for infringements caused by: (i) Your and any other third party's
|
||||||
|
modifications of Covered Software, or (ii) the combination of its
|
||||||
|
Contributions with other software (except as part of its Contributor
|
||||||
|
Version); or
|
||||||
|
|
||||||
|
(c) under Patent Claims infringed by Covered Software in the absence of
|
||||||
|
its Contributions.
|
||||||
|
|
||||||
|
This License does not grant any rights in the trademarks, service marks,
|
||||||
|
or logos of any Contributor (except as may be necessary to comply with
|
||||||
|
the notice requirements in Section 3.4).
|
||||||
|
|
||||||
|
2.4. Subsequent Licenses
|
||||||
|
|
||||||
|
No Contributor makes additional grants as a result of Your choice to
|
||||||
|
distribute the Covered Software under a subsequent version of this
|
||||||
|
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||||
|
permitted under the terms of Section 3.3).
|
||||||
|
|
||||||
|
2.5. Representation
|
||||||
|
|
||||||
|
Each Contributor represents that the Contributor believes its
|
||||||
|
Contributions are its original creation(s) or it has sufficient rights
|
||||||
|
to grant the rights to its Contributions conveyed by this License.
|
||||||
|
|
||||||
|
2.6. Fair Use
|
||||||
|
|
||||||
|
This License is not intended to limit any rights You have under
|
||||||
|
applicable copyright doctrines of fair use, fair dealing, or other
|
||||||
|
equivalents.
|
||||||
|
|
||||||
|
2.7. Conditions
|
||||||
|
|
||||||
|
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
|
||||||
|
in Section 2.1.
|
||||||
|
|
||||||
|
3. Responsibilities
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
3.1. Distribution of Source Form
|
||||||
|
|
||||||
|
All distribution of Covered Software in Source Code Form, including any
|
||||||
|
Modifications that You create or to which You contribute, must be under
|
||||||
|
the terms of this License. You must inform recipients that the Source
|
||||||
|
Code Form of the Covered Software is governed by the terms of this
|
||||||
|
License, and how they can obtain a copy of this License. You may not
|
||||||
|
attempt to alter or restrict the recipients' rights in the Source Code
|
||||||
|
Form.
|
||||||
|
|
||||||
|
3.2. Distribution of Executable Form
|
||||||
|
|
||||||
|
If You distribute Covered Software in Executable Form then:
|
||||||
|
|
||||||
|
(a) such Covered Software must also be made available in Source Code
|
||||||
|
Form, as described in Section 3.1, and You must inform recipients of
|
||||||
|
the Executable Form how they can obtain a copy of such Source Code
|
||||||
|
Form by reasonable means in a timely manner, at a charge no more
|
||||||
|
than the cost of distribution to the recipient; and
|
||||||
|
|
||||||
|
(b) You may distribute such Executable Form under the terms of this
|
||||||
|
License, or sublicense it under different terms, provided that the
|
||||||
|
license for the Executable Form does not attempt to limit or alter
|
||||||
|
the recipients' rights in the Source Code Form under this License.
|
||||||
|
|
||||||
|
3.3. Distribution of a Larger Work
|
||||||
|
|
||||||
|
You may create and distribute a Larger Work under terms of Your choice,
|
||||||
|
provided that You also comply with the requirements of this License for
|
||||||
|
the Covered Software. If the Larger Work is a combination of Covered
|
||||||
|
Software with a work governed by one or more Secondary Licenses, and the
|
||||||
|
Covered Software is not Incompatible With Secondary Licenses, this
|
||||||
|
License permits You to additionally distribute such Covered Software
|
||||||
|
under the terms of such Secondary License(s), so that the recipient of
|
||||||
|
the Larger Work may, at their option, further distribute the Covered
|
||||||
|
Software under the terms of either this License or such Secondary
|
||||||
|
License(s).
|
||||||
|
|
||||||
|
3.4. Notices
|
||||||
|
|
||||||
|
You may not remove or alter the substance of any license notices
|
||||||
|
(including copyright notices, patent notices, disclaimers of warranty,
|
||||||
|
or limitations of liability) contained within the Source Code Form of
|
||||||
|
the Covered Software, except that You may alter any license notices to
|
||||||
|
the extent required to remedy known factual inaccuracies.
|
||||||
|
|
||||||
|
3.5. Application of Additional Terms
|
||||||
|
|
||||||
|
You may choose to offer, and to charge a fee for, warranty, support,
|
||||||
|
indemnity or liability obligations to one or more recipients of Covered
|
||||||
|
Software. However, You may do so only on Your own behalf, and not on
|
||||||
|
behalf of any Contributor. You must make it absolutely clear that any
|
||||||
|
such warranty, support, indemnity, or liability obligation is offered by
|
||||||
|
You alone, and You hereby agree to indemnify every Contributor for any
|
||||||
|
liability incurred by such Contributor as a result of warranty, support,
|
||||||
|
indemnity or liability terms You offer. You may include additional
|
||||||
|
disclaimers of warranty and limitations of liability specific to any
|
||||||
|
jurisdiction.
|
||||||
|
|
||||||
|
4. Inability to Comply Due to Statute or Regulation
|
||||||
|
---------------------------------------------------
|
||||||
|
|
||||||
|
If it is impossible for You to comply with any of the terms of this
|
||||||
|
License with respect to some or all of the Covered Software due to
|
||||||
|
statute, judicial order, or regulation then You must: (a) comply with
|
||||||
|
the terms of this License to the maximum extent possible; and (b)
|
||||||
|
describe the limitations and the code they affect. Such description must
|
||||||
|
be placed in a text file included with all distributions of the Covered
|
||||||
|
Software under this License. Except to the extent prohibited by statute
|
||||||
|
or regulation, such description must be sufficiently detailed for a
|
||||||
|
recipient of ordinary skill to be able to understand it.
|
||||||
|
|
||||||
|
5. Termination
|
||||||
|
--------------
|
||||||
|
|
||||||
|
5.1. The rights granted under this License will terminate automatically
|
||||||
|
if You fail to comply with any of its terms. However, if You become
|
||||||
|
compliant, then the rights granted under this License from a particular
|
||||||
|
Contributor are reinstated (a) provisionally, unless and until such
|
||||||
|
Contributor explicitly and finally terminates Your grants, and (b) on an
|
||||||
|
ongoing basis, if such Contributor fails to notify You of the
|
||||||
|
non-compliance by some reasonable means prior to 60 days after You have
|
||||||
|
come back into compliance. Moreover, Your grants from a particular
|
||||||
|
Contributor are reinstated on an ongoing basis if such Contributor
|
||||||
|
notifies You of the non-compliance by some reasonable means, this is the
|
||||||
|
first time You have received notice of non-compliance with this License
|
||||||
|
from such Contributor, and You become compliant prior to 30 days after
|
||||||
|
Your receipt of the notice.
|
||||||
|
|
||||||
|
5.2. If You initiate litigation against any entity by asserting a patent
|
||||||
|
infringement claim (excluding declaratory judgment actions,
|
||||||
|
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||||
|
directly or indirectly infringes any patent, then the rights granted to
|
||||||
|
You by any and all Contributors for the Covered Software under Section
|
||||||
|
2.1 of this License shall terminate.
|
||||||
|
|
||||||
|
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
|
||||||
|
end user license agreements (excluding distributors and resellers) which
|
||||||
|
have been validly granted by You or Your distributors under this License
|
||||||
|
prior to termination shall survive termination.
|
||||||
|
|
||||||
|
************************************************************************
|
||||||
|
* *
|
||||||
|
* 6. Disclaimer of Warranty *
|
||||||
|
* ------------------------- *
|
||||||
|
* *
|
||||||
|
* Covered Software is provided under this License on an "as is" *
|
||||||
|
* basis, without warranty of any kind, either expressed, implied, or *
|
||||||
|
* statutory, including, without limitation, warranties that the *
|
||||||
|
* Covered Software is free of defects, merchantable, fit for a *
|
||||||
|
* particular purpose or non-infringing. The entire risk as to the *
|
||||||
|
* quality and performance of the Covered Software is with You. *
|
||||||
|
* Should any Covered Software prove defective in any respect, You *
|
||||||
|
* (not any Contributor) assume the cost of any necessary servicing, *
|
||||||
|
* repair, or correction. This disclaimer of warranty constitutes an *
|
||||||
|
* essential part of this License. No use of any Covered Software is *
|
||||||
|
* authorized under this License except under this disclaimer. *
|
||||||
|
* *
|
||||||
|
************************************************************************
|
||||||
|
|
||||||
|
************************************************************************
|
||||||
|
* *
|
||||||
|
* 7. Limitation of Liability *
|
||||||
|
* -------------------------- *
|
||||||
|
* *
|
||||||
|
* Under no circumstances and under no legal theory, whether tort *
|
||||||
|
* (including negligence), contract, or otherwise, shall any *
|
||||||
|
* Contributor, or anyone who distributes Covered Software as *
|
||||||
|
* permitted above, be liable to You for any direct, indirect, *
|
||||||
|
* special, incidental, or consequential damages of any character *
|
||||||
|
* including, without limitation, damages for lost profits, loss of *
|
||||||
|
* goodwill, work stoppage, computer failure or malfunction, or any *
|
||||||
|
* and all other commercial damages or losses, even if such party *
|
||||||
|
* shall have been informed of the possibility of such damages. This *
|
||||||
|
* limitation of liability shall not apply to liability for death or *
|
||||||
|
* personal injury resulting from such party's negligence to the *
|
||||||
|
* extent applicable law prohibits such limitation. Some *
|
||||||
|
* jurisdictions do not allow the exclusion or limitation of *
|
||||||
|
* incidental or consequential damages, so this exclusion and *
|
||||||
|
* limitation may not apply to You. *
|
||||||
|
* *
|
||||||
|
************************************************************************
|
||||||
|
|
||||||
|
8. Litigation
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Any litigation relating to this License may be brought only in the
|
||||||
|
courts of a jurisdiction where the defendant maintains its principal
|
||||||
|
place of business and such litigation shall be governed by laws of that
|
||||||
|
jurisdiction, without reference to its conflict-of-law provisions.
|
||||||
|
Nothing in this Section shall prevent a party's ability to bring
|
||||||
|
cross-claims or counter-claims.
|
||||||
|
|
||||||
|
9. Miscellaneous
|
||||||
|
----------------
|
||||||
|
|
||||||
|
This License represents the complete agreement concerning the subject
|
||||||
|
matter hereof. If any provision of this License is held to be
|
||||||
|
unenforceable, such provision shall be reformed only to the extent
|
||||||
|
necessary to make it enforceable. Any law or regulation which provides
|
||||||
|
that the language of a contract shall be construed against the drafter
|
||||||
|
shall not be used to construe this License against a Contributor.
|
||||||
|
|
||||||
|
10. Versions of the License
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
10.1. New Versions
|
||||||
|
|
||||||
|
Mozilla Foundation is the license steward. Except as provided in Section
|
||||||
|
10.3, no one other than the license steward has the right to modify or
|
||||||
|
publish new versions of this License. Each version will be given a
|
||||||
|
distinguishing version number.
|
||||||
|
|
||||||
|
10.2. Effect of New Versions
|
||||||
|
|
||||||
|
You may distribute the Covered Software under the terms of the version
|
||||||
|
of the License under which You originally received the Covered Software,
|
||||||
|
or under the terms of any subsequent version published by the license
|
||||||
|
steward.
|
||||||
|
|
||||||
|
10.3. Modified Versions
|
||||||
|
|
||||||
|
If you create software not governed by this License, and you want to
|
||||||
|
create a new license for such software, you may create and use a
|
||||||
|
modified version of this License if you rename the license and remove
|
||||||
|
any references to the name of the license steward (except to note that
|
||||||
|
such modified license differs from this License).
|
||||||
|
|
||||||
|
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||||
|
Licenses
|
||||||
|
|
||||||
|
If You choose to distribute Source Code Form that is Incompatible With
|
||||||
|
Secondary Licenses under the terms of this version of the License, the
|
||||||
|
notice described in Exhibit B of this License must be attached.
|
||||||
|
|
||||||
|
Exhibit A - Source Code Form License Notice
|
||||||
|
-------------------------------------------
|
||||||
|
|
||||||
|
This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
If it is not possible or desirable to put the notice in a particular
|
||||||
|
file, then You may include the notice in a location (such as a LICENSE
|
||||||
|
file in a relevant directory) where a recipient would be likely to look
|
||||||
|
for such a notice.
|
||||||
|
|
||||||
|
You may add additional accurate notices of copyright ownership.
|
||||||
|
|
||||||
|
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||||
|
---------------------------------------------------------
|
||||||
|
|
||||||
|
This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||||
|
defined by the Mozilla Public License, v. 2.0.
|
41
README.md
Normal file
41
README.md
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
# logman
|
||||||
|
|
||||||
|
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fwymillerlinux%2Flogman.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Fwymillerlinux%2Flogman?ref=badge_shield)
|
||||||
|
|
||||||
|
Collecting log files for the greater good!
|
||||||
|
|
||||||
|
This program lets you grab log files remotely and store them up into a compressed file on your local machine!
|
||||||
|
|
||||||
|
In all reality, you can literally grab any file you wish to grab of any remote machine.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
If you have Go installed, use `go get` for grabbing this repo:
|
||||||
|
|
||||||
|
`go get github.com/wymillerlinux/logman`
|
||||||
|
|
||||||
|
If you don't have Go installed, I will provide binaries soon.
|
||||||
|
|
||||||
|
## Running
|
||||||
|
|
||||||
|
Before you start the program, I would like to highlight the attraction to said program.
|
||||||
|
The configuration file, `config.yaml`, is where you set everything about where you want
|
||||||
|
to grab logs from.
|
||||||
|
|
||||||
|
To run the `logman` program:
|
||||||
|
|
||||||
|
`go run .` in the root directory of the project.
|
||||||
|
|
||||||
|
To build the `logman` program:
|
||||||
|
|
||||||
|
`go build .` and then a binary will appear in the `bin` directory of your `$GOPATH`.
|
||||||
|
|
||||||
|
After that, just run the binary and you should be golden.
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
The GitHub issue board is where I post issues with the program. If you any issue with the program, please post it there. Go panics are a great example of an issue you can post.
|
||||||
|
|
||||||
|
I'm new to Go, so forgive the long wait time for any bux fix.
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
If you would like to contribute, feel free to email me or send in pull requests. `todo.md` should have some things to get you rolling. There's quite a few items on there that I want added to make `logman` a finished product.
|
@ -11,6 +11,7 @@ type Configuration struct {
|
|||||||
Password string
|
Password string
|
||||||
Port int
|
Port int
|
||||||
Hosts []string
|
Hosts []string
|
||||||
|
Logs []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func initializeConfig(filename string) Configuration {
|
func initializeConfig(filename string) Configuration {
|
||||||
|
58
generate.go
58
generate.go
@ -1,5 +1,61 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
// this file is for generating the config if it doesn't exist
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// this file is for generating the config if it doesn't exist, mainly for the idiots like me :)
|
||||||
// this is not really a priority right now so it sitting in the backburner as you read this
|
// this is not really a priority right now so it sitting in the backburner as you read this
|
||||||
// signed Wyatt J. Miller, the awesome guy who doesn't generate configs *thumbs up*
|
// signed Wyatt J. Miller, the awesome guy who doesn't generate configs *thumbs up*
|
||||||
|
|
||||||
|
var config string = "config.yaml"
|
||||||
|
|
||||||
|
func doesConfigExist() bool {
|
||||||
|
_, err := os.Stat(config)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func createTemplateConfig(result bool) {
|
||||||
|
if result == false {
|
||||||
|
os.Create(config)
|
||||||
|
} else {
|
||||||
|
fmt.Println("Configuration file already created")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeTemplateConfig(filename string) {
|
||||||
|
hosts := make([]string, 1)
|
||||||
|
logs := make([]string, 1)
|
||||||
|
|
||||||
|
config := Configuration{
|
||||||
|
"jbob",
|
||||||
|
"jbobisawesome",
|
||||||
|
22,
|
||||||
|
hosts,
|
||||||
|
logs,
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := yaml.Marshal(&config)
|
||||||
|
|
||||||
|
fmt.Printf(string(data))
|
||||||
|
_ = ioutil.WriteFile(filename, data, 0600)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Errorf("Couldn't create the configuration file", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Template for logman's configuration complete!")
|
||||||
|
fmt.Println("")
|
||||||
|
fmt.Println("Fill in the necessary credentials you need. If")
|
||||||
|
fmt.Println("you need assitance, check out the wiki for more.")
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
7
main.go
7
main.go
@ -3,6 +3,13 @@ package main
|
|||||||
import "log"
|
import "log"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
isCreated := doesConfigExist()
|
||||||
|
|
||||||
|
if isCreated == false {
|
||||||
|
createTemplateConfig(isCreated)
|
||||||
|
writeTemplateConfig("config.yaml")
|
||||||
|
}
|
||||||
|
|
||||||
config := initializeConfig("config.yaml")
|
config := initializeConfig("config.yaml")
|
||||||
sshConn, sshConfig := initializeConnection(config)
|
sshConn, sshConfig := initializeConnection(config)
|
||||||
clientConns := sshConn.dialConnection(sshConfig)
|
clientConns := sshConn.dialConnection(sshConfig)
|
||||||
|
28
sftp.go
28
sftp.go
@ -8,36 +8,40 @@ import (
|
|||||||
"golang.org/x/crypto/ssh"
|
"golang.org/x/crypto/ssh"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
func (s SSHConnection) getFile(client *ssh.Client) []*os.File {
|
||||||
dstPath string = "/home/wyatt/"
|
homedir, _ := os.UserHomeDir()
|
||||||
srcPath string = "/var/log/"
|
var dstFiles []*os.File
|
||||||
filename string = "dpkg.log"
|
|
||||||
)
|
|
||||||
|
|
||||||
func getFile(client *ssh.Client) {
|
for _, j := range s.Logs {
|
||||||
sftp, err := sftp.NewClient(client)
|
sftp, err := sftp.NewClient(client)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Errorf("FUCK")
|
fmt.Errorf("Error")
|
||||||
}
|
}
|
||||||
|
|
||||||
defer sftp.Close()
|
defer sftp.Close()
|
||||||
|
|
||||||
srcFile, err := sftp.Open(srcPath + filename)
|
srcFile, err := sftp.Open(j)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Errorf("FUCK")
|
fmt.Errorf("Error")
|
||||||
}
|
}
|
||||||
|
|
||||||
defer srcFile.Close()
|
defer srcFile.Close()
|
||||||
|
|
||||||
dstFile, err := os.Create(dstPath + filename)
|
h := slashSeperator(j)
|
||||||
|
|
||||||
|
dstFile, err := os.Create(homedir + "/" + h)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Errorf("FUCK")
|
fmt.Errorf("Error")
|
||||||
}
|
}
|
||||||
|
|
||||||
defer dstFile.Close()
|
defer dstFile.Close()
|
||||||
|
|
||||||
srcFile.WriteTo(dstFile)
|
srcFile.WriteTo(dstFile)
|
||||||
|
|
||||||
|
dstFiles = append(dstFiles, dstFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
return dstFiles
|
||||||
}
|
}
|
||||||
|
18
ssh.go
18
ssh.go
@ -2,6 +2,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
"golang.org/x/crypto/ssh"
|
"golang.org/x/crypto/ssh"
|
||||||
)
|
)
|
||||||
@ -17,6 +18,7 @@ type SSHConnection struct {
|
|||||||
Password string
|
Password string
|
||||||
Port int
|
Port int
|
||||||
Hosts []string
|
Hosts []string
|
||||||
|
Logs []string
|
||||||
}
|
}
|
||||||
|
|
||||||
type SSHClients []*ssh.Client
|
type SSHClients []*ssh.Client
|
||||||
@ -38,6 +40,7 @@ func initializeConnection(config Configuration) (*SSHConnection, *ssh.ClientConf
|
|||||||
Password: config.Password,
|
Password: config.Password,
|
||||||
Port: config.Port,
|
Port: config.Port,
|
||||||
Hosts: config.Hosts,
|
Hosts: config.Hosts,
|
||||||
|
Logs: config.Logs,
|
||||||
}
|
}
|
||||||
|
|
||||||
sshConfig := &ssh.ClientConfig{
|
sshConfig := &ssh.ClientConfig{
|
||||||
@ -91,22 +94,19 @@ func (s SSHConnection) openSession(client SSHClients) SSHSessions {
|
|||||||
func (s SSHConnection) executeSFTP(execute SSHClients) SSHSFTP {
|
func (s SSHConnection) executeSFTP(execute SSHClients) SSHSFTP {
|
||||||
// execute order 66 lol
|
// execute order 66 lol
|
||||||
sftp := SSHSFTP{}
|
sftp := SSHSFTP{}
|
||||||
|
homedir, _ := os.UserHomeDir()
|
||||||
|
|
||||||
for _, j := range execute {
|
for _, j := range execute {
|
||||||
// TODO: this is just a placeholder, change to the actual tarring executable
|
slashed := s.getFile(j)
|
||||||
getFile(j)
|
for _, k := range slashed {
|
||||||
|
name := osfileToSting(k)
|
||||||
err := gzipit("/home/wyatt/"+filename, ".")
|
err := gzipit(homedir+"/"+name, ".")
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Errorf("Cannot gzip file(s)", err)
|
fmt.Errorf("Cannot gzip file(s)", err)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return sftp
|
return sftp
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s SSHConnection) gzipItUp() {
|
|
||||||
// TODO: placeholder function??
|
|
||||||
}
|
|
||||||
|
28
string.go
28
string.go
@ -1,7 +1,33 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import "time"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
func timeToString(currentTime time.Time) string {
|
func timeToString(currentTime time.Time) string {
|
||||||
return currentTime.String()
|
return currentTime.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func osfileToSting(currentOsFile *os.File) string {
|
||||||
|
file, err := os.Open(currentOsFile.Name())
|
||||||
|
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
fileinfo, err := file.Stat()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Heyo, there's no file here!\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
name := fileinfo.Name()
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
|
func slashSeperator(unslashed string) string {
|
||||||
|
s := unslashed
|
||||||
|
_, file := filepath.Split(s)
|
||||||
|
return file
|
||||||
|
}
|
||||||
|
7
todo.md
Normal file
7
todo.md
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
## Things I got to do for the project
|
||||||
|
- Have config file dictate what log file/directory you want
|
||||||
|
- Allow having SSH keys and passwordless SSH sessions, along with having bypassing keys altogether
|
||||||
|
- Allow fetching of multiple log files (fields under the defined host? Seperate key/field? Dynamic?)
|
||||||
|
- Allow different machines to collect different log files
|
||||||
|
- Allow to gather directories of log files
|
||||||
|
- Develop a log getting logs for sanity
|
3
vendor/golang.org/x/crypto/AUTHORS
generated
vendored
3
vendor/golang.org/x/crypto/AUTHORS
generated
vendored
@ -1,3 +0,0 @@
|
|||||||
# This source code refers to The Go Authors for copyright purposes.
|
|
||||||
# The master list of authors is in the main Go distribution,
|
|
||||||
# visible at https://tip.golang.org/AUTHORS.
|
|
3
vendor/golang.org/x/crypto/CONTRIBUTORS
generated
vendored
3
vendor/golang.org/x/crypto/CONTRIBUTORS
generated
vendored
@ -1,3 +0,0 @@
|
|||||||
# This source code was written by the Go contributors.
|
|
||||||
# The master list of contributors is in the main Go distribution,
|
|
||||||
# visible at https://tip.golang.org/CONTRIBUTORS.
|
|
27
vendor/golang.org/x/crypto/LICENSE
generated
vendored
27
vendor/golang.org/x/crypto/LICENSE
generated
vendored
@ -1,27 +0,0 @@
|
|||||||
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/golang.org/x/crypto/PATENTS
generated
vendored
22
vendor/golang.org/x/crypto/PATENTS
generated
vendored
@ -1,22 +0,0 @@
|
|||||||
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.
|
|
8
vendor/golang.org/x/crypto/curve25519/const_amd64.h
generated
vendored
8
vendor/golang.org/x/crypto/curve25519/const_amd64.h
generated
vendored
@ -1,8 +0,0 @@
|
|||||||
// 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.
|
|
||||||
|
|
||||||
// This code was translated into a form compatible with 6a from the public
|
|
||||||
// domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html
|
|
||||||
|
|
||||||
#define REDMASK51 0x0007FFFFFFFFFFFF
|
|
20
vendor/golang.org/x/crypto/curve25519/const_amd64.s
generated
vendored
20
vendor/golang.org/x/crypto/curve25519/const_amd64.s
generated
vendored
@ -1,20 +0,0 @@
|
|||||||
// 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.
|
|
||||||
|
|
||||||
// This code was translated into a form compatible with 6a from the public
|
|
||||||
// domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html
|
|
||||||
|
|
||||||
// +build amd64,!gccgo,!appengine
|
|
||||||
|
|
||||||
// These constants cannot be encoded in non-MOVQ immediates.
|
|
||||||
// We access them directly from memory instead.
|
|
||||||
|
|
||||||
DATA ·_121666_213(SB)/8, $996687872
|
|
||||||
GLOBL ·_121666_213(SB), 8, $8
|
|
||||||
|
|
||||||
DATA ·_2P0(SB)/8, $0xFFFFFFFFFFFDA
|
|
||||||
GLOBL ·_2P0(SB), 8, $8
|
|
||||||
|
|
||||||
DATA ·_2P1234(SB)/8, $0xFFFFFFFFFFFFE
|
|
||||||
GLOBL ·_2P1234(SB), 8, $8
|
|
65
vendor/golang.org/x/crypto/curve25519/cswap_amd64.s
generated
vendored
65
vendor/golang.org/x/crypto/curve25519/cswap_amd64.s
generated
vendored
@ -1,65 +0,0 @@
|
|||||||
// 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.
|
|
||||||
|
|
||||||
// +build amd64,!gccgo,!appengine
|
|
||||||
|
|
||||||
// func cswap(inout *[4][5]uint64, v uint64)
|
|
||||||
TEXT ·cswap(SB),7,$0
|
|
||||||
MOVQ inout+0(FP),DI
|
|
||||||
MOVQ v+8(FP),SI
|
|
||||||
|
|
||||||
SUBQ $1, SI
|
|
||||||
NOTQ SI
|
|
||||||
MOVQ SI, X15
|
|
||||||
PSHUFD $0x44, X15, X15
|
|
||||||
|
|
||||||
MOVOU 0(DI), X0
|
|
||||||
MOVOU 16(DI), X2
|
|
||||||
MOVOU 32(DI), X4
|
|
||||||
MOVOU 48(DI), X6
|
|
||||||
MOVOU 64(DI), X8
|
|
||||||
MOVOU 80(DI), X1
|
|
||||||
MOVOU 96(DI), X3
|
|
||||||
MOVOU 112(DI), X5
|
|
||||||
MOVOU 128(DI), X7
|
|
||||||
MOVOU 144(DI), X9
|
|
||||||
|
|
||||||
MOVO X1, X10
|
|
||||||
MOVO X3, X11
|
|
||||||
MOVO X5, X12
|
|
||||||
MOVO X7, X13
|
|
||||||
MOVO X9, X14
|
|
||||||
|
|
||||||
PXOR X0, X10
|
|
||||||
PXOR X2, X11
|
|
||||||
PXOR X4, X12
|
|
||||||
PXOR X6, X13
|
|
||||||
PXOR X8, X14
|
|
||||||
PAND X15, X10
|
|
||||||
PAND X15, X11
|
|
||||||
PAND X15, X12
|
|
||||||
PAND X15, X13
|
|
||||||
PAND X15, X14
|
|
||||||
PXOR X10, X0
|
|
||||||
PXOR X10, X1
|
|
||||||
PXOR X11, X2
|
|
||||||
PXOR X11, X3
|
|
||||||
PXOR X12, X4
|
|
||||||
PXOR X12, X5
|
|
||||||
PXOR X13, X6
|
|
||||||
PXOR X13, X7
|
|
||||||
PXOR X14, X8
|
|
||||||
PXOR X14, X9
|
|
||||||
|
|
||||||
MOVOU X0, 0(DI)
|
|
||||||
MOVOU X2, 16(DI)
|
|
||||||
MOVOU X4, 32(DI)
|
|
||||||
MOVOU X6, 48(DI)
|
|
||||||
MOVOU X8, 64(DI)
|
|
||||||
MOVOU X1, 80(DI)
|
|
||||||
MOVOU X3, 96(DI)
|
|
||||||
MOVOU X5, 112(DI)
|
|
||||||
MOVOU X7, 128(DI)
|
|
||||||
MOVOU X9, 144(DI)
|
|
||||||
RET
|
|
834
vendor/golang.org/x/crypto/curve25519/curve25519.go
generated
vendored
834
vendor/golang.org/x/crypto/curve25519/curve25519.go
generated
vendored
@ -1,834 +0,0 @@
|
|||||||
// Copyright 2013 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// We have an implementation in amd64 assembly so this code is only run on
|
|
||||||
// non-amd64 platforms. The amd64 assembly does not support gccgo.
|
|
||||||
// +build !amd64 gccgo appengine
|
|
||||||
|
|
||||||
package curve25519
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/binary"
|
|
||||||
)
|
|
||||||
|
|
||||||
// This code is a port of the public domain, "ref10" implementation of
|
|
||||||
// curve25519 from SUPERCOP 20130419 by D. J. Bernstein.
|
|
||||||
|
|
||||||
// fieldElement represents an element of the field GF(2^255 - 19). An element
|
|
||||||
// t, entries t[0]...t[9], represents the integer t[0]+2^26 t[1]+2^51 t[2]+2^77
|
|
||||||
// t[3]+2^102 t[4]+...+2^230 t[9]. Bounds on each t[i] vary depending on
|
|
||||||
// context.
|
|
||||||
type fieldElement [10]int32
|
|
||||||
|
|
||||||
func feZero(fe *fieldElement) {
|
|
||||||
for i := range fe {
|
|
||||||
fe[i] = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func feOne(fe *fieldElement) {
|
|
||||||
feZero(fe)
|
|
||||||
fe[0] = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
func feAdd(dst, a, b *fieldElement) {
|
|
||||||
for i := range dst {
|
|
||||||
dst[i] = a[i] + b[i]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func feSub(dst, a, b *fieldElement) {
|
|
||||||
for i := range dst {
|
|
||||||
dst[i] = a[i] - b[i]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func feCopy(dst, src *fieldElement) {
|
|
||||||
for i := range dst {
|
|
||||||
dst[i] = src[i]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// feCSwap replaces (f,g) with (g,f) if b == 1; replaces (f,g) with (f,g) if b == 0.
|
|
||||||
//
|
|
||||||
// Preconditions: b in {0,1}.
|
|
||||||
func feCSwap(f, g *fieldElement, b int32) {
|
|
||||||
b = -b
|
|
||||||
for i := range f {
|
|
||||||
t := b & (f[i] ^ g[i])
|
|
||||||
f[i] ^= t
|
|
||||||
g[i] ^= t
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// load3 reads a 24-bit, little-endian value from in.
|
|
||||||
func load3(in []byte) int64 {
|
|
||||||
var r int64
|
|
||||||
r = int64(in[0])
|
|
||||||
r |= int64(in[1]) << 8
|
|
||||||
r |= int64(in[2]) << 16
|
|
||||||
return r
|
|
||||||
}
|
|
||||||
|
|
||||||
// load4 reads a 32-bit, little-endian value from in.
|
|
||||||
func load4(in []byte) int64 {
|
|
||||||
return int64(binary.LittleEndian.Uint32(in))
|
|
||||||
}
|
|
||||||
|
|
||||||
func feFromBytes(dst *fieldElement, src *[32]byte) {
|
|
||||||
h0 := load4(src[:])
|
|
||||||
h1 := load3(src[4:]) << 6
|
|
||||||
h2 := load3(src[7:]) << 5
|
|
||||||
h3 := load3(src[10:]) << 3
|
|
||||||
h4 := load3(src[13:]) << 2
|
|
||||||
h5 := load4(src[16:])
|
|
||||||
h6 := load3(src[20:]) << 7
|
|
||||||
h7 := load3(src[23:]) << 5
|
|
||||||
h8 := load3(src[26:]) << 4
|
|
||||||
h9 := (load3(src[29:]) & 0x7fffff) << 2
|
|
||||||
|
|
||||||
var carry [10]int64
|
|
||||||
carry[9] = (h9 + 1<<24) >> 25
|
|
||||||
h0 += carry[9] * 19
|
|
||||||
h9 -= carry[9] << 25
|
|
||||||
carry[1] = (h1 + 1<<24) >> 25
|
|
||||||
h2 += carry[1]
|
|
||||||
h1 -= carry[1] << 25
|
|
||||||
carry[3] = (h3 + 1<<24) >> 25
|
|
||||||
h4 += carry[3]
|
|
||||||
h3 -= carry[3] << 25
|
|
||||||
carry[5] = (h5 + 1<<24) >> 25
|
|
||||||
h6 += carry[5]
|
|
||||||
h5 -= carry[5] << 25
|
|
||||||
carry[7] = (h7 + 1<<24) >> 25
|
|
||||||
h8 += carry[7]
|
|
||||||
h7 -= carry[7] << 25
|
|
||||||
|
|
||||||
carry[0] = (h0 + 1<<25) >> 26
|
|
||||||
h1 += carry[0]
|
|
||||||
h0 -= carry[0] << 26
|
|
||||||
carry[2] = (h2 + 1<<25) >> 26
|
|
||||||
h3 += carry[2]
|
|
||||||
h2 -= carry[2] << 26
|
|
||||||
carry[4] = (h4 + 1<<25) >> 26
|
|
||||||
h5 += carry[4]
|
|
||||||
h4 -= carry[4] << 26
|
|
||||||
carry[6] = (h6 + 1<<25) >> 26
|
|
||||||
h7 += carry[6]
|
|
||||||
h6 -= carry[6] << 26
|
|
||||||
carry[8] = (h8 + 1<<25) >> 26
|
|
||||||
h9 += carry[8]
|
|
||||||
h8 -= carry[8] << 26
|
|
||||||
|
|
||||||
dst[0] = int32(h0)
|
|
||||||
dst[1] = int32(h1)
|
|
||||||
dst[2] = int32(h2)
|
|
||||||
dst[3] = int32(h3)
|
|
||||||
dst[4] = int32(h4)
|
|
||||||
dst[5] = int32(h5)
|
|
||||||
dst[6] = int32(h6)
|
|
||||||
dst[7] = int32(h7)
|
|
||||||
dst[8] = int32(h8)
|
|
||||||
dst[9] = int32(h9)
|
|
||||||
}
|
|
||||||
|
|
||||||
// feToBytes marshals h to s.
|
|
||||||
// Preconditions:
|
|
||||||
// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
|
|
||||||
//
|
|
||||||
// Write p=2^255-19; q=floor(h/p).
|
|
||||||
// Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))).
|
|
||||||
//
|
|
||||||
// Proof:
|
|
||||||
// Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4.
|
|
||||||
// Also have |h-2^230 h9|<2^230 so |19 2^(-255)(h-2^230 h9)|<1/4.
|
|
||||||
//
|
|
||||||
// Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9).
|
|
||||||
// Then 0<y<1.
|
|
||||||
//
|
|
||||||
// Write r=h-pq.
|
|
||||||
// Have 0<=r<=p-1=2^255-20.
|
|
||||||
// Thus 0<=r+19(2^-255)r<r+19(2^-255)2^255<=2^255-1.
|
|
||||||
//
|
|
||||||
// Write x=r+19(2^-255)r+y.
|
|
||||||
// Then 0<x<2^255 so floor(2^(-255)x) = 0 so floor(q+2^(-255)x) = q.
|
|
||||||
//
|
|
||||||
// Have q+2^(-255)x = 2^(-255)(h + 19 2^(-25) h9 + 2^(-1))
|
|
||||||
// so floor(2^(-255)(h + 19 2^(-25) h9 + 2^(-1))) = q.
|
|
||||||
func feToBytes(s *[32]byte, h *fieldElement) {
|
|
||||||
var carry [10]int32
|
|
||||||
|
|
||||||
q := (19*h[9] + (1 << 24)) >> 25
|
|
||||||
q = (h[0] + q) >> 26
|
|
||||||
q = (h[1] + q) >> 25
|
|
||||||
q = (h[2] + q) >> 26
|
|
||||||
q = (h[3] + q) >> 25
|
|
||||||
q = (h[4] + q) >> 26
|
|
||||||
q = (h[5] + q) >> 25
|
|
||||||
q = (h[6] + q) >> 26
|
|
||||||
q = (h[7] + q) >> 25
|
|
||||||
q = (h[8] + q) >> 26
|
|
||||||
q = (h[9] + q) >> 25
|
|
||||||
|
|
||||||
// Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20.
|
|
||||||
h[0] += 19 * q
|
|
||||||
// Goal: Output h-2^255 q, which is between 0 and 2^255-20.
|
|
||||||
|
|
||||||
carry[0] = h[0] >> 26
|
|
||||||
h[1] += carry[0]
|
|
||||||
h[0] -= carry[0] << 26
|
|
||||||
carry[1] = h[1] >> 25
|
|
||||||
h[2] += carry[1]
|
|
||||||
h[1] -= carry[1] << 25
|
|
||||||
carry[2] = h[2] >> 26
|
|
||||||
h[3] += carry[2]
|
|
||||||
h[2] -= carry[2] << 26
|
|
||||||
carry[3] = h[3] >> 25
|
|
||||||
h[4] += carry[3]
|
|
||||||
h[3] -= carry[3] << 25
|
|
||||||
carry[4] = h[4] >> 26
|
|
||||||
h[5] += carry[4]
|
|
||||||
h[4] -= carry[4] << 26
|
|
||||||
carry[5] = h[5] >> 25
|
|
||||||
h[6] += carry[5]
|
|
||||||
h[5] -= carry[5] << 25
|
|
||||||
carry[6] = h[6] >> 26
|
|
||||||
h[7] += carry[6]
|
|
||||||
h[6] -= carry[6] << 26
|
|
||||||
carry[7] = h[7] >> 25
|
|
||||||
h[8] += carry[7]
|
|
||||||
h[7] -= carry[7] << 25
|
|
||||||
carry[8] = h[8] >> 26
|
|
||||||
h[9] += carry[8]
|
|
||||||
h[8] -= carry[8] << 26
|
|
||||||
carry[9] = h[9] >> 25
|
|
||||||
h[9] -= carry[9] << 25
|
|
||||||
// h10 = carry9
|
|
||||||
|
|
||||||
// Goal: Output h[0]+...+2^255 h10-2^255 q, which is between 0 and 2^255-20.
|
|
||||||
// Have h[0]+...+2^230 h[9] between 0 and 2^255-1;
|
|
||||||
// evidently 2^255 h10-2^255 q = 0.
|
|
||||||
// Goal: Output h[0]+...+2^230 h[9].
|
|
||||||
|
|
||||||
s[0] = byte(h[0] >> 0)
|
|
||||||
s[1] = byte(h[0] >> 8)
|
|
||||||
s[2] = byte(h[0] >> 16)
|
|
||||||
s[3] = byte((h[0] >> 24) | (h[1] << 2))
|
|
||||||
s[4] = byte(h[1] >> 6)
|
|
||||||
s[5] = byte(h[1] >> 14)
|
|
||||||
s[6] = byte((h[1] >> 22) | (h[2] << 3))
|
|
||||||
s[7] = byte(h[2] >> 5)
|
|
||||||
s[8] = byte(h[2] >> 13)
|
|
||||||
s[9] = byte((h[2] >> 21) | (h[3] << 5))
|
|
||||||
s[10] = byte(h[3] >> 3)
|
|
||||||
s[11] = byte(h[3] >> 11)
|
|
||||||
s[12] = byte((h[3] >> 19) | (h[4] << 6))
|
|
||||||
s[13] = byte(h[4] >> 2)
|
|
||||||
s[14] = byte(h[4] >> 10)
|
|
||||||
s[15] = byte(h[4] >> 18)
|
|
||||||
s[16] = byte(h[5] >> 0)
|
|
||||||
s[17] = byte(h[5] >> 8)
|
|
||||||
s[18] = byte(h[5] >> 16)
|
|
||||||
s[19] = byte((h[5] >> 24) | (h[6] << 1))
|
|
||||||
s[20] = byte(h[6] >> 7)
|
|
||||||
s[21] = byte(h[6] >> 15)
|
|
||||||
s[22] = byte((h[6] >> 23) | (h[7] << 3))
|
|
||||||
s[23] = byte(h[7] >> 5)
|
|
||||||
s[24] = byte(h[7] >> 13)
|
|
||||||
s[25] = byte((h[7] >> 21) | (h[8] << 4))
|
|
||||||
s[26] = byte(h[8] >> 4)
|
|
||||||
s[27] = byte(h[8] >> 12)
|
|
||||||
s[28] = byte((h[8] >> 20) | (h[9] << 6))
|
|
||||||
s[29] = byte(h[9] >> 2)
|
|
||||||
s[30] = byte(h[9] >> 10)
|
|
||||||
s[31] = byte(h[9] >> 18)
|
|
||||||
}
|
|
||||||
|
|
||||||
// feMul calculates h = f * g
|
|
||||||
// Can overlap h with f or g.
|
|
||||||
//
|
|
||||||
// Preconditions:
|
|
||||||
// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
|
|
||||||
// |g| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
|
|
||||||
//
|
|
||||||
// Postconditions:
|
|
||||||
// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
|
|
||||||
//
|
|
||||||
// Notes on implementation strategy:
|
|
||||||
//
|
|
||||||
// Using schoolbook multiplication.
|
|
||||||
// Karatsuba would save a little in some cost models.
|
|
||||||
//
|
|
||||||
// Most multiplications by 2 and 19 are 32-bit precomputations;
|
|
||||||
// cheaper than 64-bit postcomputations.
|
|
||||||
//
|
|
||||||
// There is one remaining multiplication by 19 in the carry chain;
|
|
||||||
// one *19 precomputation can be merged into this,
|
|
||||||
// but the resulting data flow is considerably less clean.
|
|
||||||
//
|
|
||||||
// There are 12 carries below.
|
|
||||||
// 10 of them are 2-way parallelizable and vectorizable.
|
|
||||||
// Can get away with 11 carries, but then data flow is much deeper.
|
|
||||||
//
|
|
||||||
// With tighter constraints on inputs can squeeze carries into int32.
|
|
||||||
func feMul(h, f, g *fieldElement) {
|
|
||||||
f0 := f[0]
|
|
||||||
f1 := f[1]
|
|
||||||
f2 := f[2]
|
|
||||||
f3 := f[3]
|
|
||||||
f4 := f[4]
|
|
||||||
f5 := f[5]
|
|
||||||
f6 := f[6]
|
|
||||||
f7 := f[7]
|
|
||||||
f8 := f[8]
|
|
||||||
f9 := f[9]
|
|
||||||
g0 := g[0]
|
|
||||||
g1 := g[1]
|
|
||||||
g2 := g[2]
|
|
||||||
g3 := g[3]
|
|
||||||
g4 := g[4]
|
|
||||||
g5 := g[5]
|
|
||||||
g6 := g[6]
|
|
||||||
g7 := g[7]
|
|
||||||
g8 := g[8]
|
|
||||||
g9 := g[9]
|
|
||||||
g1_19 := 19 * g1 // 1.4*2^29
|
|
||||||
g2_19 := 19 * g2 // 1.4*2^30; still ok
|
|
||||||
g3_19 := 19 * g3
|
|
||||||
g4_19 := 19 * g4
|
|
||||||
g5_19 := 19 * g5
|
|
||||||
g6_19 := 19 * g6
|
|
||||||
g7_19 := 19 * g7
|
|
||||||
g8_19 := 19 * g8
|
|
||||||
g9_19 := 19 * g9
|
|
||||||
f1_2 := 2 * f1
|
|
||||||
f3_2 := 2 * f3
|
|
||||||
f5_2 := 2 * f5
|
|
||||||
f7_2 := 2 * f7
|
|
||||||
f9_2 := 2 * f9
|
|
||||||
f0g0 := int64(f0) * int64(g0)
|
|
||||||
f0g1 := int64(f0) * int64(g1)
|
|
||||||
f0g2 := int64(f0) * int64(g2)
|
|
||||||
f0g3 := int64(f0) * int64(g3)
|
|
||||||
f0g4 := int64(f0) * int64(g4)
|
|
||||||
f0g5 := int64(f0) * int64(g5)
|
|
||||||
f0g6 := int64(f0) * int64(g6)
|
|
||||||
f0g7 := int64(f0) * int64(g7)
|
|
||||||
f0g8 := int64(f0) * int64(g8)
|
|
||||||
f0g9 := int64(f0) * int64(g9)
|
|
||||||
f1g0 := int64(f1) * int64(g0)
|
|
||||||
f1g1_2 := int64(f1_2) * int64(g1)
|
|
||||||
f1g2 := int64(f1) * int64(g2)
|
|
||||||
f1g3_2 := int64(f1_2) * int64(g3)
|
|
||||||
f1g4 := int64(f1) * int64(g4)
|
|
||||||
f1g5_2 := int64(f1_2) * int64(g5)
|
|
||||||
f1g6 := int64(f1) * int64(g6)
|
|
||||||
f1g7_2 := int64(f1_2) * int64(g7)
|
|
||||||
f1g8 := int64(f1) * int64(g8)
|
|
||||||
f1g9_38 := int64(f1_2) * int64(g9_19)
|
|
||||||
f2g0 := int64(f2) * int64(g0)
|
|
||||||
f2g1 := int64(f2) * int64(g1)
|
|
||||||
f2g2 := int64(f2) * int64(g2)
|
|
||||||
f2g3 := int64(f2) * int64(g3)
|
|
||||||
f2g4 := int64(f2) * int64(g4)
|
|
||||||
f2g5 := int64(f2) * int64(g5)
|
|
||||||
f2g6 := int64(f2) * int64(g6)
|
|
||||||
f2g7 := int64(f2) * int64(g7)
|
|
||||||
f2g8_19 := int64(f2) * int64(g8_19)
|
|
||||||
f2g9_19 := int64(f2) * int64(g9_19)
|
|
||||||
f3g0 := int64(f3) * int64(g0)
|
|
||||||
f3g1_2 := int64(f3_2) * int64(g1)
|
|
||||||
f3g2 := int64(f3) * int64(g2)
|
|
||||||
f3g3_2 := int64(f3_2) * int64(g3)
|
|
||||||
f3g4 := int64(f3) * int64(g4)
|
|
||||||
f3g5_2 := int64(f3_2) * int64(g5)
|
|
||||||
f3g6 := int64(f3) * int64(g6)
|
|
||||||
f3g7_38 := int64(f3_2) * int64(g7_19)
|
|
||||||
f3g8_19 := int64(f3) * int64(g8_19)
|
|
||||||
f3g9_38 := int64(f3_2) * int64(g9_19)
|
|
||||||
f4g0 := int64(f4) * int64(g0)
|
|
||||||
f4g1 := int64(f4) * int64(g1)
|
|
||||||
f4g2 := int64(f4) * int64(g2)
|
|
||||||
f4g3 := int64(f4) * int64(g3)
|
|
||||||
f4g4 := int64(f4) * int64(g4)
|
|
||||||
f4g5 := int64(f4) * int64(g5)
|
|
||||||
f4g6_19 := int64(f4) * int64(g6_19)
|
|
||||||
f4g7_19 := int64(f4) * int64(g7_19)
|
|
||||||
f4g8_19 := int64(f4) * int64(g8_19)
|
|
||||||
f4g9_19 := int64(f4) * int64(g9_19)
|
|
||||||
f5g0 := int64(f5) * int64(g0)
|
|
||||||
f5g1_2 := int64(f5_2) * int64(g1)
|
|
||||||
f5g2 := int64(f5) * int64(g2)
|
|
||||||
f5g3_2 := int64(f5_2) * int64(g3)
|
|
||||||
f5g4 := int64(f5) * int64(g4)
|
|
||||||
f5g5_38 := int64(f5_2) * int64(g5_19)
|
|
||||||
f5g6_19 := int64(f5) * int64(g6_19)
|
|
||||||
f5g7_38 := int64(f5_2) * int64(g7_19)
|
|
||||||
f5g8_19 := int64(f5) * int64(g8_19)
|
|
||||||
f5g9_38 := int64(f5_2) * int64(g9_19)
|
|
||||||
f6g0 := int64(f6) * int64(g0)
|
|
||||||
f6g1 := int64(f6) * int64(g1)
|
|
||||||
f6g2 := int64(f6) * int64(g2)
|
|
||||||
f6g3 := int64(f6) * int64(g3)
|
|
||||||
f6g4_19 := int64(f6) * int64(g4_19)
|
|
||||||
f6g5_19 := int64(f6) * int64(g5_19)
|
|
||||||
f6g6_19 := int64(f6) * int64(g6_19)
|
|
||||||
f6g7_19 := int64(f6) * int64(g7_19)
|
|
||||||
f6g8_19 := int64(f6) * int64(g8_19)
|
|
||||||
f6g9_19 := int64(f6) * int64(g9_19)
|
|
||||||
f7g0 := int64(f7) * int64(g0)
|
|
||||||
f7g1_2 := int64(f7_2) * int64(g1)
|
|
||||||
f7g2 := int64(f7) * int64(g2)
|
|
||||||
f7g3_38 := int64(f7_2) * int64(g3_19)
|
|
||||||
f7g4_19 := int64(f7) * int64(g4_19)
|
|
||||||
f7g5_38 := int64(f7_2) * int64(g5_19)
|
|
||||||
f7g6_19 := int64(f7) * int64(g6_19)
|
|
||||||
f7g7_38 := int64(f7_2) * int64(g7_19)
|
|
||||||
f7g8_19 := int64(f7) * int64(g8_19)
|
|
||||||
f7g9_38 := int64(f7_2) * int64(g9_19)
|
|
||||||
f8g0 := int64(f8) * int64(g0)
|
|
||||||
f8g1 := int64(f8) * int64(g1)
|
|
||||||
f8g2_19 := int64(f8) * int64(g2_19)
|
|
||||||
f8g3_19 := int64(f8) * int64(g3_19)
|
|
||||||
f8g4_19 := int64(f8) * int64(g4_19)
|
|
||||||
f8g5_19 := int64(f8) * int64(g5_19)
|
|
||||||
f8g6_19 := int64(f8) * int64(g6_19)
|
|
||||||
f8g7_19 := int64(f8) * int64(g7_19)
|
|
||||||
f8g8_19 := int64(f8) * int64(g8_19)
|
|
||||||
f8g9_19 := int64(f8) * int64(g9_19)
|
|
||||||
f9g0 := int64(f9) * int64(g0)
|
|
||||||
f9g1_38 := int64(f9_2) * int64(g1_19)
|
|
||||||
f9g2_19 := int64(f9) * int64(g2_19)
|
|
||||||
f9g3_38 := int64(f9_2) * int64(g3_19)
|
|
||||||
f9g4_19 := int64(f9) * int64(g4_19)
|
|
||||||
f9g5_38 := int64(f9_2) * int64(g5_19)
|
|
||||||
f9g6_19 := int64(f9) * int64(g6_19)
|
|
||||||
f9g7_38 := int64(f9_2) * int64(g7_19)
|
|
||||||
f9g8_19 := int64(f9) * int64(g8_19)
|
|
||||||
f9g9_38 := int64(f9_2) * int64(g9_19)
|
|
||||||
h0 := f0g0 + f1g9_38 + f2g8_19 + f3g7_38 + f4g6_19 + f5g5_38 + f6g4_19 + f7g3_38 + f8g2_19 + f9g1_38
|
|
||||||
h1 := f0g1 + f1g0 + f2g9_19 + f3g8_19 + f4g7_19 + f5g6_19 + f6g5_19 + f7g4_19 + f8g3_19 + f9g2_19
|
|
||||||
h2 := f0g2 + f1g1_2 + f2g0 + f3g9_38 + f4g8_19 + f5g7_38 + f6g6_19 + f7g5_38 + f8g4_19 + f9g3_38
|
|
||||||
h3 := f0g3 + f1g2 + f2g1 + f3g0 + f4g9_19 + f5g8_19 + f6g7_19 + f7g6_19 + f8g5_19 + f9g4_19
|
|
||||||
h4 := f0g4 + f1g3_2 + f2g2 + f3g1_2 + f4g0 + f5g9_38 + f6g8_19 + f7g7_38 + f8g6_19 + f9g5_38
|
|
||||||
h5 := f0g5 + f1g4 + f2g3 + f3g2 + f4g1 + f5g0 + f6g9_19 + f7g8_19 + f8g7_19 + f9g6_19
|
|
||||||
h6 := f0g6 + f1g5_2 + f2g4 + f3g3_2 + f4g2 + f5g1_2 + f6g0 + f7g9_38 + f8g8_19 + f9g7_38
|
|
||||||
h7 := f0g7 + f1g6 + f2g5 + f3g4 + f4g3 + f5g2 + f6g1 + f7g0 + f8g9_19 + f9g8_19
|
|
||||||
h8 := f0g8 + f1g7_2 + f2g6 + f3g5_2 + f4g4 + f5g3_2 + f6g2 + f7g1_2 + f8g0 + f9g9_38
|
|
||||||
h9 := f0g9 + f1g8 + f2g7 + f3g6 + f4g5 + f5g4 + f6g3 + f7g2 + f8g1 + f9g0
|
|
||||||
var carry [10]int64
|
|
||||||
|
|
||||||
// |h0| <= (1.1*1.1*2^52*(1+19+19+19+19)+1.1*1.1*2^50*(38+38+38+38+38))
|
|
||||||
// i.e. |h0| <= 1.2*2^59; narrower ranges for h2, h4, h6, h8
|
|
||||||
// |h1| <= (1.1*1.1*2^51*(1+1+19+19+19+19+19+19+19+19))
|
|
||||||
// i.e. |h1| <= 1.5*2^58; narrower ranges for h3, h5, h7, h9
|
|
||||||
|
|
||||||
carry[0] = (h0 + (1 << 25)) >> 26
|
|
||||||
h1 += carry[0]
|
|
||||||
h0 -= carry[0] << 26
|
|
||||||
carry[4] = (h4 + (1 << 25)) >> 26
|
|
||||||
h5 += carry[4]
|
|
||||||
h4 -= carry[4] << 26
|
|
||||||
// |h0| <= 2^25
|
|
||||||
// |h4| <= 2^25
|
|
||||||
// |h1| <= 1.51*2^58
|
|
||||||
// |h5| <= 1.51*2^58
|
|
||||||
|
|
||||||
carry[1] = (h1 + (1 << 24)) >> 25
|
|
||||||
h2 += carry[1]
|
|
||||||
h1 -= carry[1] << 25
|
|
||||||
carry[5] = (h5 + (1 << 24)) >> 25
|
|
||||||
h6 += carry[5]
|
|
||||||
h5 -= carry[5] << 25
|
|
||||||
// |h1| <= 2^24; from now on fits into int32
|
|
||||||
// |h5| <= 2^24; from now on fits into int32
|
|
||||||
// |h2| <= 1.21*2^59
|
|
||||||
// |h6| <= 1.21*2^59
|
|
||||||
|
|
||||||
carry[2] = (h2 + (1 << 25)) >> 26
|
|
||||||
h3 += carry[2]
|
|
||||||
h2 -= carry[2] << 26
|
|
||||||
carry[6] = (h6 + (1 << 25)) >> 26
|
|
||||||
h7 += carry[6]
|
|
||||||
h6 -= carry[6] << 26
|
|
||||||
// |h2| <= 2^25; from now on fits into int32 unchanged
|
|
||||||
// |h6| <= 2^25; from now on fits into int32 unchanged
|
|
||||||
// |h3| <= 1.51*2^58
|
|
||||||
// |h7| <= 1.51*2^58
|
|
||||||
|
|
||||||
carry[3] = (h3 + (1 << 24)) >> 25
|
|
||||||
h4 += carry[3]
|
|
||||||
h3 -= carry[3] << 25
|
|
||||||
carry[7] = (h7 + (1 << 24)) >> 25
|
|
||||||
h8 += carry[7]
|
|
||||||
h7 -= carry[7] << 25
|
|
||||||
// |h3| <= 2^24; from now on fits into int32 unchanged
|
|
||||||
// |h7| <= 2^24; from now on fits into int32 unchanged
|
|
||||||
// |h4| <= 1.52*2^33
|
|
||||||
// |h8| <= 1.52*2^33
|
|
||||||
|
|
||||||
carry[4] = (h4 + (1 << 25)) >> 26
|
|
||||||
h5 += carry[4]
|
|
||||||
h4 -= carry[4] << 26
|
|
||||||
carry[8] = (h8 + (1 << 25)) >> 26
|
|
||||||
h9 += carry[8]
|
|
||||||
h8 -= carry[8] << 26
|
|
||||||
// |h4| <= 2^25; from now on fits into int32 unchanged
|
|
||||||
// |h8| <= 2^25; from now on fits into int32 unchanged
|
|
||||||
// |h5| <= 1.01*2^24
|
|
||||||
// |h9| <= 1.51*2^58
|
|
||||||
|
|
||||||
carry[9] = (h9 + (1 << 24)) >> 25
|
|
||||||
h0 += carry[9] * 19
|
|
||||||
h9 -= carry[9] << 25
|
|
||||||
// |h9| <= 2^24; from now on fits into int32 unchanged
|
|
||||||
// |h0| <= 1.8*2^37
|
|
||||||
|
|
||||||
carry[0] = (h0 + (1 << 25)) >> 26
|
|
||||||
h1 += carry[0]
|
|
||||||
h0 -= carry[0] << 26
|
|
||||||
// |h0| <= 2^25; from now on fits into int32 unchanged
|
|
||||||
// |h1| <= 1.01*2^24
|
|
||||||
|
|
||||||
h[0] = int32(h0)
|
|
||||||
h[1] = int32(h1)
|
|
||||||
h[2] = int32(h2)
|
|
||||||
h[3] = int32(h3)
|
|
||||||
h[4] = int32(h4)
|
|
||||||
h[5] = int32(h5)
|
|
||||||
h[6] = int32(h6)
|
|
||||||
h[7] = int32(h7)
|
|
||||||
h[8] = int32(h8)
|
|
||||||
h[9] = int32(h9)
|
|
||||||
}
|
|
||||||
|
|
||||||
// feSquare calculates h = f*f. Can overlap h with f.
|
|
||||||
//
|
|
||||||
// Preconditions:
|
|
||||||
// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
|
|
||||||
//
|
|
||||||
// Postconditions:
|
|
||||||
// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
|
|
||||||
func feSquare(h, f *fieldElement) {
|
|
||||||
f0 := f[0]
|
|
||||||
f1 := f[1]
|
|
||||||
f2 := f[2]
|
|
||||||
f3 := f[3]
|
|
||||||
f4 := f[4]
|
|
||||||
f5 := f[5]
|
|
||||||
f6 := f[6]
|
|
||||||
f7 := f[7]
|
|
||||||
f8 := f[8]
|
|
||||||
f9 := f[9]
|
|
||||||
f0_2 := 2 * f0
|
|
||||||
f1_2 := 2 * f1
|
|
||||||
f2_2 := 2 * f2
|
|
||||||
f3_2 := 2 * f3
|
|
||||||
f4_2 := 2 * f4
|
|
||||||
f5_2 := 2 * f5
|
|
||||||
f6_2 := 2 * f6
|
|
||||||
f7_2 := 2 * f7
|
|
||||||
f5_38 := 38 * f5 // 1.31*2^30
|
|
||||||
f6_19 := 19 * f6 // 1.31*2^30
|
|
||||||
f7_38 := 38 * f7 // 1.31*2^30
|
|
||||||
f8_19 := 19 * f8 // 1.31*2^30
|
|
||||||
f9_38 := 38 * f9 // 1.31*2^30
|
|
||||||
f0f0 := int64(f0) * int64(f0)
|
|
||||||
f0f1_2 := int64(f0_2) * int64(f1)
|
|
||||||
f0f2_2 := int64(f0_2) * int64(f2)
|
|
||||||
f0f3_2 := int64(f0_2) * int64(f3)
|
|
||||||
f0f4_2 := int64(f0_2) * int64(f4)
|
|
||||||
f0f5_2 := int64(f0_2) * int64(f5)
|
|
||||||
f0f6_2 := int64(f0_2) * int64(f6)
|
|
||||||
f0f7_2 := int64(f0_2) * int64(f7)
|
|
||||||
f0f8_2 := int64(f0_2) * int64(f8)
|
|
||||||
f0f9_2 := int64(f0_2) * int64(f9)
|
|
||||||
f1f1_2 := int64(f1_2) * int64(f1)
|
|
||||||
f1f2_2 := int64(f1_2) * int64(f2)
|
|
||||||
f1f3_4 := int64(f1_2) * int64(f3_2)
|
|
||||||
f1f4_2 := int64(f1_2) * int64(f4)
|
|
||||||
f1f5_4 := int64(f1_2) * int64(f5_2)
|
|
||||||
f1f6_2 := int64(f1_2) * int64(f6)
|
|
||||||
f1f7_4 := int64(f1_2) * int64(f7_2)
|
|
||||||
f1f8_2 := int64(f1_2) * int64(f8)
|
|
||||||
f1f9_76 := int64(f1_2) * int64(f9_38)
|
|
||||||
f2f2 := int64(f2) * int64(f2)
|
|
||||||
f2f3_2 := int64(f2_2) * int64(f3)
|
|
||||||
f2f4_2 := int64(f2_2) * int64(f4)
|
|
||||||
f2f5_2 := int64(f2_2) * int64(f5)
|
|
||||||
f2f6_2 := int64(f2_2) * int64(f6)
|
|
||||||
f2f7_2 := int64(f2_2) * int64(f7)
|
|
||||||
f2f8_38 := int64(f2_2) * int64(f8_19)
|
|
||||||
f2f9_38 := int64(f2) * int64(f9_38)
|
|
||||||
f3f3_2 := int64(f3_2) * int64(f3)
|
|
||||||
f3f4_2 := int64(f3_2) * int64(f4)
|
|
||||||
f3f5_4 := int64(f3_2) * int64(f5_2)
|
|
||||||
f3f6_2 := int64(f3_2) * int64(f6)
|
|
||||||
f3f7_76 := int64(f3_2) * int64(f7_38)
|
|
||||||
f3f8_38 := int64(f3_2) * int64(f8_19)
|
|
||||||
f3f9_76 := int64(f3_2) * int64(f9_38)
|
|
||||||
f4f4 := int64(f4) * int64(f4)
|
|
||||||
f4f5_2 := int64(f4_2) * int64(f5)
|
|
||||||
f4f6_38 := int64(f4_2) * int64(f6_19)
|
|
||||||
f4f7_38 := int64(f4) * int64(f7_38)
|
|
||||||
f4f8_38 := int64(f4_2) * int64(f8_19)
|
|
||||||
f4f9_38 := int64(f4) * int64(f9_38)
|
|
||||||
f5f5_38 := int64(f5) * int64(f5_38)
|
|
||||||
f5f6_38 := int64(f5_2) * int64(f6_19)
|
|
||||||
f5f7_76 := int64(f5_2) * int64(f7_38)
|
|
||||||
f5f8_38 := int64(f5_2) * int64(f8_19)
|
|
||||||
f5f9_76 := int64(f5_2) * int64(f9_38)
|
|
||||||
f6f6_19 := int64(f6) * int64(f6_19)
|
|
||||||
f6f7_38 := int64(f6) * int64(f7_38)
|
|
||||||
f6f8_38 := int64(f6_2) * int64(f8_19)
|
|
||||||
f6f9_38 := int64(f6) * int64(f9_38)
|
|
||||||
f7f7_38 := int64(f7) * int64(f7_38)
|
|
||||||
f7f8_38 := int64(f7_2) * int64(f8_19)
|
|
||||||
f7f9_76 := int64(f7_2) * int64(f9_38)
|
|
||||||
f8f8_19 := int64(f8) * int64(f8_19)
|
|
||||||
f8f9_38 := int64(f8) * int64(f9_38)
|
|
||||||
f9f9_38 := int64(f9) * int64(f9_38)
|
|
||||||
h0 := f0f0 + f1f9_76 + f2f8_38 + f3f7_76 + f4f6_38 + f5f5_38
|
|
||||||
h1 := f0f1_2 + f2f9_38 + f3f8_38 + f4f7_38 + f5f6_38
|
|
||||||
h2 := f0f2_2 + f1f1_2 + f3f9_76 + f4f8_38 + f5f7_76 + f6f6_19
|
|
||||||
h3 := f0f3_2 + f1f2_2 + f4f9_38 + f5f8_38 + f6f7_38
|
|
||||||
h4 := f0f4_2 + f1f3_4 + f2f2 + f5f9_76 + f6f8_38 + f7f7_38
|
|
||||||
h5 := f0f5_2 + f1f4_2 + f2f3_2 + f6f9_38 + f7f8_38
|
|
||||||
h6 := f0f6_2 + f1f5_4 + f2f4_2 + f3f3_2 + f7f9_76 + f8f8_19
|
|
||||||
h7 := f0f7_2 + f1f6_2 + f2f5_2 + f3f4_2 + f8f9_38
|
|
||||||
h8 := f0f8_2 + f1f7_4 + f2f6_2 + f3f5_4 + f4f4 + f9f9_38
|
|
||||||
h9 := f0f9_2 + f1f8_2 + f2f7_2 + f3f6_2 + f4f5_2
|
|
||||||
var carry [10]int64
|
|
||||||
|
|
||||||
carry[0] = (h0 + (1 << 25)) >> 26
|
|
||||||
h1 += carry[0]
|
|
||||||
h0 -= carry[0] << 26
|
|
||||||
carry[4] = (h4 + (1 << 25)) >> 26
|
|
||||||
h5 += carry[4]
|
|
||||||
h4 -= carry[4] << 26
|
|
||||||
|
|
||||||
carry[1] = (h1 + (1 << 24)) >> 25
|
|
||||||
h2 += carry[1]
|
|
||||||
h1 -= carry[1] << 25
|
|
||||||
carry[5] = (h5 + (1 << 24)) >> 25
|
|
||||||
h6 += carry[5]
|
|
||||||
h5 -= carry[5] << 25
|
|
||||||
|
|
||||||
carry[2] = (h2 + (1 << 25)) >> 26
|
|
||||||
h3 += carry[2]
|
|
||||||
h2 -= carry[2] << 26
|
|
||||||
carry[6] = (h6 + (1 << 25)) >> 26
|
|
||||||
h7 += carry[6]
|
|
||||||
h6 -= carry[6] << 26
|
|
||||||
|
|
||||||
carry[3] = (h3 + (1 << 24)) >> 25
|
|
||||||
h4 += carry[3]
|
|
||||||
h3 -= carry[3] << 25
|
|
||||||
carry[7] = (h7 + (1 << 24)) >> 25
|
|
||||||
h8 += carry[7]
|
|
||||||
h7 -= carry[7] << 25
|
|
||||||
|
|
||||||
carry[4] = (h4 + (1 << 25)) >> 26
|
|
||||||
h5 += carry[4]
|
|
||||||
h4 -= carry[4] << 26
|
|
||||||
carry[8] = (h8 + (1 << 25)) >> 26
|
|
||||||
h9 += carry[8]
|
|
||||||
h8 -= carry[8] << 26
|
|
||||||
|
|
||||||
carry[9] = (h9 + (1 << 24)) >> 25
|
|
||||||
h0 += carry[9] * 19
|
|
||||||
h9 -= carry[9] << 25
|
|
||||||
|
|
||||||
carry[0] = (h0 + (1 << 25)) >> 26
|
|
||||||
h1 += carry[0]
|
|
||||||
h0 -= carry[0] << 26
|
|
||||||
|
|
||||||
h[0] = int32(h0)
|
|
||||||
h[1] = int32(h1)
|
|
||||||
h[2] = int32(h2)
|
|
||||||
h[3] = int32(h3)
|
|
||||||
h[4] = int32(h4)
|
|
||||||
h[5] = int32(h5)
|
|
||||||
h[6] = int32(h6)
|
|
||||||
h[7] = int32(h7)
|
|
||||||
h[8] = int32(h8)
|
|
||||||
h[9] = int32(h9)
|
|
||||||
}
|
|
||||||
|
|
||||||
// feMul121666 calculates h = f * 121666. Can overlap h with f.
|
|
||||||
//
|
|
||||||
// Preconditions:
|
|
||||||
// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
|
|
||||||
//
|
|
||||||
// Postconditions:
|
|
||||||
// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
|
|
||||||
func feMul121666(h, f *fieldElement) {
|
|
||||||
h0 := int64(f[0]) * 121666
|
|
||||||
h1 := int64(f[1]) * 121666
|
|
||||||
h2 := int64(f[2]) * 121666
|
|
||||||
h3 := int64(f[3]) * 121666
|
|
||||||
h4 := int64(f[4]) * 121666
|
|
||||||
h5 := int64(f[5]) * 121666
|
|
||||||
h6 := int64(f[6]) * 121666
|
|
||||||
h7 := int64(f[7]) * 121666
|
|
||||||
h8 := int64(f[8]) * 121666
|
|
||||||
h9 := int64(f[9]) * 121666
|
|
||||||
var carry [10]int64
|
|
||||||
|
|
||||||
carry[9] = (h9 + (1 << 24)) >> 25
|
|
||||||
h0 += carry[9] * 19
|
|
||||||
h9 -= carry[9] << 25
|
|
||||||
carry[1] = (h1 + (1 << 24)) >> 25
|
|
||||||
h2 += carry[1]
|
|
||||||
h1 -= carry[1] << 25
|
|
||||||
carry[3] = (h3 + (1 << 24)) >> 25
|
|
||||||
h4 += carry[3]
|
|
||||||
h3 -= carry[3] << 25
|
|
||||||
carry[5] = (h5 + (1 << 24)) >> 25
|
|
||||||
h6 += carry[5]
|
|
||||||
h5 -= carry[5] << 25
|
|
||||||
carry[7] = (h7 + (1 << 24)) >> 25
|
|
||||||
h8 += carry[7]
|
|
||||||
h7 -= carry[7] << 25
|
|
||||||
|
|
||||||
carry[0] = (h0 + (1 << 25)) >> 26
|
|
||||||
h1 += carry[0]
|
|
||||||
h0 -= carry[0] << 26
|
|
||||||
carry[2] = (h2 + (1 << 25)) >> 26
|
|
||||||
h3 += carry[2]
|
|
||||||
h2 -= carry[2] << 26
|
|
||||||
carry[4] = (h4 + (1 << 25)) >> 26
|
|
||||||
h5 += carry[4]
|
|
||||||
h4 -= carry[4] << 26
|
|
||||||
carry[6] = (h6 + (1 << 25)) >> 26
|
|
||||||
h7 += carry[6]
|
|
||||||
h6 -= carry[6] << 26
|
|
||||||
carry[8] = (h8 + (1 << 25)) >> 26
|
|
||||||
h9 += carry[8]
|
|
||||||
h8 -= carry[8] << 26
|
|
||||||
|
|
||||||
h[0] = int32(h0)
|
|
||||||
h[1] = int32(h1)
|
|
||||||
h[2] = int32(h2)
|
|
||||||
h[3] = int32(h3)
|
|
||||||
h[4] = int32(h4)
|
|
||||||
h[5] = int32(h5)
|
|
||||||
h[6] = int32(h6)
|
|
||||||
h[7] = int32(h7)
|
|
||||||
h[8] = int32(h8)
|
|
||||||
h[9] = int32(h9)
|
|
||||||
}
|
|
||||||
|
|
||||||
// feInvert sets out = z^-1.
|
|
||||||
func feInvert(out, z *fieldElement) {
|
|
||||||
var t0, t1, t2, t3 fieldElement
|
|
||||||
var i int
|
|
||||||
|
|
||||||
feSquare(&t0, z)
|
|
||||||
for i = 1; i < 1; i++ {
|
|
||||||
feSquare(&t0, &t0)
|
|
||||||
}
|
|
||||||
feSquare(&t1, &t0)
|
|
||||||
for i = 1; i < 2; i++ {
|
|
||||||
feSquare(&t1, &t1)
|
|
||||||
}
|
|
||||||
feMul(&t1, z, &t1)
|
|
||||||
feMul(&t0, &t0, &t1)
|
|
||||||
feSquare(&t2, &t0)
|
|
||||||
for i = 1; i < 1; i++ {
|
|
||||||
feSquare(&t2, &t2)
|
|
||||||
}
|
|
||||||
feMul(&t1, &t1, &t2)
|
|
||||||
feSquare(&t2, &t1)
|
|
||||||
for i = 1; i < 5; i++ {
|
|
||||||
feSquare(&t2, &t2)
|
|
||||||
}
|
|
||||||
feMul(&t1, &t2, &t1)
|
|
||||||
feSquare(&t2, &t1)
|
|
||||||
for i = 1; i < 10; i++ {
|
|
||||||
feSquare(&t2, &t2)
|
|
||||||
}
|
|
||||||
feMul(&t2, &t2, &t1)
|
|
||||||
feSquare(&t3, &t2)
|
|
||||||
for i = 1; i < 20; i++ {
|
|
||||||
feSquare(&t3, &t3)
|
|
||||||
}
|
|
||||||
feMul(&t2, &t3, &t2)
|
|
||||||
feSquare(&t2, &t2)
|
|
||||||
for i = 1; i < 10; i++ {
|
|
||||||
feSquare(&t2, &t2)
|
|
||||||
}
|
|
||||||
feMul(&t1, &t2, &t1)
|
|
||||||
feSquare(&t2, &t1)
|
|
||||||
for i = 1; i < 50; i++ {
|
|
||||||
feSquare(&t2, &t2)
|
|
||||||
}
|
|
||||||
feMul(&t2, &t2, &t1)
|
|
||||||
feSquare(&t3, &t2)
|
|
||||||
for i = 1; i < 100; i++ {
|
|
||||||
feSquare(&t3, &t3)
|
|
||||||
}
|
|
||||||
feMul(&t2, &t3, &t2)
|
|
||||||
feSquare(&t2, &t2)
|
|
||||||
for i = 1; i < 50; i++ {
|
|
||||||
feSquare(&t2, &t2)
|
|
||||||
}
|
|
||||||
feMul(&t1, &t2, &t1)
|
|
||||||
feSquare(&t1, &t1)
|
|
||||||
for i = 1; i < 5; i++ {
|
|
||||||
feSquare(&t1, &t1)
|
|
||||||
}
|
|
||||||
feMul(out, &t1, &t0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func scalarMult(out, in, base *[32]byte) {
|
|
||||||
var e [32]byte
|
|
||||||
|
|
||||||
copy(e[:], in[:])
|
|
||||||
e[0] &= 248
|
|
||||||
e[31] &= 127
|
|
||||||
e[31] |= 64
|
|
||||||
|
|
||||||
var x1, x2, z2, x3, z3, tmp0, tmp1 fieldElement
|
|
||||||
feFromBytes(&x1, base)
|
|
||||||
feOne(&x2)
|
|
||||||
feCopy(&x3, &x1)
|
|
||||||
feOne(&z3)
|
|
||||||
|
|
||||||
swap := int32(0)
|
|
||||||
for pos := 254; pos >= 0; pos-- {
|
|
||||||
b := e[pos/8] >> uint(pos&7)
|
|
||||||
b &= 1
|
|
||||||
swap ^= int32(b)
|
|
||||||
feCSwap(&x2, &x3, swap)
|
|
||||||
feCSwap(&z2, &z3, swap)
|
|
||||||
swap = int32(b)
|
|
||||||
|
|
||||||
feSub(&tmp0, &x3, &z3)
|
|
||||||
feSub(&tmp1, &x2, &z2)
|
|
||||||
feAdd(&x2, &x2, &z2)
|
|
||||||
feAdd(&z2, &x3, &z3)
|
|
||||||
feMul(&z3, &tmp0, &x2)
|
|
||||||
feMul(&z2, &z2, &tmp1)
|
|
||||||
feSquare(&tmp0, &tmp1)
|
|
||||||
feSquare(&tmp1, &x2)
|
|
||||||
feAdd(&x3, &z3, &z2)
|
|
||||||
feSub(&z2, &z3, &z2)
|
|
||||||
feMul(&x2, &tmp1, &tmp0)
|
|
||||||
feSub(&tmp1, &tmp1, &tmp0)
|
|
||||||
feSquare(&z2, &z2)
|
|
||||||
feMul121666(&z3, &tmp1)
|
|
||||||
feSquare(&x3, &x3)
|
|
||||||
feAdd(&tmp0, &tmp0, &z3)
|
|
||||||
feMul(&z3, &x1, &z2)
|
|
||||||
feMul(&z2, &tmp1, &tmp0)
|
|
||||||
}
|
|
||||||
|
|
||||||
feCSwap(&x2, &x3, swap)
|
|
||||||
feCSwap(&z2, &z3, swap)
|
|
||||||
|
|
||||||
feInvert(&z2, &z2)
|
|
||||||
feMul(&x2, &x2, &z2)
|
|
||||||
feToBytes(out, &x2)
|
|
||||||
}
|
|
23
vendor/golang.org/x/crypto/curve25519/doc.go
generated
vendored
23
vendor/golang.org/x/crypto/curve25519/doc.go
generated
vendored
@ -1,23 +0,0 @@
|
|||||||
// 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 curve25519 provides an implementation of scalar multiplication on
|
|
||||||
// the elliptic curve known as curve25519. See https://cr.yp.to/ecdh.html
|
|
||||||
package curve25519 // import "golang.org/x/crypto/curve25519"
|
|
||||||
|
|
||||||
// basePoint is the x coordinate of the generator of the curve.
|
|
||||||
var basePoint = [32]byte{9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
|
||||||
|
|
||||||
// ScalarMult sets dst to the product in*base where dst and base are the x
|
|
||||||
// coordinates of group points and all values are in little-endian form.
|
|
||||||
func ScalarMult(dst, in, base *[32]byte) {
|
|
||||||
scalarMult(dst, in, base)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ScalarBaseMult sets dst to the product in*base where dst and base are the x
|
|
||||||
// coordinates of group points, base is the standard generator and all values
|
|
||||||
// are in little-endian form.
|
|
||||||
func ScalarBaseMult(dst, in *[32]byte) {
|
|
||||||
ScalarMult(dst, in, &basePoint)
|
|
||||||
}
|
|
73
vendor/golang.org/x/crypto/curve25519/freeze_amd64.s
generated
vendored
73
vendor/golang.org/x/crypto/curve25519/freeze_amd64.s
generated
vendored
@ -1,73 +0,0 @@
|
|||||||
// 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.
|
|
||||||
|
|
||||||
// This code was translated into a form compatible with 6a from the public
|
|
||||||
// domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html
|
|
||||||
|
|
||||||
// +build amd64,!gccgo,!appengine
|
|
||||||
|
|
||||||
#include "const_amd64.h"
|
|
||||||
|
|
||||||
// func freeze(inout *[5]uint64)
|
|
||||||
TEXT ·freeze(SB),7,$0-8
|
|
||||||
MOVQ inout+0(FP), DI
|
|
||||||
|
|
||||||
MOVQ 0(DI),SI
|
|
||||||
MOVQ 8(DI),DX
|
|
||||||
MOVQ 16(DI),CX
|
|
||||||
MOVQ 24(DI),R8
|
|
||||||
MOVQ 32(DI),R9
|
|
||||||
MOVQ $REDMASK51,AX
|
|
||||||
MOVQ AX,R10
|
|
||||||
SUBQ $18,R10
|
|
||||||
MOVQ $3,R11
|
|
||||||
REDUCELOOP:
|
|
||||||
MOVQ SI,R12
|
|
||||||
SHRQ $51,R12
|
|
||||||
ANDQ AX,SI
|
|
||||||
ADDQ R12,DX
|
|
||||||
MOVQ DX,R12
|
|
||||||
SHRQ $51,R12
|
|
||||||
ANDQ AX,DX
|
|
||||||
ADDQ R12,CX
|
|
||||||
MOVQ CX,R12
|
|
||||||
SHRQ $51,R12
|
|
||||||
ANDQ AX,CX
|
|
||||||
ADDQ R12,R8
|
|
||||||
MOVQ R8,R12
|
|
||||||
SHRQ $51,R12
|
|
||||||
ANDQ AX,R8
|
|
||||||
ADDQ R12,R9
|
|
||||||
MOVQ R9,R12
|
|
||||||
SHRQ $51,R12
|
|
||||||
ANDQ AX,R9
|
|
||||||
IMUL3Q $19,R12,R12
|
|
||||||
ADDQ R12,SI
|
|
||||||
SUBQ $1,R11
|
|
||||||
JA REDUCELOOP
|
|
||||||
MOVQ $1,R12
|
|
||||||
CMPQ R10,SI
|
|
||||||
CMOVQLT R11,R12
|
|
||||||
CMPQ AX,DX
|
|
||||||
CMOVQNE R11,R12
|
|
||||||
CMPQ AX,CX
|
|
||||||
CMOVQNE R11,R12
|
|
||||||
CMPQ AX,R8
|
|
||||||
CMOVQNE R11,R12
|
|
||||||
CMPQ AX,R9
|
|
||||||
CMOVQNE R11,R12
|
|
||||||
NEGQ R12
|
|
||||||
ANDQ R12,AX
|
|
||||||
ANDQ R12,R10
|
|
||||||
SUBQ R10,SI
|
|
||||||
SUBQ AX,DX
|
|
||||||
SUBQ AX,CX
|
|
||||||
SUBQ AX,R8
|
|
||||||
SUBQ AX,R9
|
|
||||||
MOVQ SI,0(DI)
|
|
||||||
MOVQ DX,8(DI)
|
|
||||||
MOVQ CX,16(DI)
|
|
||||||
MOVQ R8,24(DI)
|
|
||||||
MOVQ R9,32(DI)
|
|
||||||
RET
|
|
1377
vendor/golang.org/x/crypto/curve25519/ladderstep_amd64.s
generated
vendored
1377
vendor/golang.org/x/crypto/curve25519/ladderstep_amd64.s
generated
vendored
File diff suppressed because it is too large
Load Diff
240
vendor/golang.org/x/crypto/curve25519/mont25519_amd64.go
generated
vendored
240
vendor/golang.org/x/crypto/curve25519/mont25519_amd64.go
generated
vendored
@ -1,240 +0,0 @@
|
|||||||
// 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.
|
|
||||||
|
|
||||||
// +build amd64,!gccgo,!appengine
|
|
||||||
|
|
||||||
package curve25519
|
|
||||||
|
|
||||||
// These functions are implemented in the .s files. The names of the functions
|
|
||||||
// in the rest of the file are also taken from the SUPERCOP sources to help
|
|
||||||
// people following along.
|
|
||||||
|
|
||||||
//go:noescape
|
|
||||||
|
|
||||||
func cswap(inout *[5]uint64, v uint64)
|
|
||||||
|
|
||||||
//go:noescape
|
|
||||||
|
|
||||||
func ladderstep(inout *[5][5]uint64)
|
|
||||||
|
|
||||||
//go:noescape
|
|
||||||
|
|
||||||
func freeze(inout *[5]uint64)
|
|
||||||
|
|
||||||
//go:noescape
|
|
||||||
|
|
||||||
func mul(dest, a, b *[5]uint64)
|
|
||||||
|
|
||||||
//go:noescape
|
|
||||||
|
|
||||||
func square(out, in *[5]uint64)
|
|
||||||
|
|
||||||
// mladder uses a Montgomery ladder to calculate (xr/zr) *= s.
|
|
||||||
func mladder(xr, zr *[5]uint64, s *[32]byte) {
|
|
||||||
var work [5][5]uint64
|
|
||||||
|
|
||||||
work[0] = *xr
|
|
||||||
setint(&work[1], 1)
|
|
||||||
setint(&work[2], 0)
|
|
||||||
work[3] = *xr
|
|
||||||
setint(&work[4], 1)
|
|
||||||
|
|
||||||
j := uint(6)
|
|
||||||
var prevbit byte
|
|
||||||
|
|
||||||
for i := 31; i >= 0; i-- {
|
|
||||||
for j < 8 {
|
|
||||||
bit := ((*s)[i] >> j) & 1
|
|
||||||
swap := bit ^ prevbit
|
|
||||||
prevbit = bit
|
|
||||||
cswap(&work[1], uint64(swap))
|
|
||||||
ladderstep(&work)
|
|
||||||
j--
|
|
||||||
}
|
|
||||||
j = 7
|
|
||||||
}
|
|
||||||
|
|
||||||
*xr = work[1]
|
|
||||||
*zr = work[2]
|
|
||||||
}
|
|
||||||
|
|
||||||
func scalarMult(out, in, base *[32]byte) {
|
|
||||||
var e [32]byte
|
|
||||||
copy(e[:], (*in)[:])
|
|
||||||
e[0] &= 248
|
|
||||||
e[31] &= 127
|
|
||||||
e[31] |= 64
|
|
||||||
|
|
||||||
var t, z [5]uint64
|
|
||||||
unpack(&t, base)
|
|
||||||
mladder(&t, &z, &e)
|
|
||||||
invert(&z, &z)
|
|
||||||
mul(&t, &t, &z)
|
|
||||||
pack(out, &t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func setint(r *[5]uint64, v uint64) {
|
|
||||||
r[0] = v
|
|
||||||
r[1] = 0
|
|
||||||
r[2] = 0
|
|
||||||
r[3] = 0
|
|
||||||
r[4] = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// unpack sets r = x where r consists of 5, 51-bit limbs in little-endian
|
|
||||||
// order.
|
|
||||||
func unpack(r *[5]uint64, x *[32]byte) {
|
|
||||||
r[0] = uint64(x[0]) |
|
|
||||||
uint64(x[1])<<8 |
|
|
||||||
uint64(x[2])<<16 |
|
|
||||||
uint64(x[3])<<24 |
|
|
||||||
uint64(x[4])<<32 |
|
|
||||||
uint64(x[5])<<40 |
|
|
||||||
uint64(x[6]&7)<<48
|
|
||||||
|
|
||||||
r[1] = uint64(x[6])>>3 |
|
|
||||||
uint64(x[7])<<5 |
|
|
||||||
uint64(x[8])<<13 |
|
|
||||||
uint64(x[9])<<21 |
|
|
||||||
uint64(x[10])<<29 |
|
|
||||||
uint64(x[11])<<37 |
|
|
||||||
uint64(x[12]&63)<<45
|
|
||||||
|
|
||||||
r[2] = uint64(x[12])>>6 |
|
|
||||||
uint64(x[13])<<2 |
|
|
||||||
uint64(x[14])<<10 |
|
|
||||||
uint64(x[15])<<18 |
|
|
||||||
uint64(x[16])<<26 |
|
|
||||||
uint64(x[17])<<34 |
|
|
||||||
uint64(x[18])<<42 |
|
|
||||||
uint64(x[19]&1)<<50
|
|
||||||
|
|
||||||
r[3] = uint64(x[19])>>1 |
|
|
||||||
uint64(x[20])<<7 |
|
|
||||||
uint64(x[21])<<15 |
|
|
||||||
uint64(x[22])<<23 |
|
|
||||||
uint64(x[23])<<31 |
|
|
||||||
uint64(x[24])<<39 |
|
|
||||||
uint64(x[25]&15)<<47
|
|
||||||
|
|
||||||
r[4] = uint64(x[25])>>4 |
|
|
||||||
uint64(x[26])<<4 |
|
|
||||||
uint64(x[27])<<12 |
|
|
||||||
uint64(x[28])<<20 |
|
|
||||||
uint64(x[29])<<28 |
|
|
||||||
uint64(x[30])<<36 |
|
|
||||||
uint64(x[31]&127)<<44
|
|
||||||
}
|
|
||||||
|
|
||||||
// pack sets out = x where out is the usual, little-endian form of the 5,
|
|
||||||
// 51-bit limbs in x.
|
|
||||||
func pack(out *[32]byte, x *[5]uint64) {
|
|
||||||
t := *x
|
|
||||||
freeze(&t)
|
|
||||||
|
|
||||||
out[0] = byte(t[0])
|
|
||||||
out[1] = byte(t[0] >> 8)
|
|
||||||
out[2] = byte(t[0] >> 16)
|
|
||||||
out[3] = byte(t[0] >> 24)
|
|
||||||
out[4] = byte(t[0] >> 32)
|
|
||||||
out[5] = byte(t[0] >> 40)
|
|
||||||
out[6] = byte(t[0] >> 48)
|
|
||||||
|
|
||||||
out[6] ^= byte(t[1]<<3) & 0xf8
|
|
||||||
out[7] = byte(t[1] >> 5)
|
|
||||||
out[8] = byte(t[1] >> 13)
|
|
||||||
out[9] = byte(t[1] >> 21)
|
|
||||||
out[10] = byte(t[1] >> 29)
|
|
||||||
out[11] = byte(t[1] >> 37)
|
|
||||||
out[12] = byte(t[1] >> 45)
|
|
||||||
|
|
||||||
out[12] ^= byte(t[2]<<6) & 0xc0
|
|
||||||
out[13] = byte(t[2] >> 2)
|
|
||||||
out[14] = byte(t[2] >> 10)
|
|
||||||
out[15] = byte(t[2] >> 18)
|
|
||||||
out[16] = byte(t[2] >> 26)
|
|
||||||
out[17] = byte(t[2] >> 34)
|
|
||||||
out[18] = byte(t[2] >> 42)
|
|
||||||
out[19] = byte(t[2] >> 50)
|
|
||||||
|
|
||||||
out[19] ^= byte(t[3]<<1) & 0xfe
|
|
||||||
out[20] = byte(t[3] >> 7)
|
|
||||||
out[21] = byte(t[3] >> 15)
|
|
||||||
out[22] = byte(t[3] >> 23)
|
|
||||||
out[23] = byte(t[3] >> 31)
|
|
||||||
out[24] = byte(t[3] >> 39)
|
|
||||||
out[25] = byte(t[3] >> 47)
|
|
||||||
|
|
||||||
out[25] ^= byte(t[4]<<4) & 0xf0
|
|
||||||
out[26] = byte(t[4] >> 4)
|
|
||||||
out[27] = byte(t[4] >> 12)
|
|
||||||
out[28] = byte(t[4] >> 20)
|
|
||||||
out[29] = byte(t[4] >> 28)
|
|
||||||
out[30] = byte(t[4] >> 36)
|
|
||||||
out[31] = byte(t[4] >> 44)
|
|
||||||
}
|
|
||||||
|
|
||||||
// invert calculates r = x^-1 mod p using Fermat's little theorem.
|
|
||||||
func invert(r *[5]uint64, x *[5]uint64) {
|
|
||||||
var z2, z9, z11, z2_5_0, z2_10_0, z2_20_0, z2_50_0, z2_100_0, t [5]uint64
|
|
||||||
|
|
||||||
square(&z2, x) /* 2 */
|
|
||||||
square(&t, &z2) /* 4 */
|
|
||||||
square(&t, &t) /* 8 */
|
|
||||||
mul(&z9, &t, x) /* 9 */
|
|
||||||
mul(&z11, &z9, &z2) /* 11 */
|
|
||||||
square(&t, &z11) /* 22 */
|
|
||||||
mul(&z2_5_0, &t, &z9) /* 2^5 - 2^0 = 31 */
|
|
||||||
|
|
||||||
square(&t, &z2_5_0) /* 2^6 - 2^1 */
|
|
||||||
for i := 1; i < 5; i++ { /* 2^20 - 2^10 */
|
|
||||||
square(&t, &t)
|
|
||||||
}
|
|
||||||
mul(&z2_10_0, &t, &z2_5_0) /* 2^10 - 2^0 */
|
|
||||||
|
|
||||||
square(&t, &z2_10_0) /* 2^11 - 2^1 */
|
|
||||||
for i := 1; i < 10; i++ { /* 2^20 - 2^10 */
|
|
||||||
square(&t, &t)
|
|
||||||
}
|
|
||||||
mul(&z2_20_0, &t, &z2_10_0) /* 2^20 - 2^0 */
|
|
||||||
|
|
||||||
square(&t, &z2_20_0) /* 2^21 - 2^1 */
|
|
||||||
for i := 1; i < 20; i++ { /* 2^40 - 2^20 */
|
|
||||||
square(&t, &t)
|
|
||||||
}
|
|
||||||
mul(&t, &t, &z2_20_0) /* 2^40 - 2^0 */
|
|
||||||
|
|
||||||
square(&t, &t) /* 2^41 - 2^1 */
|
|
||||||
for i := 1; i < 10; i++ { /* 2^50 - 2^10 */
|
|
||||||
square(&t, &t)
|
|
||||||
}
|
|
||||||
mul(&z2_50_0, &t, &z2_10_0) /* 2^50 - 2^0 */
|
|
||||||
|
|
||||||
square(&t, &z2_50_0) /* 2^51 - 2^1 */
|
|
||||||
for i := 1; i < 50; i++ { /* 2^100 - 2^50 */
|
|
||||||
square(&t, &t)
|
|
||||||
}
|
|
||||||
mul(&z2_100_0, &t, &z2_50_0) /* 2^100 - 2^0 */
|
|
||||||
|
|
||||||
square(&t, &z2_100_0) /* 2^101 - 2^1 */
|
|
||||||
for i := 1; i < 100; i++ { /* 2^200 - 2^100 */
|
|
||||||
square(&t, &t)
|
|
||||||
}
|
|
||||||
mul(&t, &t, &z2_100_0) /* 2^200 - 2^0 */
|
|
||||||
|
|
||||||
square(&t, &t) /* 2^201 - 2^1 */
|
|
||||||
for i := 1; i < 50; i++ { /* 2^250 - 2^50 */
|
|
||||||
square(&t, &t)
|
|
||||||
}
|
|
||||||
mul(&t, &t, &z2_50_0) /* 2^250 - 2^0 */
|
|
||||||
|
|
||||||
square(&t, &t) /* 2^251 - 2^1 */
|
|
||||||
square(&t, &t) /* 2^252 - 2^2 */
|
|
||||||
square(&t, &t) /* 2^253 - 2^3 */
|
|
||||||
|
|
||||||
square(&t, &t) /* 2^254 - 2^4 */
|
|
||||||
|
|
||||||
square(&t, &t) /* 2^255 - 2^5 */
|
|
||||||
mul(r, &t, &z11) /* 2^255 - 21 */
|
|
||||||
}
|
|
169
vendor/golang.org/x/crypto/curve25519/mul_amd64.s
generated
vendored
169
vendor/golang.org/x/crypto/curve25519/mul_amd64.s
generated
vendored
@ -1,169 +0,0 @@
|
|||||||
// 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.
|
|
||||||
|
|
||||||
// This code was translated into a form compatible with 6a from the public
|
|
||||||
// domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html
|
|
||||||
|
|
||||||
// +build amd64,!gccgo,!appengine
|
|
||||||
|
|
||||||
#include "const_amd64.h"
|
|
||||||
|
|
||||||
// func mul(dest, a, b *[5]uint64)
|
|
||||||
TEXT ·mul(SB),0,$16-24
|
|
||||||
MOVQ dest+0(FP), DI
|
|
||||||
MOVQ a+8(FP), SI
|
|
||||||
MOVQ b+16(FP), DX
|
|
||||||
|
|
||||||
MOVQ DX,CX
|
|
||||||
MOVQ 24(SI),DX
|
|
||||||
IMUL3Q $19,DX,AX
|
|
||||||
MOVQ AX,0(SP)
|
|
||||||
MULQ 16(CX)
|
|
||||||
MOVQ AX,R8
|
|
||||||
MOVQ DX,R9
|
|
||||||
MOVQ 32(SI),DX
|
|
||||||
IMUL3Q $19,DX,AX
|
|
||||||
MOVQ AX,8(SP)
|
|
||||||
MULQ 8(CX)
|
|
||||||
ADDQ AX,R8
|
|
||||||
ADCQ DX,R9
|
|
||||||
MOVQ 0(SI),AX
|
|
||||||
MULQ 0(CX)
|
|
||||||
ADDQ AX,R8
|
|
||||||
ADCQ DX,R9
|
|
||||||
MOVQ 0(SI),AX
|
|
||||||
MULQ 8(CX)
|
|
||||||
MOVQ AX,R10
|
|
||||||
MOVQ DX,R11
|
|
||||||
MOVQ 0(SI),AX
|
|
||||||
MULQ 16(CX)
|
|
||||||
MOVQ AX,R12
|
|
||||||
MOVQ DX,R13
|
|
||||||
MOVQ 0(SI),AX
|
|
||||||
MULQ 24(CX)
|
|
||||||
MOVQ AX,R14
|
|
||||||
MOVQ DX,R15
|
|
||||||
MOVQ 0(SI),AX
|
|
||||||
MULQ 32(CX)
|
|
||||||
MOVQ AX,BX
|
|
||||||
MOVQ DX,BP
|
|
||||||
MOVQ 8(SI),AX
|
|
||||||
MULQ 0(CX)
|
|
||||||
ADDQ AX,R10
|
|
||||||
ADCQ DX,R11
|
|
||||||
MOVQ 8(SI),AX
|
|
||||||
MULQ 8(CX)
|
|
||||||
ADDQ AX,R12
|
|
||||||
ADCQ DX,R13
|
|
||||||
MOVQ 8(SI),AX
|
|
||||||
MULQ 16(CX)
|
|
||||||
ADDQ AX,R14
|
|
||||||
ADCQ DX,R15
|
|
||||||
MOVQ 8(SI),AX
|
|
||||||
MULQ 24(CX)
|
|
||||||
ADDQ AX,BX
|
|
||||||
ADCQ DX,BP
|
|
||||||
MOVQ 8(SI),DX
|
|
||||||
IMUL3Q $19,DX,AX
|
|
||||||
MULQ 32(CX)
|
|
||||||
ADDQ AX,R8
|
|
||||||
ADCQ DX,R9
|
|
||||||
MOVQ 16(SI),AX
|
|
||||||
MULQ 0(CX)
|
|
||||||
ADDQ AX,R12
|
|
||||||
ADCQ DX,R13
|
|
||||||
MOVQ 16(SI),AX
|
|
||||||
MULQ 8(CX)
|
|
||||||
ADDQ AX,R14
|
|
||||||
ADCQ DX,R15
|
|
||||||
MOVQ 16(SI),AX
|
|
||||||
MULQ 16(CX)
|
|
||||||
ADDQ AX,BX
|
|
||||||
ADCQ DX,BP
|
|
||||||
MOVQ 16(SI),DX
|
|
||||||
IMUL3Q $19,DX,AX
|
|
||||||
MULQ 24(CX)
|
|
||||||
ADDQ AX,R8
|
|
||||||
ADCQ DX,R9
|
|
||||||
MOVQ 16(SI),DX
|
|
||||||
IMUL3Q $19,DX,AX
|
|
||||||
MULQ 32(CX)
|
|
||||||
ADDQ AX,R10
|
|
||||||
ADCQ DX,R11
|
|
||||||
MOVQ 24(SI),AX
|
|
||||||
MULQ 0(CX)
|
|
||||||
ADDQ AX,R14
|
|
||||||
ADCQ DX,R15
|
|
||||||
MOVQ 24(SI),AX
|
|
||||||
MULQ 8(CX)
|
|
||||||
ADDQ AX,BX
|
|
||||||
ADCQ DX,BP
|
|
||||||
MOVQ 0(SP),AX
|
|
||||||
MULQ 24(CX)
|
|
||||||
ADDQ AX,R10
|
|
||||||
ADCQ DX,R11
|
|
||||||
MOVQ 0(SP),AX
|
|
||||||
MULQ 32(CX)
|
|
||||||
ADDQ AX,R12
|
|
||||||
ADCQ DX,R13
|
|
||||||
MOVQ 32(SI),AX
|
|
||||||
MULQ 0(CX)
|
|
||||||
ADDQ AX,BX
|
|
||||||
ADCQ DX,BP
|
|
||||||
MOVQ 8(SP),AX
|
|
||||||
MULQ 16(CX)
|
|
||||||
ADDQ AX,R10
|
|
||||||
ADCQ DX,R11
|
|
||||||
MOVQ 8(SP),AX
|
|
||||||
MULQ 24(CX)
|
|
||||||
ADDQ AX,R12
|
|
||||||
ADCQ DX,R13
|
|
||||||
MOVQ 8(SP),AX
|
|
||||||
MULQ 32(CX)
|
|
||||||
ADDQ AX,R14
|
|
||||||
ADCQ DX,R15
|
|
||||||
MOVQ $REDMASK51,SI
|
|
||||||
SHLQ $13,R8,R9
|
|
||||||
ANDQ SI,R8
|
|
||||||
SHLQ $13,R10,R11
|
|
||||||
ANDQ SI,R10
|
|
||||||
ADDQ R9,R10
|
|
||||||
SHLQ $13,R12,R13
|
|
||||||
ANDQ SI,R12
|
|
||||||
ADDQ R11,R12
|
|
||||||
SHLQ $13,R14,R15
|
|
||||||
ANDQ SI,R14
|
|
||||||
ADDQ R13,R14
|
|
||||||
SHLQ $13,BX,BP
|
|
||||||
ANDQ SI,BX
|
|
||||||
ADDQ R15,BX
|
|
||||||
IMUL3Q $19,BP,DX
|
|
||||||
ADDQ DX,R8
|
|
||||||
MOVQ R8,DX
|
|
||||||
SHRQ $51,DX
|
|
||||||
ADDQ R10,DX
|
|
||||||
MOVQ DX,CX
|
|
||||||
SHRQ $51,DX
|
|
||||||
ANDQ SI,R8
|
|
||||||
ADDQ R12,DX
|
|
||||||
MOVQ DX,R9
|
|
||||||
SHRQ $51,DX
|
|
||||||
ANDQ SI,CX
|
|
||||||
ADDQ R14,DX
|
|
||||||
MOVQ DX,AX
|
|
||||||
SHRQ $51,DX
|
|
||||||
ANDQ SI,R9
|
|
||||||
ADDQ BX,DX
|
|
||||||
MOVQ DX,R10
|
|
||||||
SHRQ $51,DX
|
|
||||||
ANDQ SI,AX
|
|
||||||
IMUL3Q $19,DX,DX
|
|
||||||
ADDQ DX,R8
|
|
||||||
ANDQ SI,R10
|
|
||||||
MOVQ R8,0(DI)
|
|
||||||
MOVQ CX,8(DI)
|
|
||||||
MOVQ R9,16(DI)
|
|
||||||
MOVQ AX,24(DI)
|
|
||||||
MOVQ R10,32(DI)
|
|
||||||
RET
|
|
132
vendor/golang.org/x/crypto/curve25519/square_amd64.s
generated
vendored
132
vendor/golang.org/x/crypto/curve25519/square_amd64.s
generated
vendored
@ -1,132 +0,0 @@
|
|||||||
// 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.
|
|
||||||
|
|
||||||
// This code was translated into a form compatible with 6a from the public
|
|
||||||
// domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html
|
|
||||||
|
|
||||||
// +build amd64,!gccgo,!appengine
|
|
||||||
|
|
||||||
#include "const_amd64.h"
|
|
||||||
|
|
||||||
// func square(out, in *[5]uint64)
|
|
||||||
TEXT ·square(SB),7,$0-16
|
|
||||||
MOVQ out+0(FP), DI
|
|
||||||
MOVQ in+8(FP), SI
|
|
||||||
|
|
||||||
MOVQ 0(SI),AX
|
|
||||||
MULQ 0(SI)
|
|
||||||
MOVQ AX,CX
|
|
||||||
MOVQ DX,R8
|
|
||||||
MOVQ 0(SI),AX
|
|
||||||
SHLQ $1,AX
|
|
||||||
MULQ 8(SI)
|
|
||||||
MOVQ AX,R9
|
|
||||||
MOVQ DX,R10
|
|
||||||
MOVQ 0(SI),AX
|
|
||||||
SHLQ $1,AX
|
|
||||||
MULQ 16(SI)
|
|
||||||
MOVQ AX,R11
|
|
||||||
MOVQ DX,R12
|
|
||||||
MOVQ 0(SI),AX
|
|
||||||
SHLQ $1,AX
|
|
||||||
MULQ 24(SI)
|
|
||||||
MOVQ AX,R13
|
|
||||||
MOVQ DX,R14
|
|
||||||
MOVQ 0(SI),AX
|
|
||||||
SHLQ $1,AX
|
|
||||||
MULQ 32(SI)
|
|
||||||
MOVQ AX,R15
|
|
||||||
MOVQ DX,BX
|
|
||||||
MOVQ 8(SI),AX
|
|
||||||
MULQ 8(SI)
|
|
||||||
ADDQ AX,R11
|
|
||||||
ADCQ DX,R12
|
|
||||||
MOVQ 8(SI),AX
|
|
||||||
SHLQ $1,AX
|
|
||||||
MULQ 16(SI)
|
|
||||||
ADDQ AX,R13
|
|
||||||
ADCQ DX,R14
|
|
||||||
MOVQ 8(SI),AX
|
|
||||||
SHLQ $1,AX
|
|
||||||
MULQ 24(SI)
|
|
||||||
ADDQ AX,R15
|
|
||||||
ADCQ DX,BX
|
|
||||||
MOVQ 8(SI),DX
|
|
||||||
IMUL3Q $38,DX,AX
|
|
||||||
MULQ 32(SI)
|
|
||||||
ADDQ AX,CX
|
|
||||||
ADCQ DX,R8
|
|
||||||
MOVQ 16(SI),AX
|
|
||||||
MULQ 16(SI)
|
|
||||||
ADDQ AX,R15
|
|
||||||
ADCQ DX,BX
|
|
||||||
MOVQ 16(SI),DX
|
|
||||||
IMUL3Q $38,DX,AX
|
|
||||||
MULQ 24(SI)
|
|
||||||
ADDQ AX,CX
|
|
||||||
ADCQ DX,R8
|
|
||||||
MOVQ 16(SI),DX
|
|
||||||
IMUL3Q $38,DX,AX
|
|
||||||
MULQ 32(SI)
|
|
||||||
ADDQ AX,R9
|
|
||||||
ADCQ DX,R10
|
|
||||||
MOVQ 24(SI),DX
|
|
||||||
IMUL3Q $19,DX,AX
|
|
||||||
MULQ 24(SI)
|
|
||||||
ADDQ AX,R9
|
|
||||||
ADCQ DX,R10
|
|
||||||
MOVQ 24(SI),DX
|
|
||||||
IMUL3Q $38,DX,AX
|
|
||||||
MULQ 32(SI)
|
|
||||||
ADDQ AX,R11
|
|
||||||
ADCQ DX,R12
|
|
||||||
MOVQ 32(SI),DX
|
|
||||||
IMUL3Q $19,DX,AX
|
|
||||||
MULQ 32(SI)
|
|
||||||
ADDQ AX,R13
|
|
||||||
ADCQ DX,R14
|
|
||||||
MOVQ $REDMASK51,SI
|
|
||||||
SHLQ $13,CX,R8
|
|
||||||
ANDQ SI,CX
|
|
||||||
SHLQ $13,R9,R10
|
|
||||||
ANDQ SI,R9
|
|
||||||
ADDQ R8,R9
|
|
||||||
SHLQ $13,R11,R12
|
|
||||||
ANDQ SI,R11
|
|
||||||
ADDQ R10,R11
|
|
||||||
SHLQ $13,R13,R14
|
|
||||||
ANDQ SI,R13
|
|
||||||
ADDQ R12,R13
|
|
||||||
SHLQ $13,R15,BX
|
|
||||||
ANDQ SI,R15
|
|
||||||
ADDQ R14,R15
|
|
||||||
IMUL3Q $19,BX,DX
|
|
||||||
ADDQ DX,CX
|
|
||||||
MOVQ CX,DX
|
|
||||||
SHRQ $51,DX
|
|
||||||
ADDQ R9,DX
|
|
||||||
ANDQ SI,CX
|
|
||||||
MOVQ DX,R8
|
|
||||||
SHRQ $51,DX
|
|
||||||
ADDQ R11,DX
|
|
||||||
ANDQ SI,R8
|
|
||||||
MOVQ DX,R9
|
|
||||||
SHRQ $51,DX
|
|
||||||
ADDQ R13,DX
|
|
||||||
ANDQ SI,R9
|
|
||||||
MOVQ DX,AX
|
|
||||||
SHRQ $51,DX
|
|
||||||
ADDQ R15,DX
|
|
||||||
ANDQ SI,AX
|
|
||||||
MOVQ DX,R10
|
|
||||||
SHRQ $51,DX
|
|
||||||
IMUL3Q $19,DX,DX
|
|
||||||
ADDQ DX,CX
|
|
||||||
ANDQ SI,R10
|
|
||||||
MOVQ CX,0(DI)
|
|
||||||
MOVQ R8,8(DI)
|
|
||||||
MOVQ R9,16(DI)
|
|
||||||
MOVQ AX,24(DI)
|
|
||||||
MOVQ R10,32(DI)
|
|
||||||
RET
|
|
222
vendor/golang.org/x/crypto/ed25519/ed25519.go
generated
vendored
222
vendor/golang.org/x/crypto/ed25519/ed25519.go
generated
vendored
@ -1,222 +0,0 @@
|
|||||||
// Copyright 2016 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.
|
|
||||||
|
|
||||||
// In Go 1.13, the ed25519 package was promoted to the standard library as
|
|
||||||
// crypto/ed25519, and this package became a wrapper for the standard library one.
|
|
||||||
//
|
|
||||||
// +build !go1.13
|
|
||||||
|
|
||||||
// Package ed25519 implements the Ed25519 signature algorithm. See
|
|
||||||
// https://ed25519.cr.yp.to/.
|
|
||||||
//
|
|
||||||
// These functions are also compatible with the “Ed25519” function defined in
|
|
||||||
// RFC 8032. However, unlike RFC 8032's formulation, this package's private key
|
|
||||||
// representation includes a public key suffix to make multiple signing
|
|
||||||
// operations with the same key more efficient. This package refers to the RFC
|
|
||||||
// 8032 private key as the “seed”.
|
|
||||||
package ed25519
|
|
||||||
|
|
||||||
// This code is a port of the public domain, “ref10” implementation of ed25519
|
|
||||||
// from SUPERCOP.
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"crypto"
|
|
||||||
cryptorand "crypto/rand"
|
|
||||||
"crypto/sha512"
|
|
||||||
"errors"
|
|
||||||
"io"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"golang.org/x/crypto/ed25519/internal/edwards25519"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// PublicKeySize is the size, in bytes, of public keys as used in this package.
|
|
||||||
PublicKeySize = 32
|
|
||||||
// PrivateKeySize is the size, in bytes, of private keys as used in this package.
|
|
||||||
PrivateKeySize = 64
|
|
||||||
// SignatureSize is the size, in bytes, of signatures generated and verified by this package.
|
|
||||||
SignatureSize = 64
|
|
||||||
// SeedSize is the size, in bytes, of private key seeds. These are the private key representations used by RFC 8032.
|
|
||||||
SeedSize = 32
|
|
||||||
)
|
|
||||||
|
|
||||||
// PublicKey is the type of Ed25519 public keys.
|
|
||||||
type PublicKey []byte
|
|
||||||
|
|
||||||
// PrivateKey is the type of Ed25519 private keys. It implements crypto.Signer.
|
|
||||||
type PrivateKey []byte
|
|
||||||
|
|
||||||
// Public returns the PublicKey corresponding to priv.
|
|
||||||
func (priv PrivateKey) Public() crypto.PublicKey {
|
|
||||||
publicKey := make([]byte, PublicKeySize)
|
|
||||||
copy(publicKey, priv[32:])
|
|
||||||
return PublicKey(publicKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Seed returns the private key seed corresponding to priv. It is provided for
|
|
||||||
// interoperability with RFC 8032. RFC 8032's private keys correspond to seeds
|
|
||||||
// in this package.
|
|
||||||
func (priv PrivateKey) Seed() []byte {
|
|
||||||
seed := make([]byte, SeedSize)
|
|
||||||
copy(seed, priv[:32])
|
|
||||||
return seed
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sign signs the given message with priv.
|
|
||||||
// Ed25519 performs two passes over messages to be signed and therefore cannot
|
|
||||||
// handle pre-hashed messages. Thus opts.HashFunc() must return zero to
|
|
||||||
// indicate the message hasn't been hashed. This can be achieved by passing
|
|
||||||
// crypto.Hash(0) as the value for opts.
|
|
||||||
func (priv PrivateKey) Sign(rand io.Reader, message []byte, opts crypto.SignerOpts) (signature []byte, err error) {
|
|
||||||
if opts.HashFunc() != crypto.Hash(0) {
|
|
||||||
return nil, errors.New("ed25519: cannot sign hashed message")
|
|
||||||
}
|
|
||||||
|
|
||||||
return Sign(priv, message), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GenerateKey generates a public/private key pair using entropy from rand.
|
|
||||||
// If rand is nil, crypto/rand.Reader will be used.
|
|
||||||
func GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error) {
|
|
||||||
if rand == nil {
|
|
||||||
rand = cryptorand.Reader
|
|
||||||
}
|
|
||||||
|
|
||||||
seed := make([]byte, SeedSize)
|
|
||||||
if _, err := io.ReadFull(rand, seed); err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
privateKey := NewKeyFromSeed(seed)
|
|
||||||
publicKey := make([]byte, PublicKeySize)
|
|
||||||
copy(publicKey, privateKey[32:])
|
|
||||||
|
|
||||||
return publicKey, privateKey, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewKeyFromSeed calculates a private key from a seed. It will panic if
|
|
||||||
// len(seed) is not SeedSize. This function is provided for interoperability
|
|
||||||
// with RFC 8032. RFC 8032's private keys correspond to seeds in this
|
|
||||||
// package.
|
|
||||||
func NewKeyFromSeed(seed []byte) PrivateKey {
|
|
||||||
if l := len(seed); l != SeedSize {
|
|
||||||
panic("ed25519: bad seed length: " + strconv.Itoa(l))
|
|
||||||
}
|
|
||||||
|
|
||||||
digest := sha512.Sum512(seed)
|
|
||||||
digest[0] &= 248
|
|
||||||
digest[31] &= 127
|
|
||||||
digest[31] |= 64
|
|
||||||
|
|
||||||
var A edwards25519.ExtendedGroupElement
|
|
||||||
var hBytes [32]byte
|
|
||||||
copy(hBytes[:], digest[:])
|
|
||||||
edwards25519.GeScalarMultBase(&A, &hBytes)
|
|
||||||
var publicKeyBytes [32]byte
|
|
||||||
A.ToBytes(&publicKeyBytes)
|
|
||||||
|
|
||||||
privateKey := make([]byte, PrivateKeySize)
|
|
||||||
copy(privateKey, seed)
|
|
||||||
copy(privateKey[32:], publicKeyBytes[:])
|
|
||||||
|
|
||||||
return privateKey
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sign signs the message with privateKey and returns a signature. It will
|
|
||||||
// panic if len(privateKey) is not PrivateKeySize.
|
|
||||||
func Sign(privateKey PrivateKey, message []byte) []byte {
|
|
||||||
if l := len(privateKey); l != PrivateKeySize {
|
|
||||||
panic("ed25519: bad private key length: " + strconv.Itoa(l))
|
|
||||||
}
|
|
||||||
|
|
||||||
h := sha512.New()
|
|
||||||
h.Write(privateKey[:32])
|
|
||||||
|
|
||||||
var digest1, messageDigest, hramDigest [64]byte
|
|
||||||
var expandedSecretKey [32]byte
|
|
||||||
h.Sum(digest1[:0])
|
|
||||||
copy(expandedSecretKey[:], digest1[:])
|
|
||||||
expandedSecretKey[0] &= 248
|
|
||||||
expandedSecretKey[31] &= 63
|
|
||||||
expandedSecretKey[31] |= 64
|
|
||||||
|
|
||||||
h.Reset()
|
|
||||||
h.Write(digest1[32:])
|
|
||||||
h.Write(message)
|
|
||||||
h.Sum(messageDigest[:0])
|
|
||||||
|
|
||||||
var messageDigestReduced [32]byte
|
|
||||||
edwards25519.ScReduce(&messageDigestReduced, &messageDigest)
|
|
||||||
var R edwards25519.ExtendedGroupElement
|
|
||||||
edwards25519.GeScalarMultBase(&R, &messageDigestReduced)
|
|
||||||
|
|
||||||
var encodedR [32]byte
|
|
||||||
R.ToBytes(&encodedR)
|
|
||||||
|
|
||||||
h.Reset()
|
|
||||||
h.Write(encodedR[:])
|
|
||||||
h.Write(privateKey[32:])
|
|
||||||
h.Write(message)
|
|
||||||
h.Sum(hramDigest[:0])
|
|
||||||
var hramDigestReduced [32]byte
|
|
||||||
edwards25519.ScReduce(&hramDigestReduced, &hramDigest)
|
|
||||||
|
|
||||||
var s [32]byte
|
|
||||||
edwards25519.ScMulAdd(&s, &hramDigestReduced, &expandedSecretKey, &messageDigestReduced)
|
|
||||||
|
|
||||||
signature := make([]byte, SignatureSize)
|
|
||||||
copy(signature[:], encodedR[:])
|
|
||||||
copy(signature[32:], s[:])
|
|
||||||
|
|
||||||
return signature
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify reports whether sig is a valid signature of message by publicKey. It
|
|
||||||
// will panic if len(publicKey) is not PublicKeySize.
|
|
||||||
func Verify(publicKey PublicKey, message, sig []byte) bool {
|
|
||||||
if l := len(publicKey); l != PublicKeySize {
|
|
||||||
panic("ed25519: bad public key length: " + strconv.Itoa(l))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(sig) != SignatureSize || sig[63]&224 != 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
var A edwards25519.ExtendedGroupElement
|
|
||||||
var publicKeyBytes [32]byte
|
|
||||||
copy(publicKeyBytes[:], publicKey)
|
|
||||||
if !A.FromBytes(&publicKeyBytes) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
edwards25519.FeNeg(&A.X, &A.X)
|
|
||||||
edwards25519.FeNeg(&A.T, &A.T)
|
|
||||||
|
|
||||||
h := sha512.New()
|
|
||||||
h.Write(sig[:32])
|
|
||||||
h.Write(publicKey[:])
|
|
||||||
h.Write(message)
|
|
||||||
var digest [64]byte
|
|
||||||
h.Sum(digest[:0])
|
|
||||||
|
|
||||||
var hReduced [32]byte
|
|
||||||
edwards25519.ScReduce(&hReduced, &digest)
|
|
||||||
|
|
||||||
var R edwards25519.ProjectiveGroupElement
|
|
||||||
var s [32]byte
|
|
||||||
copy(s[:], sig[32:])
|
|
||||||
|
|
||||||
// https://tools.ietf.org/html/rfc8032#section-5.1.7 requires that s be in
|
|
||||||
// the range [0, order) in order to prevent signature malleability.
|
|
||||||
if !edwards25519.ScMinimal(&s) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
edwards25519.GeDoubleScalarMultVartime(&R, &hReduced, &A, &s)
|
|
||||||
|
|
||||||
var checkR [32]byte
|
|
||||||
R.ToBytes(&checkR)
|
|
||||||
return bytes.Equal(sig[:32], checkR[:])
|
|
||||||
}
|
|
73
vendor/golang.org/x/crypto/ed25519/ed25519_go113.go
generated
vendored
73
vendor/golang.org/x/crypto/ed25519/ed25519_go113.go
generated
vendored
@ -1,73 +0,0 @@
|
|||||||
// Copyright 2019 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.
|
|
||||||
|
|
||||||
// +build go1.13
|
|
||||||
|
|
||||||
// Package ed25519 implements the Ed25519 signature algorithm. See
|
|
||||||
// https://ed25519.cr.yp.to/.
|
|
||||||
//
|
|
||||||
// These functions are also compatible with the “Ed25519” function defined in
|
|
||||||
// RFC 8032. However, unlike RFC 8032's formulation, this package's private key
|
|
||||||
// representation includes a public key suffix to make multiple signing
|
|
||||||
// operations with the same key more efficient. This package refers to the RFC
|
|
||||||
// 8032 private key as the “seed”.
|
|
||||||
//
|
|
||||||
// Beginning with Go 1.13, the functionality of this package was moved to the
|
|
||||||
// standard library as crypto/ed25519. This package only acts as a compatibility
|
|
||||||
// wrapper.
|
|
||||||
package ed25519
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/ed25519"
|
|
||||||
"io"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// PublicKeySize is the size, in bytes, of public keys as used in this package.
|
|
||||||
PublicKeySize = 32
|
|
||||||
// PrivateKeySize is the size, in bytes, of private keys as used in this package.
|
|
||||||
PrivateKeySize = 64
|
|
||||||
// SignatureSize is the size, in bytes, of signatures generated and verified by this package.
|
|
||||||
SignatureSize = 64
|
|
||||||
// SeedSize is the size, in bytes, of private key seeds. These are the private key representations used by RFC 8032.
|
|
||||||
SeedSize = 32
|
|
||||||
)
|
|
||||||
|
|
||||||
// PublicKey is the type of Ed25519 public keys.
|
|
||||||
//
|
|
||||||
// This type is an alias for crypto/ed25519's PublicKey type.
|
|
||||||
// See the crypto/ed25519 package for the methods on this type.
|
|
||||||
type PublicKey = ed25519.PublicKey
|
|
||||||
|
|
||||||
// PrivateKey is the type of Ed25519 private keys. It implements crypto.Signer.
|
|
||||||
//
|
|
||||||
// This type is an alias for crypto/ed25519's PrivateKey type.
|
|
||||||
// See the crypto/ed25519 package for the methods on this type.
|
|
||||||
type PrivateKey = ed25519.PrivateKey
|
|
||||||
|
|
||||||
// GenerateKey generates a public/private key pair using entropy from rand.
|
|
||||||
// If rand is nil, crypto/rand.Reader will be used.
|
|
||||||
func GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error) {
|
|
||||||
return ed25519.GenerateKey(rand)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewKeyFromSeed calculates a private key from a seed. It will panic if
|
|
||||||
// len(seed) is not SeedSize. This function is provided for interoperability
|
|
||||||
// with RFC 8032. RFC 8032's private keys correspond to seeds in this
|
|
||||||
// package.
|
|
||||||
func NewKeyFromSeed(seed []byte) PrivateKey {
|
|
||||||
return ed25519.NewKeyFromSeed(seed)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sign signs the message with privateKey and returns a signature. It will
|
|
||||||
// panic if len(privateKey) is not PrivateKeySize.
|
|
||||||
func Sign(privateKey PrivateKey, message []byte) []byte {
|
|
||||||
return ed25519.Sign(privateKey, message)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify reports whether sig is a valid signature of message by publicKey. It
|
|
||||||
// will panic if len(publicKey) is not PublicKeySize.
|
|
||||||
func Verify(publicKey PublicKey, message, sig []byte) bool {
|
|
||||||
return ed25519.Verify(publicKey, message, sig)
|
|
||||||
}
|
|
1422
vendor/golang.org/x/crypto/ed25519/internal/edwards25519/const.go
generated
vendored
1422
vendor/golang.org/x/crypto/ed25519/internal/edwards25519/const.go
generated
vendored
File diff suppressed because it is too large
Load Diff
1793
vendor/golang.org/x/crypto/ed25519/internal/edwards25519/edwards25519.go
generated
vendored
1793
vendor/golang.org/x/crypto/ed25519/internal/edwards25519/edwards25519.go
generated
vendored
File diff suppressed because it is too large
Load Diff
308
vendor/golang.org/x/crypto/internal/chacha20/asm_arm64.s
generated
vendored
308
vendor/golang.org/x/crypto/internal/chacha20/asm_arm64.s
generated
vendored
@ -1,308 +0,0 @@
|
|||||||
// Copyright 2018 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.
|
|
||||||
|
|
||||||
// +build go1.11
|
|
||||||
// +build !gccgo,!appengine
|
|
||||||
|
|
||||||
#include "textflag.h"
|
|
||||||
|
|
||||||
#define NUM_ROUNDS 10
|
|
||||||
|
|
||||||
// func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32)
|
|
||||||
TEXT ·xorKeyStreamVX(SB), NOSPLIT, $0
|
|
||||||
MOVD dst+0(FP), R1
|
|
||||||
MOVD src+24(FP), R2
|
|
||||||
MOVD src_len+32(FP), R3
|
|
||||||
MOVD key+48(FP), R4
|
|
||||||
MOVD nonce+56(FP), R6
|
|
||||||
MOVD counter+64(FP), R7
|
|
||||||
|
|
||||||
MOVD $·constants(SB), R10
|
|
||||||
MOVD $·incRotMatrix(SB), R11
|
|
||||||
|
|
||||||
MOVW (R7), R20
|
|
||||||
|
|
||||||
AND $~255, R3, R13
|
|
||||||
ADD R2, R13, R12 // R12 for block end
|
|
||||||
AND $255, R3, R13
|
|
||||||
loop:
|
|
||||||
MOVD $NUM_ROUNDS, R21
|
|
||||||
VLD1 (R11), [V30.S4, V31.S4]
|
|
||||||
|
|
||||||
// load contants
|
|
||||||
// VLD4R (R10), [V0.S4, V1.S4, V2.S4, V3.S4]
|
|
||||||
WORD $0x4D60E940
|
|
||||||
|
|
||||||
// load keys
|
|
||||||
// VLD4R 16(R4), [V4.S4, V5.S4, V6.S4, V7.S4]
|
|
||||||
WORD $0x4DFFE884
|
|
||||||
// VLD4R 16(R4), [V8.S4, V9.S4, V10.S4, V11.S4]
|
|
||||||
WORD $0x4DFFE888
|
|
||||||
SUB $32, R4
|
|
||||||
|
|
||||||
// load counter + nonce
|
|
||||||
// VLD1R (R7), [V12.S4]
|
|
||||||
WORD $0x4D40C8EC
|
|
||||||
|
|
||||||
// VLD3R (R6), [V13.S4, V14.S4, V15.S4]
|
|
||||||
WORD $0x4D40E8CD
|
|
||||||
|
|
||||||
// update counter
|
|
||||||
VADD V30.S4, V12.S4, V12.S4
|
|
||||||
|
|
||||||
chacha:
|
|
||||||
// V0..V3 += V4..V7
|
|
||||||
// V12..V15 <<<= ((V12..V15 XOR V0..V3), 16)
|
|
||||||
VADD V0.S4, V4.S4, V0.S4
|
|
||||||
VADD V1.S4, V5.S4, V1.S4
|
|
||||||
VADD V2.S4, V6.S4, V2.S4
|
|
||||||
VADD V3.S4, V7.S4, V3.S4
|
|
||||||
VEOR V12.B16, V0.B16, V12.B16
|
|
||||||
VEOR V13.B16, V1.B16, V13.B16
|
|
||||||
VEOR V14.B16, V2.B16, V14.B16
|
|
||||||
VEOR V15.B16, V3.B16, V15.B16
|
|
||||||
VREV32 V12.H8, V12.H8
|
|
||||||
VREV32 V13.H8, V13.H8
|
|
||||||
VREV32 V14.H8, V14.H8
|
|
||||||
VREV32 V15.H8, V15.H8
|
|
||||||
// V8..V11 += V12..V15
|
|
||||||
// V4..V7 <<<= ((V4..V7 XOR V8..V11), 12)
|
|
||||||
VADD V8.S4, V12.S4, V8.S4
|
|
||||||
VADD V9.S4, V13.S4, V9.S4
|
|
||||||
VADD V10.S4, V14.S4, V10.S4
|
|
||||||
VADD V11.S4, V15.S4, V11.S4
|
|
||||||
VEOR V8.B16, V4.B16, V16.B16
|
|
||||||
VEOR V9.B16, V5.B16, V17.B16
|
|
||||||
VEOR V10.B16, V6.B16, V18.B16
|
|
||||||
VEOR V11.B16, V7.B16, V19.B16
|
|
||||||
VSHL $12, V16.S4, V4.S4
|
|
||||||
VSHL $12, V17.S4, V5.S4
|
|
||||||
VSHL $12, V18.S4, V6.S4
|
|
||||||
VSHL $12, V19.S4, V7.S4
|
|
||||||
VSRI $20, V16.S4, V4.S4
|
|
||||||
VSRI $20, V17.S4, V5.S4
|
|
||||||
VSRI $20, V18.S4, V6.S4
|
|
||||||
VSRI $20, V19.S4, V7.S4
|
|
||||||
|
|
||||||
// V0..V3 += V4..V7
|
|
||||||
// V12..V15 <<<= ((V12..V15 XOR V0..V3), 8)
|
|
||||||
VADD V0.S4, V4.S4, V0.S4
|
|
||||||
VADD V1.S4, V5.S4, V1.S4
|
|
||||||
VADD V2.S4, V6.S4, V2.S4
|
|
||||||
VADD V3.S4, V7.S4, V3.S4
|
|
||||||
VEOR V12.B16, V0.B16, V12.B16
|
|
||||||
VEOR V13.B16, V1.B16, V13.B16
|
|
||||||
VEOR V14.B16, V2.B16, V14.B16
|
|
||||||
VEOR V15.B16, V3.B16, V15.B16
|
|
||||||
VTBL V31.B16, [V12.B16], V12.B16
|
|
||||||
VTBL V31.B16, [V13.B16], V13.B16
|
|
||||||
VTBL V31.B16, [V14.B16], V14.B16
|
|
||||||
VTBL V31.B16, [V15.B16], V15.B16
|
|
||||||
|
|
||||||
// V8..V11 += V12..V15
|
|
||||||
// V4..V7 <<<= ((V4..V7 XOR V8..V11), 7)
|
|
||||||
VADD V12.S4, V8.S4, V8.S4
|
|
||||||
VADD V13.S4, V9.S4, V9.S4
|
|
||||||
VADD V14.S4, V10.S4, V10.S4
|
|
||||||
VADD V15.S4, V11.S4, V11.S4
|
|
||||||
VEOR V8.B16, V4.B16, V16.B16
|
|
||||||
VEOR V9.B16, V5.B16, V17.B16
|
|
||||||
VEOR V10.B16, V6.B16, V18.B16
|
|
||||||
VEOR V11.B16, V7.B16, V19.B16
|
|
||||||
VSHL $7, V16.S4, V4.S4
|
|
||||||
VSHL $7, V17.S4, V5.S4
|
|
||||||
VSHL $7, V18.S4, V6.S4
|
|
||||||
VSHL $7, V19.S4, V7.S4
|
|
||||||
VSRI $25, V16.S4, V4.S4
|
|
||||||
VSRI $25, V17.S4, V5.S4
|
|
||||||
VSRI $25, V18.S4, V6.S4
|
|
||||||
VSRI $25, V19.S4, V7.S4
|
|
||||||
|
|
||||||
// V0..V3 += V5..V7, V4
|
|
||||||
// V15,V12-V14 <<<= ((V15,V12-V14 XOR V0..V3), 16)
|
|
||||||
VADD V0.S4, V5.S4, V0.S4
|
|
||||||
VADD V1.S4, V6.S4, V1.S4
|
|
||||||
VADD V2.S4, V7.S4, V2.S4
|
|
||||||
VADD V3.S4, V4.S4, V3.S4
|
|
||||||
VEOR V15.B16, V0.B16, V15.B16
|
|
||||||
VEOR V12.B16, V1.B16, V12.B16
|
|
||||||
VEOR V13.B16, V2.B16, V13.B16
|
|
||||||
VEOR V14.B16, V3.B16, V14.B16
|
|
||||||
VREV32 V12.H8, V12.H8
|
|
||||||
VREV32 V13.H8, V13.H8
|
|
||||||
VREV32 V14.H8, V14.H8
|
|
||||||
VREV32 V15.H8, V15.H8
|
|
||||||
|
|
||||||
// V10 += V15; V5 <<<= ((V10 XOR V5), 12)
|
|
||||||
// ...
|
|
||||||
VADD V15.S4, V10.S4, V10.S4
|
|
||||||
VADD V12.S4, V11.S4, V11.S4
|
|
||||||
VADD V13.S4, V8.S4, V8.S4
|
|
||||||
VADD V14.S4, V9.S4, V9.S4
|
|
||||||
VEOR V10.B16, V5.B16, V16.B16
|
|
||||||
VEOR V11.B16, V6.B16, V17.B16
|
|
||||||
VEOR V8.B16, V7.B16, V18.B16
|
|
||||||
VEOR V9.B16, V4.B16, V19.B16
|
|
||||||
VSHL $12, V16.S4, V5.S4
|
|
||||||
VSHL $12, V17.S4, V6.S4
|
|
||||||
VSHL $12, V18.S4, V7.S4
|
|
||||||
VSHL $12, V19.S4, V4.S4
|
|
||||||
VSRI $20, V16.S4, V5.S4
|
|
||||||
VSRI $20, V17.S4, V6.S4
|
|
||||||
VSRI $20, V18.S4, V7.S4
|
|
||||||
VSRI $20, V19.S4, V4.S4
|
|
||||||
|
|
||||||
// V0 += V5; V15 <<<= ((V0 XOR V15), 8)
|
|
||||||
// ...
|
|
||||||
VADD V5.S4, V0.S4, V0.S4
|
|
||||||
VADD V6.S4, V1.S4, V1.S4
|
|
||||||
VADD V7.S4, V2.S4, V2.S4
|
|
||||||
VADD V4.S4, V3.S4, V3.S4
|
|
||||||
VEOR V0.B16, V15.B16, V15.B16
|
|
||||||
VEOR V1.B16, V12.B16, V12.B16
|
|
||||||
VEOR V2.B16, V13.B16, V13.B16
|
|
||||||
VEOR V3.B16, V14.B16, V14.B16
|
|
||||||
VTBL V31.B16, [V12.B16], V12.B16
|
|
||||||
VTBL V31.B16, [V13.B16], V13.B16
|
|
||||||
VTBL V31.B16, [V14.B16], V14.B16
|
|
||||||
VTBL V31.B16, [V15.B16], V15.B16
|
|
||||||
|
|
||||||
// V10 += V15; V5 <<<= ((V10 XOR V5), 7)
|
|
||||||
// ...
|
|
||||||
VADD V15.S4, V10.S4, V10.S4
|
|
||||||
VADD V12.S4, V11.S4, V11.S4
|
|
||||||
VADD V13.S4, V8.S4, V8.S4
|
|
||||||
VADD V14.S4, V9.S4, V9.S4
|
|
||||||
VEOR V10.B16, V5.B16, V16.B16
|
|
||||||
VEOR V11.B16, V6.B16, V17.B16
|
|
||||||
VEOR V8.B16, V7.B16, V18.B16
|
|
||||||
VEOR V9.B16, V4.B16, V19.B16
|
|
||||||
VSHL $7, V16.S4, V5.S4
|
|
||||||
VSHL $7, V17.S4, V6.S4
|
|
||||||
VSHL $7, V18.S4, V7.S4
|
|
||||||
VSHL $7, V19.S4, V4.S4
|
|
||||||
VSRI $25, V16.S4, V5.S4
|
|
||||||
VSRI $25, V17.S4, V6.S4
|
|
||||||
VSRI $25, V18.S4, V7.S4
|
|
||||||
VSRI $25, V19.S4, V4.S4
|
|
||||||
|
|
||||||
SUB $1, R21
|
|
||||||
CBNZ R21, chacha
|
|
||||||
|
|
||||||
// VLD4R (R10), [V16.S4, V17.S4, V18.S4, V19.S4]
|
|
||||||
WORD $0x4D60E950
|
|
||||||
|
|
||||||
// VLD4R 16(R4), [V20.S4, V21.S4, V22.S4, V23.S4]
|
|
||||||
WORD $0x4DFFE894
|
|
||||||
VADD V30.S4, V12.S4, V12.S4
|
|
||||||
VADD V16.S4, V0.S4, V0.S4
|
|
||||||
VADD V17.S4, V1.S4, V1.S4
|
|
||||||
VADD V18.S4, V2.S4, V2.S4
|
|
||||||
VADD V19.S4, V3.S4, V3.S4
|
|
||||||
// VLD4R 16(R4), [V24.S4, V25.S4, V26.S4, V27.S4]
|
|
||||||
WORD $0x4DFFE898
|
|
||||||
// restore R4
|
|
||||||
SUB $32, R4
|
|
||||||
|
|
||||||
// load counter + nonce
|
|
||||||
// VLD1R (R7), [V28.S4]
|
|
||||||
WORD $0x4D40C8FC
|
|
||||||
// VLD3R (R6), [V29.S4, V30.S4, V31.S4]
|
|
||||||
WORD $0x4D40E8DD
|
|
||||||
|
|
||||||
VADD V20.S4, V4.S4, V4.S4
|
|
||||||
VADD V21.S4, V5.S4, V5.S4
|
|
||||||
VADD V22.S4, V6.S4, V6.S4
|
|
||||||
VADD V23.S4, V7.S4, V7.S4
|
|
||||||
VADD V24.S4, V8.S4, V8.S4
|
|
||||||
VADD V25.S4, V9.S4, V9.S4
|
|
||||||
VADD V26.S4, V10.S4, V10.S4
|
|
||||||
VADD V27.S4, V11.S4, V11.S4
|
|
||||||
VADD V28.S4, V12.S4, V12.S4
|
|
||||||
VADD V29.S4, V13.S4, V13.S4
|
|
||||||
VADD V30.S4, V14.S4, V14.S4
|
|
||||||
VADD V31.S4, V15.S4, V15.S4
|
|
||||||
|
|
||||||
VZIP1 V1.S4, V0.S4, V16.S4
|
|
||||||
VZIP2 V1.S4, V0.S4, V17.S4
|
|
||||||
VZIP1 V3.S4, V2.S4, V18.S4
|
|
||||||
VZIP2 V3.S4, V2.S4, V19.S4
|
|
||||||
VZIP1 V5.S4, V4.S4, V20.S4
|
|
||||||
VZIP2 V5.S4, V4.S4, V21.S4
|
|
||||||
VZIP1 V7.S4, V6.S4, V22.S4
|
|
||||||
VZIP2 V7.S4, V6.S4, V23.S4
|
|
||||||
VZIP1 V9.S4, V8.S4, V24.S4
|
|
||||||
VZIP2 V9.S4, V8.S4, V25.S4
|
|
||||||
VZIP1 V11.S4, V10.S4, V26.S4
|
|
||||||
VZIP2 V11.S4, V10.S4, V27.S4
|
|
||||||
VZIP1 V13.S4, V12.S4, V28.S4
|
|
||||||
VZIP2 V13.S4, V12.S4, V29.S4
|
|
||||||
VZIP1 V15.S4, V14.S4, V30.S4
|
|
||||||
VZIP2 V15.S4, V14.S4, V31.S4
|
|
||||||
VZIP1 V18.D2, V16.D2, V0.D2
|
|
||||||
VZIP2 V18.D2, V16.D2, V4.D2
|
|
||||||
VZIP1 V19.D2, V17.D2, V8.D2
|
|
||||||
VZIP2 V19.D2, V17.D2, V12.D2
|
|
||||||
VLD1.P 64(R2), [V16.B16, V17.B16, V18.B16, V19.B16]
|
|
||||||
|
|
||||||
VZIP1 V22.D2, V20.D2, V1.D2
|
|
||||||
VZIP2 V22.D2, V20.D2, V5.D2
|
|
||||||
VZIP1 V23.D2, V21.D2, V9.D2
|
|
||||||
VZIP2 V23.D2, V21.D2, V13.D2
|
|
||||||
VLD1.P 64(R2), [V20.B16, V21.B16, V22.B16, V23.B16]
|
|
||||||
VZIP1 V26.D2, V24.D2, V2.D2
|
|
||||||
VZIP2 V26.D2, V24.D2, V6.D2
|
|
||||||
VZIP1 V27.D2, V25.D2, V10.D2
|
|
||||||
VZIP2 V27.D2, V25.D2, V14.D2
|
|
||||||
VLD1.P 64(R2), [V24.B16, V25.B16, V26.B16, V27.B16]
|
|
||||||
VZIP1 V30.D2, V28.D2, V3.D2
|
|
||||||
VZIP2 V30.D2, V28.D2, V7.D2
|
|
||||||
VZIP1 V31.D2, V29.D2, V11.D2
|
|
||||||
VZIP2 V31.D2, V29.D2, V15.D2
|
|
||||||
VLD1.P 64(R2), [V28.B16, V29.B16, V30.B16, V31.B16]
|
|
||||||
VEOR V0.B16, V16.B16, V16.B16
|
|
||||||
VEOR V1.B16, V17.B16, V17.B16
|
|
||||||
VEOR V2.B16, V18.B16, V18.B16
|
|
||||||
VEOR V3.B16, V19.B16, V19.B16
|
|
||||||
VST1.P [V16.B16, V17.B16, V18.B16, V19.B16], 64(R1)
|
|
||||||
VEOR V4.B16, V20.B16, V20.B16
|
|
||||||
VEOR V5.B16, V21.B16, V21.B16
|
|
||||||
VEOR V6.B16, V22.B16, V22.B16
|
|
||||||
VEOR V7.B16, V23.B16, V23.B16
|
|
||||||
VST1.P [V20.B16, V21.B16, V22.B16, V23.B16], 64(R1)
|
|
||||||
VEOR V8.B16, V24.B16, V24.B16
|
|
||||||
VEOR V9.B16, V25.B16, V25.B16
|
|
||||||
VEOR V10.B16, V26.B16, V26.B16
|
|
||||||
VEOR V11.B16, V27.B16, V27.B16
|
|
||||||
VST1.P [V24.B16, V25.B16, V26.B16, V27.B16], 64(R1)
|
|
||||||
VEOR V12.B16, V28.B16, V28.B16
|
|
||||||
VEOR V13.B16, V29.B16, V29.B16
|
|
||||||
VEOR V14.B16, V30.B16, V30.B16
|
|
||||||
VEOR V15.B16, V31.B16, V31.B16
|
|
||||||
VST1.P [V28.B16, V29.B16, V30.B16, V31.B16], 64(R1)
|
|
||||||
|
|
||||||
ADD $4, R20
|
|
||||||
MOVW R20, (R7) // update counter
|
|
||||||
|
|
||||||
CMP R2, R12
|
|
||||||
BGT loop
|
|
||||||
|
|
||||||
RET
|
|
||||||
|
|
||||||
|
|
||||||
DATA ·constants+0x00(SB)/4, $0x61707865
|
|
||||||
DATA ·constants+0x04(SB)/4, $0x3320646e
|
|
||||||
DATA ·constants+0x08(SB)/4, $0x79622d32
|
|
||||||
DATA ·constants+0x0c(SB)/4, $0x6b206574
|
|
||||||
GLOBL ·constants(SB), NOPTR|RODATA, $32
|
|
||||||
|
|
||||||
DATA ·incRotMatrix+0x00(SB)/4, $0x00000000
|
|
||||||
DATA ·incRotMatrix+0x04(SB)/4, $0x00000001
|
|
||||||
DATA ·incRotMatrix+0x08(SB)/4, $0x00000002
|
|
||||||
DATA ·incRotMatrix+0x0c(SB)/4, $0x00000003
|
|
||||||
DATA ·incRotMatrix+0x10(SB)/4, $0x02010003
|
|
||||||
DATA ·incRotMatrix+0x14(SB)/4, $0x06050407
|
|
||||||
DATA ·incRotMatrix+0x18(SB)/4, $0x0A09080B
|
|
||||||
DATA ·incRotMatrix+0x1c(SB)/4, $0x0E0D0C0F
|
|
||||||
GLOBL ·incRotMatrix(SB), NOPTR|RODATA, $32
|
|
668
vendor/golang.org/x/crypto/internal/chacha20/asm_ppc64le.s
generated
vendored
668
vendor/golang.org/x/crypto/internal/chacha20/asm_ppc64le.s
generated
vendored
@ -1,668 +0,0 @@
|
|||||||
// Copyright 2019 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.
|
|
||||||
|
|
||||||
// Based on CRYPTOGAMS code with the following comment:
|
|
||||||
// # ====================================================================
|
|
||||||
// # Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
|
|
||||||
// # project. The module is, however, dual licensed under OpenSSL and
|
|
||||||
// # CRYPTOGAMS licenses depending on where you obtain it. For further
|
|
||||||
// # details see http://www.openssl.org/~appro/cryptogams/.
|
|
||||||
// # ====================================================================
|
|
||||||
|
|
||||||
// Original code can be found at the link below:
|
|
||||||
// https://github.com/dot-asm/cryptogams/commit/a60f5b50ed908e91e5c39ca79126a4a876d5d8ff
|
|
||||||
|
|
||||||
// There are some differences between CRYPTOGAMS code and this one. The round
|
|
||||||
// loop for "_int" isn't the same as the original. Some adjustments were
|
|
||||||
// necessary because there are less vector registers available. For example, some
|
|
||||||
// X variables (r12, r13, r14, and r15) share the same register used by the
|
|
||||||
// counter. The original code uses ctr to name the counter. Here we use CNT
|
|
||||||
// because golang uses CTR as the counter register name.
|
|
||||||
|
|
||||||
// +build ppc64le,!gccgo,!appengine
|
|
||||||
|
|
||||||
#include "textflag.h"
|
|
||||||
|
|
||||||
#define OUT R3
|
|
||||||
#define INP R4
|
|
||||||
#define LEN R5
|
|
||||||
#define KEY R6
|
|
||||||
#define CNT R7
|
|
||||||
|
|
||||||
#define TEMP R8
|
|
||||||
|
|
||||||
#define X0 R11
|
|
||||||
#define X1 R12
|
|
||||||
#define X2 R14
|
|
||||||
#define X3 R15
|
|
||||||
#define X4 R16
|
|
||||||
#define X5 R17
|
|
||||||
#define X6 R18
|
|
||||||
#define X7 R19
|
|
||||||
#define X8 R20
|
|
||||||
#define X9 R21
|
|
||||||
#define X10 R22
|
|
||||||
#define X11 R23
|
|
||||||
#define X12 R24
|
|
||||||
#define X13 R25
|
|
||||||
#define X14 R26
|
|
||||||
#define X15 R27
|
|
||||||
|
|
||||||
#define CON0 X0
|
|
||||||
#define CON1 X1
|
|
||||||
#define CON2 X2
|
|
||||||
#define CON3 X3
|
|
||||||
|
|
||||||
#define KEY0 X4
|
|
||||||
#define KEY1 X5
|
|
||||||
#define KEY2 X6
|
|
||||||
#define KEY3 X7
|
|
||||||
#define KEY4 X8
|
|
||||||
#define KEY5 X9
|
|
||||||
#define KEY6 X10
|
|
||||||
#define KEY7 X11
|
|
||||||
|
|
||||||
#define CNT0 X12
|
|
||||||
#define CNT1 X13
|
|
||||||
#define CNT2 X14
|
|
||||||
#define CNT3 X15
|
|
||||||
|
|
||||||
#define TMP0 R9
|
|
||||||
#define TMP1 R10
|
|
||||||
#define TMP2 R28
|
|
||||||
#define TMP3 R29
|
|
||||||
|
|
||||||
#define CONSTS R8
|
|
||||||
|
|
||||||
#define A0 V0
|
|
||||||
#define B0 V1
|
|
||||||
#define C0 V2
|
|
||||||
#define D0 V3
|
|
||||||
#define A1 V4
|
|
||||||
#define B1 V5
|
|
||||||
#define C1 V6
|
|
||||||
#define D1 V7
|
|
||||||
#define A2 V8
|
|
||||||
#define B2 V9
|
|
||||||
#define C2 V10
|
|
||||||
#define D2 V11
|
|
||||||
#define T0 V12
|
|
||||||
#define T1 V13
|
|
||||||
#define T2 V14
|
|
||||||
|
|
||||||
#define K0 V15
|
|
||||||
#define K1 V16
|
|
||||||
#define K2 V17
|
|
||||||
#define K3 V18
|
|
||||||
#define K4 V19
|
|
||||||
#define K5 V20
|
|
||||||
|
|
||||||
#define FOUR V21
|
|
||||||
#define SIXTEEN V22
|
|
||||||
#define TWENTY4 V23
|
|
||||||
#define TWENTY V24
|
|
||||||
#define TWELVE V25
|
|
||||||
#define TWENTY5 V26
|
|
||||||
#define SEVEN V27
|
|
||||||
|
|
||||||
#define INPPERM V28
|
|
||||||
#define OUTPERM V29
|
|
||||||
#define OUTMASK V30
|
|
||||||
|
|
||||||
#define DD0 V31
|
|
||||||
#define DD1 SEVEN
|
|
||||||
#define DD2 T0
|
|
||||||
#define DD3 T1
|
|
||||||
#define DD4 T2
|
|
||||||
|
|
||||||
DATA ·consts+0x00(SB)/8, $0x3320646e61707865
|
|
||||||
DATA ·consts+0x08(SB)/8, $0x6b20657479622d32
|
|
||||||
DATA ·consts+0x10(SB)/8, $0x0000000000000001
|
|
||||||
DATA ·consts+0x18(SB)/8, $0x0000000000000000
|
|
||||||
DATA ·consts+0x20(SB)/8, $0x0000000000000004
|
|
||||||
DATA ·consts+0x28(SB)/8, $0x0000000000000000
|
|
||||||
DATA ·consts+0x30(SB)/8, $0x0a0b08090e0f0c0d
|
|
||||||
DATA ·consts+0x38(SB)/8, $0x0203000106070405
|
|
||||||
DATA ·consts+0x40(SB)/8, $0x090a0b080d0e0f0c
|
|
||||||
DATA ·consts+0x48(SB)/8, $0x0102030005060704
|
|
||||||
GLOBL ·consts(SB), RODATA, $80
|
|
||||||
|
|
||||||
//func chaCha20_ctr32_vmx(out, inp *byte, len int, key *[32]byte, counter *[16]byte)
|
|
||||||
TEXT ·chaCha20_ctr32_vmx(SB),NOSPLIT|NOFRAME,$0
|
|
||||||
// Load the arguments inside the registers
|
|
||||||
MOVD out+0(FP), OUT
|
|
||||||
MOVD inp+8(FP), INP
|
|
||||||
MOVD len+16(FP), LEN
|
|
||||||
MOVD key+24(FP), KEY
|
|
||||||
MOVD counter+32(FP), CNT
|
|
||||||
|
|
||||||
MOVD $·consts(SB), CONSTS // point to consts addr
|
|
||||||
|
|
||||||
MOVD $16, X0
|
|
||||||
MOVD $32, X1
|
|
||||||
MOVD $48, X2
|
|
||||||
MOVD $64, X3
|
|
||||||
MOVD $31, X4
|
|
||||||
MOVD $15, X5
|
|
||||||
|
|
||||||
// Load key
|
|
||||||
LVX (KEY)(R0), K1
|
|
||||||
LVSR (KEY)(R0), T0
|
|
||||||
LVX (KEY)(X0), K2
|
|
||||||
LVX (KEY)(X4), DD0
|
|
||||||
|
|
||||||
// Load counter
|
|
||||||
LVX (CNT)(R0), K3
|
|
||||||
LVSR (CNT)(R0), T1
|
|
||||||
LVX (CNT)(X5), DD1
|
|
||||||
|
|
||||||
// Load constants
|
|
||||||
LVX (CONSTS)(R0), K0
|
|
||||||
LVX (CONSTS)(X0), K5
|
|
||||||
LVX (CONSTS)(X1), FOUR
|
|
||||||
LVX (CONSTS)(X2), SIXTEEN
|
|
||||||
LVX (CONSTS)(X3), TWENTY4
|
|
||||||
|
|
||||||
// Align key and counter
|
|
||||||
VPERM K2, K1, T0, K1
|
|
||||||
VPERM DD0, K2, T0, K2
|
|
||||||
VPERM DD1, K3, T1, K3
|
|
||||||
|
|
||||||
// Load counter to GPR
|
|
||||||
MOVWZ 0(CNT), CNT0
|
|
||||||
MOVWZ 4(CNT), CNT1
|
|
||||||
MOVWZ 8(CNT), CNT2
|
|
||||||
MOVWZ 12(CNT), CNT3
|
|
||||||
|
|
||||||
// Adjust vectors for the initial state
|
|
||||||
VADDUWM K3, K5, K3
|
|
||||||
VADDUWM K3, K5, K4
|
|
||||||
VADDUWM K4, K5, K5
|
|
||||||
|
|
||||||
// Synthesized constants
|
|
||||||
VSPLTISW $-12, TWENTY
|
|
||||||
VSPLTISW $12, TWELVE
|
|
||||||
VSPLTISW $-7, TWENTY5
|
|
||||||
|
|
||||||
VXOR T0, T0, T0
|
|
||||||
VSPLTISW $-1, OUTMASK
|
|
||||||
LVSR (INP)(R0), INPPERM
|
|
||||||
LVSL (OUT)(R0), OUTPERM
|
|
||||||
VPERM OUTMASK, T0, OUTPERM, OUTMASK
|
|
||||||
|
|
||||||
loop_outer_vmx:
|
|
||||||
// Load constant
|
|
||||||
MOVD $0x61707865, CON0
|
|
||||||
MOVD $0x3320646e, CON1
|
|
||||||
MOVD $0x79622d32, CON2
|
|
||||||
MOVD $0x6b206574, CON3
|
|
||||||
|
|
||||||
VOR K0, K0, A0
|
|
||||||
VOR K0, K0, A1
|
|
||||||
VOR K0, K0, A2
|
|
||||||
VOR K1, K1, B0
|
|
||||||
|
|
||||||
MOVD $10, TEMP
|
|
||||||
|
|
||||||
// Load key to GPR
|
|
||||||
MOVWZ 0(KEY), X4
|
|
||||||
MOVWZ 4(KEY), X5
|
|
||||||
MOVWZ 8(KEY), X6
|
|
||||||
MOVWZ 12(KEY), X7
|
|
||||||
VOR K1, K1, B1
|
|
||||||
VOR K1, K1, B2
|
|
||||||
MOVWZ 16(KEY), X8
|
|
||||||
MOVWZ 0(CNT), X12
|
|
||||||
MOVWZ 20(KEY), X9
|
|
||||||
MOVWZ 4(CNT), X13
|
|
||||||
VOR K2, K2, C0
|
|
||||||
VOR K2, K2, C1
|
|
||||||
MOVWZ 24(KEY), X10
|
|
||||||
MOVWZ 8(CNT), X14
|
|
||||||
VOR K2, K2, C2
|
|
||||||
VOR K3, K3, D0
|
|
||||||
MOVWZ 28(KEY), X11
|
|
||||||
MOVWZ 12(CNT), X15
|
|
||||||
VOR K4, K4, D1
|
|
||||||
VOR K5, K5, D2
|
|
||||||
|
|
||||||
MOVD X4, TMP0
|
|
||||||
MOVD X5, TMP1
|
|
||||||
MOVD X6, TMP2
|
|
||||||
MOVD X7, TMP3
|
|
||||||
VSPLTISW $7, SEVEN
|
|
||||||
|
|
||||||
MOVD TEMP, CTR
|
|
||||||
|
|
||||||
loop_vmx:
|
|
||||||
// CRYPTOGAMS uses a macro to create a loop using perl. This isn't possible
|
|
||||||
// using assembly macros. Therefore, the macro expansion result was used
|
|
||||||
// in order to maintain the algorithm efficiency.
|
|
||||||
// This loop generates three keystream blocks using VMX instructions and,
|
|
||||||
// in parallel, one keystream block using scalar instructions.
|
|
||||||
ADD X4, X0, X0
|
|
||||||
ADD X5, X1, X1
|
|
||||||
VADDUWM A0, B0, A0
|
|
||||||
VADDUWM A1, B1, A1
|
|
||||||
ADD X6, X2, X2
|
|
||||||
ADD X7, X3, X3
|
|
||||||
VADDUWM A2, B2, A2
|
|
||||||
VXOR D0, A0, D0
|
|
||||||
XOR X0, X12, X12
|
|
||||||
XOR X1, X13, X13
|
|
||||||
VXOR D1, A1, D1
|
|
||||||
VXOR D2, A2, D2
|
|
||||||
XOR X2, X14, X14
|
|
||||||
XOR X3, X15, X15
|
|
||||||
VPERM D0, D0, SIXTEEN, D0
|
|
||||||
VPERM D1, D1, SIXTEEN, D1
|
|
||||||
ROTLW $16, X12, X12
|
|
||||||
ROTLW $16, X13, X13
|
|
||||||
VPERM D2, D2, SIXTEEN, D2
|
|
||||||
VADDUWM C0, D0, C0
|
|
||||||
ROTLW $16, X14, X14
|
|
||||||
ROTLW $16, X15, X15
|
|
||||||
VADDUWM C1, D1, C1
|
|
||||||
VADDUWM C2, D2, C2
|
|
||||||
ADD X12, X8, X8
|
|
||||||
ADD X13, X9, X9
|
|
||||||
VXOR B0, C0, T0
|
|
||||||
VXOR B1, C1, T1
|
|
||||||
ADD X14, X10, X10
|
|
||||||
ADD X15, X11, X11
|
|
||||||
VXOR B2, C2, T2
|
|
||||||
VRLW T0, TWELVE, B0
|
|
||||||
XOR X8, X4, X4
|
|
||||||
XOR X9, X5, X5
|
|
||||||
VRLW T1, TWELVE, B1
|
|
||||||
VRLW T2, TWELVE, B2
|
|
||||||
XOR X10, X6, X6
|
|
||||||
XOR X11, X7, X7
|
|
||||||
VADDUWM A0, B0, A0
|
|
||||||
VADDUWM A1, B1, A1
|
|
||||||
ROTLW $12, X4, X4
|
|
||||||
ROTLW $12, X5, X5
|
|
||||||
VADDUWM A2, B2, A2
|
|
||||||
VXOR D0, A0, D0
|
|
||||||
ROTLW $12, X6, X6
|
|
||||||
ROTLW $12, X7, X7
|
|
||||||
VXOR D1, A1, D1
|
|
||||||
VXOR D2, A2, D2
|
|
||||||
ADD X4, X0, X0
|
|
||||||
ADD X5, X1, X1
|
|
||||||
VPERM D0, D0, TWENTY4, D0
|
|
||||||
VPERM D1, D1, TWENTY4, D1
|
|
||||||
ADD X6, X2, X2
|
|
||||||
ADD X7, X3, X3
|
|
||||||
VPERM D2, D2, TWENTY4, D2
|
|
||||||
VADDUWM C0, D0, C0
|
|
||||||
XOR X0, X12, X12
|
|
||||||
XOR X1, X13, X13
|
|
||||||
VADDUWM C1, D1, C1
|
|
||||||
VADDUWM C2, D2, C2
|
|
||||||
XOR X2, X14, X14
|
|
||||||
XOR X3, X15, X15
|
|
||||||
VXOR B0, C0, T0
|
|
||||||
VXOR B1, C1, T1
|
|
||||||
ROTLW $8, X12, X12
|
|
||||||
ROTLW $8, X13, X13
|
|
||||||
VXOR B2, C2, T2
|
|
||||||
VRLW T0, SEVEN, B0
|
|
||||||
ROTLW $8, X14, X14
|
|
||||||
ROTLW $8, X15, X15
|
|
||||||
VRLW T1, SEVEN, B1
|
|
||||||
VRLW T2, SEVEN, B2
|
|
||||||
ADD X12, X8, X8
|
|
||||||
ADD X13, X9, X9
|
|
||||||
VSLDOI $8, C0, C0, C0
|
|
||||||
VSLDOI $8, C1, C1, C1
|
|
||||||
ADD X14, X10, X10
|
|
||||||
ADD X15, X11, X11
|
|
||||||
VSLDOI $8, C2, C2, C2
|
|
||||||
VSLDOI $12, B0, B0, B0
|
|
||||||
XOR X8, X4, X4
|
|
||||||
XOR X9, X5, X5
|
|
||||||
VSLDOI $12, B1, B1, B1
|
|
||||||
VSLDOI $12, B2, B2, B2
|
|
||||||
XOR X10, X6, X6
|
|
||||||
XOR X11, X7, X7
|
|
||||||
VSLDOI $4, D0, D0, D0
|
|
||||||
VSLDOI $4, D1, D1, D1
|
|
||||||
ROTLW $7, X4, X4
|
|
||||||
ROTLW $7, X5, X5
|
|
||||||
VSLDOI $4, D2, D2, D2
|
|
||||||
VADDUWM A0, B0, A0
|
|
||||||
ROTLW $7, X6, X6
|
|
||||||
ROTLW $7, X7, X7
|
|
||||||
VADDUWM A1, B1, A1
|
|
||||||
VADDUWM A2, B2, A2
|
|
||||||
ADD X5, X0, X0
|
|
||||||
ADD X6, X1, X1
|
|
||||||
VXOR D0, A0, D0
|
|
||||||
VXOR D1, A1, D1
|
|
||||||
ADD X7, X2, X2
|
|
||||||
ADD X4, X3, X3
|
|
||||||
VXOR D2, A2, D2
|
|
||||||
VPERM D0, D0, SIXTEEN, D0
|
|
||||||
XOR X0, X15, X15
|
|
||||||
XOR X1, X12, X12
|
|
||||||
VPERM D1, D1, SIXTEEN, D1
|
|
||||||
VPERM D2, D2, SIXTEEN, D2
|
|
||||||
XOR X2, X13, X13
|
|
||||||
XOR X3, X14, X14
|
|
||||||
VADDUWM C0, D0, C0
|
|
||||||
VADDUWM C1, D1, C1
|
|
||||||
ROTLW $16, X15, X15
|
|
||||||
ROTLW $16, X12, X12
|
|
||||||
VADDUWM C2, D2, C2
|
|
||||||
VXOR B0, C0, T0
|
|
||||||
ROTLW $16, X13, X13
|
|
||||||
ROTLW $16, X14, X14
|
|
||||||
VXOR B1, C1, T1
|
|
||||||
VXOR B2, C2, T2
|
|
||||||
ADD X15, X10, X10
|
|
||||||
ADD X12, X11, X11
|
|
||||||
VRLW T0, TWELVE, B0
|
|
||||||
VRLW T1, TWELVE, B1
|
|
||||||
ADD X13, X8, X8
|
|
||||||
ADD X14, X9, X9
|
|
||||||
VRLW T2, TWELVE, B2
|
|
||||||
VADDUWM A0, B0, A0
|
|
||||||
XOR X10, X5, X5
|
|
||||||
XOR X11, X6, X6
|
|
||||||
VADDUWM A1, B1, A1
|
|
||||||
VADDUWM A2, B2, A2
|
|
||||||
XOR X8, X7, X7
|
|
||||||
XOR X9, X4, X4
|
|
||||||
VXOR D0, A0, D0
|
|
||||||
VXOR D1, A1, D1
|
|
||||||
ROTLW $12, X5, X5
|
|
||||||
ROTLW $12, X6, X6
|
|
||||||
VXOR D2, A2, D2
|
|
||||||
VPERM D0, D0, TWENTY4, D0
|
|
||||||
ROTLW $12, X7, X7
|
|
||||||
ROTLW $12, X4, X4
|
|
||||||
VPERM D1, D1, TWENTY4, D1
|
|
||||||
VPERM D2, D2, TWENTY4, D2
|
|
||||||
ADD X5, X0, X0
|
|
||||||
ADD X6, X1, X1
|
|
||||||
VADDUWM C0, D0, C0
|
|
||||||
VADDUWM C1, D1, C1
|
|
||||||
ADD X7, X2, X2
|
|
||||||
ADD X4, X3, X3
|
|
||||||
VADDUWM C2, D2, C2
|
|
||||||
VXOR B0, C0, T0
|
|
||||||
XOR X0, X15, X15
|
|
||||||
XOR X1, X12, X12
|
|
||||||
VXOR B1, C1, T1
|
|
||||||
VXOR B2, C2, T2
|
|
||||||
XOR X2, X13, X13
|
|
||||||
XOR X3, X14, X14
|
|
||||||
VRLW T0, SEVEN, B0
|
|
||||||
VRLW T1, SEVEN, B1
|
|
||||||
ROTLW $8, X15, X15
|
|
||||||
ROTLW $8, X12, X12
|
|
||||||
VRLW T2, SEVEN, B2
|
|
||||||
VSLDOI $8, C0, C0, C0
|
|
||||||
ROTLW $8, X13, X13
|
|
||||||
ROTLW $8, X14, X14
|
|
||||||
VSLDOI $8, C1, C1, C1
|
|
||||||
VSLDOI $8, C2, C2, C2
|
|
||||||
ADD X15, X10, X10
|
|
||||||
ADD X12, X11, X11
|
|
||||||
VSLDOI $4, B0, B0, B0
|
|
||||||
VSLDOI $4, B1, B1, B1
|
|
||||||
ADD X13, X8, X8
|
|
||||||
ADD X14, X9, X9
|
|
||||||
VSLDOI $4, B2, B2, B2
|
|
||||||
VSLDOI $12, D0, D0, D0
|
|
||||||
XOR X10, X5, X5
|
|
||||||
XOR X11, X6, X6
|
|
||||||
VSLDOI $12, D1, D1, D1
|
|
||||||
VSLDOI $12, D2, D2, D2
|
|
||||||
XOR X8, X7, X7
|
|
||||||
XOR X9, X4, X4
|
|
||||||
ROTLW $7, X5, X5
|
|
||||||
ROTLW $7, X6, X6
|
|
||||||
ROTLW $7, X7, X7
|
|
||||||
ROTLW $7, X4, X4
|
|
||||||
BC 0x10, 0, loop_vmx
|
|
||||||
|
|
||||||
SUB $256, LEN, LEN
|
|
||||||
|
|
||||||
// Accumulate key block
|
|
||||||
ADD $0x61707865, X0, X0
|
|
||||||
ADD $0x3320646e, X1, X1
|
|
||||||
ADD $0x79622d32, X2, X2
|
|
||||||
ADD $0x6b206574, X3, X3
|
|
||||||
ADD TMP0, X4, X4
|
|
||||||
ADD TMP1, X5, X5
|
|
||||||
ADD TMP2, X6, X6
|
|
||||||
ADD TMP3, X7, X7
|
|
||||||
MOVWZ 16(KEY), TMP0
|
|
||||||
MOVWZ 20(KEY), TMP1
|
|
||||||
MOVWZ 24(KEY), TMP2
|
|
||||||
MOVWZ 28(KEY), TMP3
|
|
||||||
ADD TMP0, X8, X8
|
|
||||||
ADD TMP1, X9, X9
|
|
||||||
ADD TMP2, X10, X10
|
|
||||||
ADD TMP3, X11, X11
|
|
||||||
|
|
||||||
MOVWZ 12(CNT), TMP0
|
|
||||||
MOVWZ 8(CNT), TMP1
|
|
||||||
MOVWZ 4(CNT), TMP2
|
|
||||||
MOVWZ 0(CNT), TEMP
|
|
||||||
ADD TMP0, X15, X15
|
|
||||||
ADD TMP1, X14, X14
|
|
||||||
ADD TMP2, X13, X13
|
|
||||||
ADD TEMP, X12, X12
|
|
||||||
|
|
||||||
// Accumulate key block
|
|
||||||
VADDUWM A0, K0, A0
|
|
||||||
VADDUWM A1, K0, A1
|
|
||||||
VADDUWM A2, K0, A2
|
|
||||||
VADDUWM B0, K1, B0
|
|
||||||
VADDUWM B1, K1, B1
|
|
||||||
VADDUWM B2, K1, B2
|
|
||||||
VADDUWM C0, K2, C0
|
|
||||||
VADDUWM C1, K2, C1
|
|
||||||
VADDUWM C2, K2, C2
|
|
||||||
VADDUWM D0, K3, D0
|
|
||||||
VADDUWM D1, K4, D1
|
|
||||||
VADDUWM D2, K5, D2
|
|
||||||
|
|
||||||
// Increment counter
|
|
||||||
ADD $4, TEMP, TEMP
|
|
||||||
MOVW TEMP, 0(CNT)
|
|
||||||
|
|
||||||
VADDUWM K3, FOUR, K3
|
|
||||||
VADDUWM K4, FOUR, K4
|
|
||||||
VADDUWM K5, FOUR, K5
|
|
||||||
|
|
||||||
// XOR the input slice (INP) with the keystream, which is stored in GPRs (X0-X3).
|
|
||||||
|
|
||||||
// Load input (aligned or not)
|
|
||||||
MOVWZ 0(INP), TMP0
|
|
||||||
MOVWZ 4(INP), TMP1
|
|
||||||
MOVWZ 8(INP), TMP2
|
|
||||||
MOVWZ 12(INP), TMP3
|
|
||||||
|
|
||||||
// XOR with input
|
|
||||||
XOR TMP0, X0, X0
|
|
||||||
XOR TMP1, X1, X1
|
|
||||||
XOR TMP2, X2, X2
|
|
||||||
XOR TMP3, X3, X3
|
|
||||||
MOVWZ 16(INP), TMP0
|
|
||||||
MOVWZ 20(INP), TMP1
|
|
||||||
MOVWZ 24(INP), TMP2
|
|
||||||
MOVWZ 28(INP), TMP3
|
|
||||||
XOR TMP0, X4, X4
|
|
||||||
XOR TMP1, X5, X5
|
|
||||||
XOR TMP2, X6, X6
|
|
||||||
XOR TMP3, X7, X7
|
|
||||||
MOVWZ 32(INP), TMP0
|
|
||||||
MOVWZ 36(INP), TMP1
|
|
||||||
MOVWZ 40(INP), TMP2
|
|
||||||
MOVWZ 44(INP), TMP3
|
|
||||||
XOR TMP0, X8, X8
|
|
||||||
XOR TMP1, X9, X9
|
|
||||||
XOR TMP2, X10, X10
|
|
||||||
XOR TMP3, X11, X11
|
|
||||||
MOVWZ 48(INP), TMP0
|
|
||||||
MOVWZ 52(INP), TMP1
|
|
||||||
MOVWZ 56(INP), TMP2
|
|
||||||
MOVWZ 60(INP), TMP3
|
|
||||||
XOR TMP0, X12, X12
|
|
||||||
XOR TMP1, X13, X13
|
|
||||||
XOR TMP2, X14, X14
|
|
||||||
XOR TMP3, X15, X15
|
|
||||||
|
|
||||||
// Store output (aligned or not)
|
|
||||||
MOVW X0, 0(OUT)
|
|
||||||
MOVW X1, 4(OUT)
|
|
||||||
MOVW X2, 8(OUT)
|
|
||||||
MOVW X3, 12(OUT)
|
|
||||||
|
|
||||||
ADD $64, INP, INP // INP points to the end of the slice for the alignment code below
|
|
||||||
|
|
||||||
MOVW X4, 16(OUT)
|
|
||||||
MOVD $16, TMP0
|
|
||||||
MOVW X5, 20(OUT)
|
|
||||||
MOVD $32, TMP1
|
|
||||||
MOVW X6, 24(OUT)
|
|
||||||
MOVD $48, TMP2
|
|
||||||
MOVW X7, 28(OUT)
|
|
||||||
MOVD $64, TMP3
|
|
||||||
MOVW X8, 32(OUT)
|
|
||||||
MOVW X9, 36(OUT)
|
|
||||||
MOVW X10, 40(OUT)
|
|
||||||
MOVW X11, 44(OUT)
|
|
||||||
MOVW X12, 48(OUT)
|
|
||||||
MOVW X13, 52(OUT)
|
|
||||||
MOVW X14, 56(OUT)
|
|
||||||
MOVW X15, 60(OUT)
|
|
||||||
ADD $64, OUT, OUT
|
|
||||||
|
|
||||||
// Load input
|
|
||||||
LVX (INP)(R0), DD0
|
|
||||||
LVX (INP)(TMP0), DD1
|
|
||||||
LVX (INP)(TMP1), DD2
|
|
||||||
LVX (INP)(TMP2), DD3
|
|
||||||
LVX (INP)(TMP3), DD4
|
|
||||||
ADD $64, INP, INP
|
|
||||||
|
|
||||||
VPERM DD1, DD0, INPPERM, DD0 // Align input
|
|
||||||
VPERM DD2, DD1, INPPERM, DD1
|
|
||||||
VPERM DD3, DD2, INPPERM, DD2
|
|
||||||
VPERM DD4, DD3, INPPERM, DD3
|
|
||||||
VXOR A0, DD0, A0 // XOR with input
|
|
||||||
VXOR B0, DD1, B0
|
|
||||||
LVX (INP)(TMP0), DD1 // Keep loading input
|
|
||||||
VXOR C0, DD2, C0
|
|
||||||
LVX (INP)(TMP1), DD2
|
|
||||||
VXOR D0, DD3, D0
|
|
||||||
LVX (INP)(TMP2), DD3
|
|
||||||
LVX (INP)(TMP3), DD0
|
|
||||||
ADD $64, INP, INP
|
|
||||||
MOVD $63, TMP3 // 63 is not a typo
|
|
||||||
VPERM A0, A0, OUTPERM, A0
|
|
||||||
VPERM B0, B0, OUTPERM, B0
|
|
||||||
VPERM C0, C0, OUTPERM, C0
|
|
||||||
VPERM D0, D0, OUTPERM, D0
|
|
||||||
|
|
||||||
VPERM DD1, DD4, INPPERM, DD4 // Align input
|
|
||||||
VPERM DD2, DD1, INPPERM, DD1
|
|
||||||
VPERM DD3, DD2, INPPERM, DD2
|
|
||||||
VPERM DD0, DD3, INPPERM, DD3
|
|
||||||
VXOR A1, DD4, A1
|
|
||||||
VXOR B1, DD1, B1
|
|
||||||
LVX (INP)(TMP0), DD1 // Keep loading
|
|
||||||
VXOR C1, DD2, C1
|
|
||||||
LVX (INP)(TMP1), DD2
|
|
||||||
VXOR D1, DD3, D1
|
|
||||||
LVX (INP)(TMP2), DD3
|
|
||||||
|
|
||||||
// Note that the LVX address is always rounded down to the nearest 16-byte
|
|
||||||
// boundary, and that it always points to at most 15 bytes beyond the end of
|
|
||||||
// the slice, so we cannot cross a page boundary.
|
|
||||||
LVX (INP)(TMP3), DD4 // Redundant in aligned case.
|
|
||||||
ADD $64, INP, INP
|
|
||||||
VPERM A1, A1, OUTPERM, A1 // Pre-misalign output
|
|
||||||
VPERM B1, B1, OUTPERM, B1
|
|
||||||
VPERM C1, C1, OUTPERM, C1
|
|
||||||
VPERM D1, D1, OUTPERM, D1
|
|
||||||
|
|
||||||
VPERM DD1, DD0, INPPERM, DD0 // Align Input
|
|
||||||
VPERM DD2, DD1, INPPERM, DD1
|
|
||||||
VPERM DD3, DD2, INPPERM, DD2
|
|
||||||
VPERM DD4, DD3, INPPERM, DD3
|
|
||||||
VXOR A2, DD0, A2
|
|
||||||
VXOR B2, DD1, B2
|
|
||||||
VXOR C2, DD2, C2
|
|
||||||
VXOR D2, DD3, D2
|
|
||||||
VPERM A2, A2, OUTPERM, A2
|
|
||||||
VPERM B2, B2, OUTPERM, B2
|
|
||||||
VPERM C2, C2, OUTPERM, C2
|
|
||||||
VPERM D2, D2, OUTPERM, D2
|
|
||||||
|
|
||||||
ANDCC $15, OUT, X1 // Is out aligned?
|
|
||||||
MOVD OUT, X0
|
|
||||||
|
|
||||||
VSEL A0, B0, OUTMASK, DD0 // Collect pre-misaligned output
|
|
||||||
VSEL B0, C0, OUTMASK, DD1
|
|
||||||
VSEL C0, D0, OUTMASK, DD2
|
|
||||||
VSEL D0, A1, OUTMASK, DD3
|
|
||||||
VSEL A1, B1, OUTMASK, B0
|
|
||||||
VSEL B1, C1, OUTMASK, C0
|
|
||||||
VSEL C1, D1, OUTMASK, D0
|
|
||||||
VSEL D1, A2, OUTMASK, A1
|
|
||||||
VSEL A2, B2, OUTMASK, B1
|
|
||||||
VSEL B2, C2, OUTMASK, C1
|
|
||||||
VSEL C2, D2, OUTMASK, D1
|
|
||||||
|
|
||||||
STVX DD0, (OUT+TMP0)
|
|
||||||
STVX DD1, (OUT+TMP1)
|
|
||||||
STVX DD2, (OUT+TMP2)
|
|
||||||
ADD $64, OUT, OUT
|
|
||||||
STVX DD3, (OUT+R0)
|
|
||||||
STVX B0, (OUT+TMP0)
|
|
||||||
STVX C0, (OUT+TMP1)
|
|
||||||
STVX D0, (OUT+TMP2)
|
|
||||||
ADD $64, OUT, OUT
|
|
||||||
STVX A1, (OUT+R0)
|
|
||||||
STVX B1, (OUT+TMP0)
|
|
||||||
STVX C1, (OUT+TMP1)
|
|
||||||
STVX D1, (OUT+TMP2)
|
|
||||||
ADD $64, OUT, OUT
|
|
||||||
|
|
||||||
BEQ aligned_vmx
|
|
||||||
|
|
||||||
SUB X1, OUT, X2 // in misaligned case edges
|
|
||||||
MOVD $0, X3 // are written byte-by-byte
|
|
||||||
|
|
||||||
unaligned_tail_vmx:
|
|
||||||
STVEBX D2, (X2+X3)
|
|
||||||
ADD $1, X3, X3
|
|
||||||
CMPW X3, X1
|
|
||||||
BNE unaligned_tail_vmx
|
|
||||||
SUB X1, X0, X2
|
|
||||||
|
|
||||||
unaligned_head_vmx:
|
|
||||||
STVEBX A0, (X2+X1)
|
|
||||||
CMPW X1, $15
|
|
||||||
ADD $1, X1, X1
|
|
||||||
BNE unaligned_head_vmx
|
|
||||||
|
|
||||||
CMPU LEN, $255 // done with 256-byte block yet?
|
|
||||||
BGT loop_outer_vmx
|
|
||||||
|
|
||||||
JMP done_vmx
|
|
||||||
|
|
||||||
aligned_vmx:
|
|
||||||
STVX A0, (X0+R0)
|
|
||||||
CMPU LEN, $255 // done with 256-byte block yet?
|
|
||||||
BGT loop_outer_vmx
|
|
||||||
|
|
||||||
done_vmx:
|
|
||||||
RET
|
|
31
vendor/golang.org/x/crypto/internal/chacha20/chacha_arm64.go
generated
vendored
31
vendor/golang.org/x/crypto/internal/chacha20/chacha_arm64.go
generated
vendored
@ -1,31 +0,0 @@
|
|||||||
// Copyright 2018 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.
|
|
||||||
|
|
||||||
// +build go1.11
|
|
||||||
// +build !gccgo
|
|
||||||
|
|
||||||
package chacha20
|
|
||||||
|
|
||||||
const (
|
|
||||||
haveAsm = true
|
|
||||||
bufSize = 256
|
|
||||||
)
|
|
||||||
|
|
||||||
//go:noescape
|
|
||||||
func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32)
|
|
||||||
|
|
||||||
func (c *Cipher) xorKeyStreamAsm(dst, src []byte) {
|
|
||||||
|
|
||||||
if len(src) >= bufSize {
|
|
||||||
xorKeyStreamVX(dst, src, &c.key, &c.nonce, &c.counter)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(src)%bufSize != 0 {
|
|
||||||
i := len(src) - len(src)%bufSize
|
|
||||||
c.buf = [bufSize]byte{}
|
|
||||||
copy(c.buf[:], src[i:])
|
|
||||||
xorKeyStreamVX(c.buf[:], c.buf[:], &c.key, &c.nonce, &c.counter)
|
|
||||||
c.len = bufSize - copy(dst[i:], c.buf[:len(src)%bufSize])
|
|
||||||
}
|
|
||||||
}
|
|
264
vendor/golang.org/x/crypto/internal/chacha20/chacha_generic.go
generated
vendored
264
vendor/golang.org/x/crypto/internal/chacha20/chacha_generic.go
generated
vendored
@ -1,264 +0,0 @@
|
|||||||
// Copyright 2016 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 ChaCha20 implements the core ChaCha20 function as specified
|
|
||||||
// in https://tools.ietf.org/html/rfc7539#section-2.3.
|
|
||||||
package chacha20
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/cipher"
|
|
||||||
"encoding/binary"
|
|
||||||
|
|
||||||
"golang.org/x/crypto/internal/subtle"
|
|
||||||
)
|
|
||||||
|
|
||||||
// assert that *Cipher implements cipher.Stream
|
|
||||||
var _ cipher.Stream = (*Cipher)(nil)
|
|
||||||
|
|
||||||
// Cipher is a stateful instance of ChaCha20 using a particular key
|
|
||||||
// and nonce. A *Cipher implements the cipher.Stream interface.
|
|
||||||
type Cipher struct {
|
|
||||||
key [8]uint32
|
|
||||||
counter uint32 // incremented after each block
|
|
||||||
nonce [3]uint32
|
|
||||||
buf [bufSize]byte // buffer for unused keystream bytes
|
|
||||||
len int // number of unused keystream bytes at end of buf
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates a new ChaCha20 stream cipher with the given key and nonce.
|
|
||||||
// The initial counter value is set to 0.
|
|
||||||
func New(key [8]uint32, nonce [3]uint32) *Cipher {
|
|
||||||
return &Cipher{key: key, nonce: nonce}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ChaCha20 constants spelling "expand 32-byte k"
|
|
||||||
const (
|
|
||||||
j0 uint32 = 0x61707865
|
|
||||||
j1 uint32 = 0x3320646e
|
|
||||||
j2 uint32 = 0x79622d32
|
|
||||||
j3 uint32 = 0x6b206574
|
|
||||||
)
|
|
||||||
|
|
||||||
func quarterRound(a, b, c, d uint32) (uint32, uint32, uint32, uint32) {
|
|
||||||
a += b
|
|
||||||
d ^= a
|
|
||||||
d = (d << 16) | (d >> 16)
|
|
||||||
c += d
|
|
||||||
b ^= c
|
|
||||||
b = (b << 12) | (b >> 20)
|
|
||||||
a += b
|
|
||||||
d ^= a
|
|
||||||
d = (d << 8) | (d >> 24)
|
|
||||||
c += d
|
|
||||||
b ^= c
|
|
||||||
b = (b << 7) | (b >> 25)
|
|
||||||
return a, b, c, d
|
|
||||||
}
|
|
||||||
|
|
||||||
// XORKeyStream XORs each byte in the given slice with a byte from the
|
|
||||||
// cipher's key stream. Dst and src must overlap entirely or not at all.
|
|
||||||
//
|
|
||||||
// If len(dst) < len(src), XORKeyStream will panic. It is acceptable
|
|
||||||
// to pass a dst bigger than src, and in that case, XORKeyStream will
|
|
||||||
// only update dst[:len(src)] and will not touch the rest of dst.
|
|
||||||
//
|
|
||||||
// Multiple calls to XORKeyStream behave as if the concatenation of
|
|
||||||
// the src buffers was passed in a single run. That is, Cipher
|
|
||||||
// maintains state and does not reset at each XORKeyStream call.
|
|
||||||
func (s *Cipher) XORKeyStream(dst, src []byte) {
|
|
||||||
if len(dst) < len(src) {
|
|
||||||
panic("chacha20: output smaller than input")
|
|
||||||
}
|
|
||||||
if subtle.InexactOverlap(dst[:len(src)], src) {
|
|
||||||
panic("chacha20: invalid buffer overlap")
|
|
||||||
}
|
|
||||||
|
|
||||||
// xor src with buffered keystream first
|
|
||||||
if s.len != 0 {
|
|
||||||
buf := s.buf[len(s.buf)-s.len:]
|
|
||||||
if len(src) < len(buf) {
|
|
||||||
buf = buf[:len(src)]
|
|
||||||
}
|
|
||||||
td, ts := dst[:len(buf)], src[:len(buf)] // BCE hint
|
|
||||||
for i, b := range buf {
|
|
||||||
td[i] = ts[i] ^ b
|
|
||||||
}
|
|
||||||
s.len -= len(buf)
|
|
||||||
if s.len != 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
s.buf = [len(s.buf)]byte{} // zero the empty buffer
|
|
||||||
src = src[len(buf):]
|
|
||||||
dst = dst[len(buf):]
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(src) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if haveAsm {
|
|
||||||
if uint64(len(src))+uint64(s.counter)*64 > (1<<38)-64 {
|
|
||||||
panic("chacha20: counter overflow")
|
|
||||||
}
|
|
||||||
s.xorKeyStreamAsm(dst, src)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// set up a 64-byte buffer to pad out the final block if needed
|
|
||||||
// (hoisted out of the main loop to avoid spills)
|
|
||||||
rem := len(src) % 64 // length of final block
|
|
||||||
fin := len(src) - rem // index of final block
|
|
||||||
if rem > 0 {
|
|
||||||
copy(s.buf[len(s.buf)-64:], src[fin:])
|
|
||||||
}
|
|
||||||
|
|
||||||
// pre-calculate most of the first round
|
|
||||||
s1, s5, s9, s13 := quarterRound(j1, s.key[1], s.key[5], s.nonce[0])
|
|
||||||
s2, s6, s10, s14 := quarterRound(j2, s.key[2], s.key[6], s.nonce[1])
|
|
||||||
s3, s7, s11, s15 := quarterRound(j3, s.key[3], s.key[7], s.nonce[2])
|
|
||||||
|
|
||||||
n := len(src)
|
|
||||||
src, dst = src[:n:n], dst[:n:n] // BCE hint
|
|
||||||
for i := 0; i < n; i += 64 {
|
|
||||||
// calculate the remainder of the first round
|
|
||||||
s0, s4, s8, s12 := quarterRound(j0, s.key[0], s.key[4], s.counter)
|
|
||||||
|
|
||||||
// execute the second round
|
|
||||||
x0, x5, x10, x15 := quarterRound(s0, s5, s10, s15)
|
|
||||||
x1, x6, x11, x12 := quarterRound(s1, s6, s11, s12)
|
|
||||||
x2, x7, x8, x13 := quarterRound(s2, s7, s8, s13)
|
|
||||||
x3, x4, x9, x14 := quarterRound(s3, s4, s9, s14)
|
|
||||||
|
|
||||||
// execute the remaining 18 rounds
|
|
||||||
for i := 0; i < 9; i++ {
|
|
||||||
x0, x4, x8, x12 = quarterRound(x0, x4, x8, x12)
|
|
||||||
x1, x5, x9, x13 = quarterRound(x1, x5, x9, x13)
|
|
||||||
x2, x6, x10, x14 = quarterRound(x2, x6, x10, x14)
|
|
||||||
x3, x7, x11, x15 = quarterRound(x3, x7, x11, x15)
|
|
||||||
|
|
||||||
x0, x5, x10, x15 = quarterRound(x0, x5, x10, x15)
|
|
||||||
x1, x6, x11, x12 = quarterRound(x1, x6, x11, x12)
|
|
||||||
x2, x7, x8, x13 = quarterRound(x2, x7, x8, x13)
|
|
||||||
x3, x4, x9, x14 = quarterRound(x3, x4, x9, x14)
|
|
||||||
}
|
|
||||||
|
|
||||||
x0 += j0
|
|
||||||
x1 += j1
|
|
||||||
x2 += j2
|
|
||||||
x3 += j3
|
|
||||||
|
|
||||||
x4 += s.key[0]
|
|
||||||
x5 += s.key[1]
|
|
||||||
x6 += s.key[2]
|
|
||||||
x7 += s.key[3]
|
|
||||||
x8 += s.key[4]
|
|
||||||
x9 += s.key[5]
|
|
||||||
x10 += s.key[6]
|
|
||||||
x11 += s.key[7]
|
|
||||||
|
|
||||||
x12 += s.counter
|
|
||||||
x13 += s.nonce[0]
|
|
||||||
x14 += s.nonce[1]
|
|
||||||
x15 += s.nonce[2]
|
|
||||||
|
|
||||||
// increment the counter
|
|
||||||
s.counter += 1
|
|
||||||
if s.counter == 0 {
|
|
||||||
panic("chacha20: counter overflow")
|
|
||||||
}
|
|
||||||
|
|
||||||
// pad to 64 bytes if needed
|
|
||||||
in, out := src[i:], dst[i:]
|
|
||||||
if i == fin {
|
|
||||||
// src[fin:] has already been copied into s.buf before
|
|
||||||
// the main loop
|
|
||||||
in, out = s.buf[len(s.buf)-64:], s.buf[len(s.buf)-64:]
|
|
||||||
}
|
|
||||||
in, out = in[:64], out[:64] // BCE hint
|
|
||||||
|
|
||||||
// XOR the key stream with the source and write out the result
|
|
||||||
xor(out[0:], in[0:], x0)
|
|
||||||
xor(out[4:], in[4:], x1)
|
|
||||||
xor(out[8:], in[8:], x2)
|
|
||||||
xor(out[12:], in[12:], x3)
|
|
||||||
xor(out[16:], in[16:], x4)
|
|
||||||
xor(out[20:], in[20:], x5)
|
|
||||||
xor(out[24:], in[24:], x6)
|
|
||||||
xor(out[28:], in[28:], x7)
|
|
||||||
xor(out[32:], in[32:], x8)
|
|
||||||
xor(out[36:], in[36:], x9)
|
|
||||||
xor(out[40:], in[40:], x10)
|
|
||||||
xor(out[44:], in[44:], x11)
|
|
||||||
xor(out[48:], in[48:], x12)
|
|
||||||
xor(out[52:], in[52:], x13)
|
|
||||||
xor(out[56:], in[56:], x14)
|
|
||||||
xor(out[60:], in[60:], x15)
|
|
||||||
}
|
|
||||||
// copy any trailing bytes out of the buffer and into dst
|
|
||||||
if rem != 0 {
|
|
||||||
s.len = 64 - rem
|
|
||||||
copy(dst[fin:], s.buf[len(s.buf)-64:])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Advance discards bytes in the key stream until the next 64 byte block
|
|
||||||
// boundary is reached and updates the counter accordingly. If the key
|
|
||||||
// stream is already at a block boundary no bytes will be discarded and
|
|
||||||
// the counter will be unchanged.
|
|
||||||
func (s *Cipher) Advance() {
|
|
||||||
s.len -= s.len % 64
|
|
||||||
if s.len == 0 {
|
|
||||||
s.buf = [len(s.buf)]byte{}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// XORKeyStream crypts bytes from in to out using the given key and counters.
|
|
||||||
// In and out must overlap entirely or not at all. Counter contains the raw
|
|
||||||
// ChaCha20 counter bytes (i.e. block counter followed by nonce).
|
|
||||||
func XORKeyStream(out, in []byte, counter *[16]byte, key *[32]byte) {
|
|
||||||
s := Cipher{
|
|
||||||
key: [8]uint32{
|
|
||||||
binary.LittleEndian.Uint32(key[0:4]),
|
|
||||||
binary.LittleEndian.Uint32(key[4:8]),
|
|
||||||
binary.LittleEndian.Uint32(key[8:12]),
|
|
||||||
binary.LittleEndian.Uint32(key[12:16]),
|
|
||||||
binary.LittleEndian.Uint32(key[16:20]),
|
|
||||||
binary.LittleEndian.Uint32(key[20:24]),
|
|
||||||
binary.LittleEndian.Uint32(key[24:28]),
|
|
||||||
binary.LittleEndian.Uint32(key[28:32]),
|
|
||||||
},
|
|
||||||
nonce: [3]uint32{
|
|
||||||
binary.LittleEndian.Uint32(counter[4:8]),
|
|
||||||
binary.LittleEndian.Uint32(counter[8:12]),
|
|
||||||
binary.LittleEndian.Uint32(counter[12:16]),
|
|
||||||
},
|
|
||||||
counter: binary.LittleEndian.Uint32(counter[0:4]),
|
|
||||||
}
|
|
||||||
s.XORKeyStream(out, in)
|
|
||||||
}
|
|
||||||
|
|
||||||
// HChaCha20 uses the ChaCha20 core to generate a derived key from a key and a
|
|
||||||
// nonce. It should only be used as part of the XChaCha20 construction.
|
|
||||||
func HChaCha20(key *[8]uint32, nonce *[4]uint32) [8]uint32 {
|
|
||||||
x0, x1, x2, x3 := j0, j1, j2, j3
|
|
||||||
x4, x5, x6, x7 := key[0], key[1], key[2], key[3]
|
|
||||||
x8, x9, x10, x11 := key[4], key[5], key[6], key[7]
|
|
||||||
x12, x13, x14, x15 := nonce[0], nonce[1], nonce[2], nonce[3]
|
|
||||||
|
|
||||||
for i := 0; i < 10; i++ {
|
|
||||||
x0, x4, x8, x12 = quarterRound(x0, x4, x8, x12)
|
|
||||||
x1, x5, x9, x13 = quarterRound(x1, x5, x9, x13)
|
|
||||||
x2, x6, x10, x14 = quarterRound(x2, x6, x10, x14)
|
|
||||||
x3, x7, x11, x15 = quarterRound(x3, x7, x11, x15)
|
|
||||||
|
|
||||||
x0, x5, x10, x15 = quarterRound(x0, x5, x10, x15)
|
|
||||||
x1, x6, x11, x12 = quarterRound(x1, x6, x11, x12)
|
|
||||||
x2, x7, x8, x13 = quarterRound(x2, x7, x8, x13)
|
|
||||||
x3, x4, x9, x14 = quarterRound(x3, x4, x9, x14)
|
|
||||||
}
|
|
||||||
|
|
||||||
var out [8]uint32
|
|
||||||
out[0], out[1], out[2], out[3] = x0, x1, x2, x3
|
|
||||||
out[4], out[5], out[6], out[7] = x12, x13, x14, x15
|
|
||||||
return out
|
|
||||||
}
|
|
16
vendor/golang.org/x/crypto/internal/chacha20/chacha_noasm.go
generated
vendored
16
vendor/golang.org/x/crypto/internal/chacha20/chacha_noasm.go
generated
vendored
@ -1,16 +0,0 @@
|
|||||||
// Copyright 2018 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.
|
|
||||||
|
|
||||||
// +build !ppc64le,!arm64,!s390x arm64,!go1.11 gccgo appengine
|
|
||||||
|
|
||||||
package chacha20
|
|
||||||
|
|
||||||
const (
|
|
||||||
bufSize = 64
|
|
||||||
haveAsm = false
|
|
||||||
)
|
|
||||||
|
|
||||||
func (*Cipher) xorKeyStreamAsm(dst, src []byte) {
|
|
||||||
panic("not implemented")
|
|
||||||
}
|
|
52
vendor/golang.org/x/crypto/internal/chacha20/chacha_ppc64le.go
generated
vendored
52
vendor/golang.org/x/crypto/internal/chacha20/chacha_ppc64le.go
generated
vendored
@ -1,52 +0,0 @@
|
|||||||
// Copyright 2019 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.
|
|
||||||
|
|
||||||
// +build ppc64le,!gccgo,!appengine
|
|
||||||
|
|
||||||
package chacha20
|
|
||||||
|
|
||||||
import "encoding/binary"
|
|
||||||
|
|
||||||
const (
|
|
||||||
bufSize = 256
|
|
||||||
haveAsm = true
|
|
||||||
)
|
|
||||||
|
|
||||||
//go:noescape
|
|
||||||
func chaCha20_ctr32_vmx(out, inp *byte, len int, key *[8]uint32, counter *uint32)
|
|
||||||
|
|
||||||
func (c *Cipher) xorKeyStreamAsm(dst, src []byte) {
|
|
||||||
if len(src) >= bufSize {
|
|
||||||
chaCha20_ctr32_vmx(&dst[0], &src[0], len(src)-len(src)%bufSize, &c.key, &c.counter)
|
|
||||||
}
|
|
||||||
if len(src)%bufSize != 0 {
|
|
||||||
chaCha20_ctr32_vmx(&c.buf[0], &c.buf[0], bufSize, &c.key, &c.counter)
|
|
||||||
start := len(src) - len(src)%bufSize
|
|
||||||
ts, td, tb := src[start:], dst[start:], c.buf[:]
|
|
||||||
// Unroll loop to XOR 32 bytes per iteration.
|
|
||||||
for i := 0; i < len(ts)-32; i += 32 {
|
|
||||||
td, tb = td[:len(ts)], tb[:len(ts)] // bounds check elimination
|
|
||||||
s0 := binary.LittleEndian.Uint64(ts[0:8])
|
|
||||||
s1 := binary.LittleEndian.Uint64(ts[8:16])
|
|
||||||
s2 := binary.LittleEndian.Uint64(ts[16:24])
|
|
||||||
s3 := binary.LittleEndian.Uint64(ts[24:32])
|
|
||||||
b0 := binary.LittleEndian.Uint64(tb[0:8])
|
|
||||||
b1 := binary.LittleEndian.Uint64(tb[8:16])
|
|
||||||
b2 := binary.LittleEndian.Uint64(tb[16:24])
|
|
||||||
b3 := binary.LittleEndian.Uint64(tb[24:32])
|
|
||||||
binary.LittleEndian.PutUint64(td[0:8], s0^b0)
|
|
||||||
binary.LittleEndian.PutUint64(td[8:16], s1^b1)
|
|
||||||
binary.LittleEndian.PutUint64(td[16:24], s2^b2)
|
|
||||||
binary.LittleEndian.PutUint64(td[24:32], s3^b3)
|
|
||||||
ts, td, tb = ts[32:], td[32:], tb[32:]
|
|
||||||
}
|
|
||||||
td, tb = td[:len(ts)], tb[:len(ts)] // bounds check elimination
|
|
||||||
for i, v := range ts {
|
|
||||||
td[i] = tb[i] ^ v
|
|
||||||
}
|
|
||||||
c.len = bufSize - (len(src) % bufSize)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
29
vendor/golang.org/x/crypto/internal/chacha20/chacha_s390x.go
generated
vendored
29
vendor/golang.org/x/crypto/internal/chacha20/chacha_s390x.go
generated
vendored
@ -1,29 +0,0 @@
|
|||||||
// Copyright 2018 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.
|
|
||||||
|
|
||||||
// +build s390x,!gccgo,!appengine
|
|
||||||
|
|
||||||
package chacha20
|
|
||||||
|
|
||||||
import (
|
|
||||||
"golang.org/x/sys/cpu"
|
|
||||||
)
|
|
||||||
|
|
||||||
var haveAsm = cpu.S390X.HasVX
|
|
||||||
|
|
||||||
const bufSize = 256
|
|
||||||
|
|
||||||
// xorKeyStreamVX is an assembly implementation of XORKeyStream. It must only
|
|
||||||
// be called when the vector facility is available.
|
|
||||||
// Implementation in asm_s390x.s.
|
|
||||||
//go:noescape
|
|
||||||
func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32, buf *[256]byte, len *int)
|
|
||||||
|
|
||||||
func (c *Cipher) xorKeyStreamAsm(dst, src []byte) {
|
|
||||||
xorKeyStreamVX(dst, src, &c.key, &c.nonce, &c.counter, &c.buf, &c.len)
|
|
||||||
}
|
|
||||||
|
|
||||||
// EXRL targets, DO NOT CALL!
|
|
||||||
func mvcSrcToBuf()
|
|
||||||
func mvcBufToDst()
|
|
260
vendor/golang.org/x/crypto/internal/chacha20/chacha_s390x.s
generated
vendored
260
vendor/golang.org/x/crypto/internal/chacha20/chacha_s390x.s
generated
vendored
@ -1,260 +0,0 @@
|
|||||||
// Copyright 2018 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.
|
|
||||||
|
|
||||||
// +build s390x,!gccgo,!appengine
|
|
||||||
|
|
||||||
#include "go_asm.h"
|
|
||||||
#include "textflag.h"
|
|
||||||
|
|
||||||
// This is an implementation of the ChaCha20 encryption algorithm as
|
|
||||||
// specified in RFC 7539. It uses vector instructions to compute
|
|
||||||
// 4 keystream blocks in parallel (256 bytes) which are then XORed
|
|
||||||
// with the bytes in the input slice.
|
|
||||||
|
|
||||||
GLOBL ·constants<>(SB), RODATA|NOPTR, $32
|
|
||||||
// BSWAP: swap bytes in each 4-byte element
|
|
||||||
DATA ·constants<>+0x00(SB)/4, $0x03020100
|
|
||||||
DATA ·constants<>+0x04(SB)/4, $0x07060504
|
|
||||||
DATA ·constants<>+0x08(SB)/4, $0x0b0a0908
|
|
||||||
DATA ·constants<>+0x0c(SB)/4, $0x0f0e0d0c
|
|
||||||
// J0: [j0, j1, j2, j3]
|
|
||||||
DATA ·constants<>+0x10(SB)/4, $0x61707865
|
|
||||||
DATA ·constants<>+0x14(SB)/4, $0x3320646e
|
|
||||||
DATA ·constants<>+0x18(SB)/4, $0x79622d32
|
|
||||||
DATA ·constants<>+0x1c(SB)/4, $0x6b206574
|
|
||||||
|
|
||||||
// EXRL targets:
|
|
||||||
TEXT ·mvcSrcToBuf(SB), NOFRAME|NOSPLIT, $0
|
|
||||||
MVC $1, (R1), (R8)
|
|
||||||
RET
|
|
||||||
|
|
||||||
TEXT ·mvcBufToDst(SB), NOFRAME|NOSPLIT, $0
|
|
||||||
MVC $1, (R8), (R9)
|
|
||||||
RET
|
|
||||||
|
|
||||||
#define BSWAP V5
|
|
||||||
#define J0 V6
|
|
||||||
#define KEY0 V7
|
|
||||||
#define KEY1 V8
|
|
||||||
#define NONCE V9
|
|
||||||
#define CTR V10
|
|
||||||
#define M0 V11
|
|
||||||
#define M1 V12
|
|
||||||
#define M2 V13
|
|
||||||
#define M3 V14
|
|
||||||
#define INC V15
|
|
||||||
#define X0 V16
|
|
||||||
#define X1 V17
|
|
||||||
#define X2 V18
|
|
||||||
#define X3 V19
|
|
||||||
#define X4 V20
|
|
||||||
#define X5 V21
|
|
||||||
#define X6 V22
|
|
||||||
#define X7 V23
|
|
||||||
#define X8 V24
|
|
||||||
#define X9 V25
|
|
||||||
#define X10 V26
|
|
||||||
#define X11 V27
|
|
||||||
#define X12 V28
|
|
||||||
#define X13 V29
|
|
||||||
#define X14 V30
|
|
||||||
#define X15 V31
|
|
||||||
|
|
||||||
#define NUM_ROUNDS 20
|
|
||||||
|
|
||||||
#define ROUND4(a0, a1, a2, a3, b0, b1, b2, b3, c0, c1, c2, c3, d0, d1, d2, d3) \
|
|
||||||
VAF a1, a0, a0 \
|
|
||||||
VAF b1, b0, b0 \
|
|
||||||
VAF c1, c0, c0 \
|
|
||||||
VAF d1, d0, d0 \
|
|
||||||
VX a0, a2, a2 \
|
|
||||||
VX b0, b2, b2 \
|
|
||||||
VX c0, c2, c2 \
|
|
||||||
VX d0, d2, d2 \
|
|
||||||
VERLLF $16, a2, a2 \
|
|
||||||
VERLLF $16, b2, b2 \
|
|
||||||
VERLLF $16, c2, c2 \
|
|
||||||
VERLLF $16, d2, d2 \
|
|
||||||
VAF a2, a3, a3 \
|
|
||||||
VAF b2, b3, b3 \
|
|
||||||
VAF c2, c3, c3 \
|
|
||||||
VAF d2, d3, d3 \
|
|
||||||
VX a3, a1, a1 \
|
|
||||||
VX b3, b1, b1 \
|
|
||||||
VX c3, c1, c1 \
|
|
||||||
VX d3, d1, d1 \
|
|
||||||
VERLLF $12, a1, a1 \
|
|
||||||
VERLLF $12, b1, b1 \
|
|
||||||
VERLLF $12, c1, c1 \
|
|
||||||
VERLLF $12, d1, d1 \
|
|
||||||
VAF a1, a0, a0 \
|
|
||||||
VAF b1, b0, b0 \
|
|
||||||
VAF c1, c0, c0 \
|
|
||||||
VAF d1, d0, d0 \
|
|
||||||
VX a0, a2, a2 \
|
|
||||||
VX b0, b2, b2 \
|
|
||||||
VX c0, c2, c2 \
|
|
||||||
VX d0, d2, d2 \
|
|
||||||
VERLLF $8, a2, a2 \
|
|
||||||
VERLLF $8, b2, b2 \
|
|
||||||
VERLLF $8, c2, c2 \
|
|
||||||
VERLLF $8, d2, d2 \
|
|
||||||
VAF a2, a3, a3 \
|
|
||||||
VAF b2, b3, b3 \
|
|
||||||
VAF c2, c3, c3 \
|
|
||||||
VAF d2, d3, d3 \
|
|
||||||
VX a3, a1, a1 \
|
|
||||||
VX b3, b1, b1 \
|
|
||||||
VX c3, c1, c1 \
|
|
||||||
VX d3, d1, d1 \
|
|
||||||
VERLLF $7, a1, a1 \
|
|
||||||
VERLLF $7, b1, b1 \
|
|
||||||
VERLLF $7, c1, c1 \
|
|
||||||
VERLLF $7, d1, d1
|
|
||||||
|
|
||||||
#define PERMUTE(mask, v0, v1, v2, v3) \
|
|
||||||
VPERM v0, v0, mask, v0 \
|
|
||||||
VPERM v1, v1, mask, v1 \
|
|
||||||
VPERM v2, v2, mask, v2 \
|
|
||||||
VPERM v3, v3, mask, v3
|
|
||||||
|
|
||||||
#define ADDV(x, v0, v1, v2, v3) \
|
|
||||||
VAF x, v0, v0 \
|
|
||||||
VAF x, v1, v1 \
|
|
||||||
VAF x, v2, v2 \
|
|
||||||
VAF x, v3, v3
|
|
||||||
|
|
||||||
#define XORV(off, dst, src, v0, v1, v2, v3) \
|
|
||||||
VLM off(src), M0, M3 \
|
|
||||||
PERMUTE(BSWAP, v0, v1, v2, v3) \
|
|
||||||
VX v0, M0, M0 \
|
|
||||||
VX v1, M1, M1 \
|
|
||||||
VX v2, M2, M2 \
|
|
||||||
VX v3, M3, M3 \
|
|
||||||
VSTM M0, M3, off(dst)
|
|
||||||
|
|
||||||
#define SHUFFLE(a, b, c, d, t, u, v, w) \
|
|
||||||
VMRHF a, c, t \ // t = {a[0], c[0], a[1], c[1]}
|
|
||||||
VMRHF b, d, u \ // u = {b[0], d[0], b[1], d[1]}
|
|
||||||
VMRLF a, c, v \ // v = {a[2], c[2], a[3], c[3]}
|
|
||||||
VMRLF b, d, w \ // w = {b[2], d[2], b[3], d[3]}
|
|
||||||
VMRHF t, u, a \ // a = {a[0], b[0], c[0], d[0]}
|
|
||||||
VMRLF t, u, b \ // b = {a[1], b[1], c[1], d[1]}
|
|
||||||
VMRHF v, w, c \ // c = {a[2], b[2], c[2], d[2]}
|
|
||||||
VMRLF v, w, d // d = {a[3], b[3], c[3], d[3]}
|
|
||||||
|
|
||||||
// func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32, buf *[256]byte, len *int)
|
|
||||||
TEXT ·xorKeyStreamVX(SB), NOSPLIT, $0
|
|
||||||
MOVD $·constants<>(SB), R1
|
|
||||||
MOVD dst+0(FP), R2 // R2=&dst[0]
|
|
||||||
LMG src+24(FP), R3, R4 // R3=&src[0] R4=len(src)
|
|
||||||
MOVD key+48(FP), R5 // R5=key
|
|
||||||
MOVD nonce+56(FP), R6 // R6=nonce
|
|
||||||
MOVD counter+64(FP), R7 // R7=counter
|
|
||||||
MOVD buf+72(FP), R8 // R8=buf
|
|
||||||
MOVD len+80(FP), R9 // R9=len
|
|
||||||
|
|
||||||
// load BSWAP and J0
|
|
||||||
VLM (R1), BSWAP, J0
|
|
||||||
|
|
||||||
// set up tail buffer
|
|
||||||
ADD $-1, R4, R12
|
|
||||||
MOVBZ R12, R12
|
|
||||||
CMPUBEQ R12, $255, aligned
|
|
||||||
MOVD R4, R1
|
|
||||||
AND $~255, R1
|
|
||||||
MOVD $(R3)(R1*1), R1
|
|
||||||
EXRL $·mvcSrcToBuf(SB), R12
|
|
||||||
MOVD $255, R0
|
|
||||||
SUB R12, R0
|
|
||||||
MOVD R0, (R9) // update len
|
|
||||||
|
|
||||||
aligned:
|
|
||||||
// setup
|
|
||||||
MOVD $95, R0
|
|
||||||
VLM (R5), KEY0, KEY1
|
|
||||||
VLL R0, (R6), NONCE
|
|
||||||
VZERO M0
|
|
||||||
VLEIB $7, $32, M0
|
|
||||||
VSRLB M0, NONCE, NONCE
|
|
||||||
|
|
||||||
// initialize counter values
|
|
||||||
VLREPF (R7), CTR
|
|
||||||
VZERO INC
|
|
||||||
VLEIF $1, $1, INC
|
|
||||||
VLEIF $2, $2, INC
|
|
||||||
VLEIF $3, $3, INC
|
|
||||||
VAF INC, CTR, CTR
|
|
||||||
VREPIF $4, INC
|
|
||||||
|
|
||||||
chacha:
|
|
||||||
VREPF $0, J0, X0
|
|
||||||
VREPF $1, J0, X1
|
|
||||||
VREPF $2, J0, X2
|
|
||||||
VREPF $3, J0, X3
|
|
||||||
VREPF $0, KEY0, X4
|
|
||||||
VREPF $1, KEY0, X5
|
|
||||||
VREPF $2, KEY0, X6
|
|
||||||
VREPF $3, KEY0, X7
|
|
||||||
VREPF $0, KEY1, X8
|
|
||||||
VREPF $1, KEY1, X9
|
|
||||||
VREPF $2, KEY1, X10
|
|
||||||
VREPF $3, KEY1, X11
|
|
||||||
VLR CTR, X12
|
|
||||||
VREPF $1, NONCE, X13
|
|
||||||
VREPF $2, NONCE, X14
|
|
||||||
VREPF $3, NONCE, X15
|
|
||||||
|
|
||||||
MOVD $(NUM_ROUNDS/2), R1
|
|
||||||
|
|
||||||
loop:
|
|
||||||
ROUND4(X0, X4, X12, X8, X1, X5, X13, X9, X2, X6, X14, X10, X3, X7, X15, X11)
|
|
||||||
ROUND4(X0, X5, X15, X10, X1, X6, X12, X11, X2, X7, X13, X8, X3, X4, X14, X9)
|
|
||||||
|
|
||||||
ADD $-1, R1
|
|
||||||
BNE loop
|
|
||||||
|
|
||||||
// decrement length
|
|
||||||
ADD $-256, R4
|
|
||||||
BLT tail
|
|
||||||
|
|
||||||
continue:
|
|
||||||
// rearrange vectors
|
|
||||||
SHUFFLE(X0, X1, X2, X3, M0, M1, M2, M3)
|
|
||||||
ADDV(J0, X0, X1, X2, X3)
|
|
||||||
SHUFFLE(X4, X5, X6, X7, M0, M1, M2, M3)
|
|
||||||
ADDV(KEY0, X4, X5, X6, X7)
|
|
||||||
SHUFFLE(X8, X9, X10, X11, M0, M1, M2, M3)
|
|
||||||
ADDV(KEY1, X8, X9, X10, X11)
|
|
||||||
VAF CTR, X12, X12
|
|
||||||
SHUFFLE(X12, X13, X14, X15, M0, M1, M2, M3)
|
|
||||||
ADDV(NONCE, X12, X13, X14, X15)
|
|
||||||
|
|
||||||
// increment counters
|
|
||||||
VAF INC, CTR, CTR
|
|
||||||
|
|
||||||
// xor keystream with plaintext
|
|
||||||
XORV(0*64, R2, R3, X0, X4, X8, X12)
|
|
||||||
XORV(1*64, R2, R3, X1, X5, X9, X13)
|
|
||||||
XORV(2*64, R2, R3, X2, X6, X10, X14)
|
|
||||||
XORV(3*64, R2, R3, X3, X7, X11, X15)
|
|
||||||
|
|
||||||
// increment pointers
|
|
||||||
MOVD $256(R2), R2
|
|
||||||
MOVD $256(R3), R3
|
|
||||||
|
|
||||||
CMPBNE R4, $0, chacha
|
|
||||||
CMPUBEQ R12, $255, return
|
|
||||||
EXRL $·mvcBufToDst(SB), R12 // len was updated during setup
|
|
||||||
|
|
||||||
return:
|
|
||||||
VSTEF $0, CTR, (R7)
|
|
||||||
RET
|
|
||||||
|
|
||||||
tail:
|
|
||||||
MOVD R2, R9
|
|
||||||
MOVD R8, R2
|
|
||||||
MOVD R8, R3
|
|
||||||
MOVD $0, R4
|
|
||||||
JMP continue
|
|
43
vendor/golang.org/x/crypto/internal/chacha20/xor.go
generated
vendored
43
vendor/golang.org/x/crypto/internal/chacha20/xor.go
generated
vendored
@ -1,43 +0,0 @@
|
|||||||
// Copyright 2018 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found src the LICENSE file.
|
|
||||||
|
|
||||||
package chacha20
|
|
||||||
|
|
||||||
import (
|
|
||||||
"runtime"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Platforms that have fast unaligned 32-bit little endian accesses.
|
|
||||||
const unaligned = runtime.GOARCH == "386" ||
|
|
||||||
runtime.GOARCH == "amd64" ||
|
|
||||||
runtime.GOARCH == "arm64" ||
|
|
||||||
runtime.GOARCH == "ppc64le" ||
|
|
||||||
runtime.GOARCH == "s390x"
|
|
||||||
|
|
||||||
// xor reads a little endian uint32 from src, XORs it with u and
|
|
||||||
// places the result in little endian byte order in dst.
|
|
||||||
func xor(dst, src []byte, u uint32) {
|
|
||||||
_, _ = src[3], dst[3] // eliminate bounds checks
|
|
||||||
if unaligned {
|
|
||||||
// The compiler should optimize this code into
|
|
||||||
// 32-bit unaligned little endian loads and stores.
|
|
||||||
// TODO: delete once the compiler does a reliably
|
|
||||||
// good job with the generic code below.
|
|
||||||
// See issue #25111 for more details.
|
|
||||||
v := uint32(src[0])
|
|
||||||
v |= uint32(src[1]) << 8
|
|
||||||
v |= uint32(src[2]) << 16
|
|
||||||
v |= uint32(src[3]) << 24
|
|
||||||
v ^= u
|
|
||||||
dst[0] = byte(v)
|
|
||||||
dst[1] = byte(v >> 8)
|
|
||||||
dst[2] = byte(v >> 16)
|
|
||||||
dst[3] = byte(v >> 24)
|
|
||||||
} else {
|
|
||||||
dst[0] = src[0] ^ byte(u)
|
|
||||||
dst[1] = src[1] ^ byte(u>>8)
|
|
||||||
dst[2] = src[2] ^ byte(u>>16)
|
|
||||||
dst[3] = src[3] ^ byte(u>>24)
|
|
||||||
}
|
|
||||||
}
|
|
32
vendor/golang.org/x/crypto/internal/subtle/aliasing.go
generated
vendored
32
vendor/golang.org/x/crypto/internal/subtle/aliasing.go
generated
vendored
@ -1,32 +0,0 @@
|
|||||||
// Copyright 2018 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.
|
|
||||||
|
|
||||||
// +build !appengine
|
|
||||||
|
|
||||||
// Package subtle implements functions that are often useful in cryptographic
|
|
||||||
// code but require careful thought to use correctly.
|
|
||||||
package subtle // import "golang.org/x/crypto/internal/subtle"
|
|
||||||
|
|
||||||
import "unsafe"
|
|
||||||
|
|
||||||
// AnyOverlap reports whether x and y share memory at any (not necessarily
|
|
||||||
// corresponding) index. The memory beyond the slice length is ignored.
|
|
||||||
func AnyOverlap(x, y []byte) bool {
|
|
||||||
return len(x) > 0 && len(y) > 0 &&
|
|
||||||
uintptr(unsafe.Pointer(&x[0])) <= uintptr(unsafe.Pointer(&y[len(y)-1])) &&
|
|
||||||
uintptr(unsafe.Pointer(&y[0])) <= uintptr(unsafe.Pointer(&x[len(x)-1]))
|
|
||||||
}
|
|
||||||
|
|
||||||
// InexactOverlap reports whether x and y share memory at any non-corresponding
|
|
||||||
// index. The memory beyond the slice length is ignored. Note that x and y can
|
|
||||||
// have different lengths and still not have any inexact overlap.
|
|
||||||
//
|
|
||||||
// InexactOverlap can be used to implement the requirements of the crypto/cipher
|
|
||||||
// AEAD, Block, BlockMode and Stream interfaces.
|
|
||||||
func InexactOverlap(x, y []byte) bool {
|
|
||||||
if len(x) == 0 || len(y) == 0 || &x[0] == &y[0] {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return AnyOverlap(x, y)
|
|
||||||
}
|
|
35
vendor/golang.org/x/crypto/internal/subtle/aliasing_appengine.go
generated
vendored
35
vendor/golang.org/x/crypto/internal/subtle/aliasing_appengine.go
generated
vendored
@ -1,35 +0,0 @@
|
|||||||
// Copyright 2018 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.
|
|
||||||
|
|
||||||
// +build appengine
|
|
||||||
|
|
||||||
// Package subtle implements functions that are often useful in cryptographic
|
|
||||||
// code but require careful thought to use correctly.
|
|
||||||
package subtle // import "golang.org/x/crypto/internal/subtle"
|
|
||||||
|
|
||||||
// This is the Google App Engine standard variant based on reflect
|
|
||||||
// because the unsafe package and cgo are disallowed.
|
|
||||||
|
|
||||||
import "reflect"
|
|
||||||
|
|
||||||
// AnyOverlap reports whether x and y share memory at any (not necessarily
|
|
||||||
// corresponding) index. The memory beyond the slice length is ignored.
|
|
||||||
func AnyOverlap(x, y []byte) bool {
|
|
||||||
return len(x) > 0 && len(y) > 0 &&
|
|
||||||
reflect.ValueOf(&x[0]).Pointer() <= reflect.ValueOf(&y[len(y)-1]).Pointer() &&
|
|
||||||
reflect.ValueOf(&y[0]).Pointer() <= reflect.ValueOf(&x[len(x)-1]).Pointer()
|
|
||||||
}
|
|
||||||
|
|
||||||
// InexactOverlap reports whether x and y share memory at any non-corresponding
|
|
||||||
// index. The memory beyond the slice length is ignored. Note that x and y can
|
|
||||||
// have different lengths and still not have any inexact overlap.
|
|
||||||
//
|
|
||||||
// InexactOverlap can be used to implement the requirements of the crypto/cipher
|
|
||||||
// AEAD, Block, BlockMode and Stream interfaces.
|
|
||||||
func InexactOverlap(x, y []byte) bool {
|
|
||||||
if len(x) == 0 || len(y) == 0 || &x[0] == &y[0] {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return AnyOverlap(x, y)
|
|
||||||
}
|
|
11
vendor/golang.org/x/crypto/poly1305/mac_noasm.go
generated
vendored
11
vendor/golang.org/x/crypto/poly1305/mac_noasm.go
generated
vendored
@ -1,11 +0,0 @@
|
|||||||
// Copyright 2018 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.
|
|
||||||
|
|
||||||
// +build !amd64,!ppc64le gccgo appengine
|
|
||||||
|
|
||||||
package poly1305
|
|
||||||
|
|
||||||
type mac struct{ macGeneric }
|
|
||||||
|
|
||||||
func newMAC(key *[32]byte) mac { return mac{newMACGeneric(key)} }
|
|
83
vendor/golang.org/x/crypto/poly1305/poly1305.go
generated
vendored
83
vendor/golang.org/x/crypto/poly1305/poly1305.go
generated
vendored
@ -1,83 +0,0 @@
|
|||||||
// 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 poly1305 implements Poly1305 one-time message authentication code as
|
|
||||||
// specified in https://cr.yp.to/mac/poly1305-20050329.pdf.
|
|
||||||
//
|
|
||||||
// Poly1305 is a fast, one-time authentication function. It is infeasible for an
|
|
||||||
// attacker to generate an authenticator for a message without the key. However, a
|
|
||||||
// key must only be used for a single message. Authenticating two different
|
|
||||||
// messages with the same key allows an attacker to forge authenticators for other
|
|
||||||
// messages with the same key.
|
|
||||||
//
|
|
||||||
// Poly1305 was originally coupled with AES in order to make Poly1305-AES. AES was
|
|
||||||
// used with a fixed key in order to generate one-time keys from an nonce.
|
|
||||||
// However, in this package AES isn't used and the one-time key is specified
|
|
||||||
// directly.
|
|
||||||
package poly1305 // import "golang.org/x/crypto/poly1305"
|
|
||||||
|
|
||||||
import "crypto/subtle"
|
|
||||||
|
|
||||||
// TagSize is the size, in bytes, of a poly1305 authenticator.
|
|
||||||
const TagSize = 16
|
|
||||||
|
|
||||||
// Verify returns true if mac is a valid authenticator for m with the given
|
|
||||||
// key.
|
|
||||||
func Verify(mac *[16]byte, m []byte, key *[32]byte) bool {
|
|
||||||
var tmp [16]byte
|
|
||||||
Sum(&tmp, m, key)
|
|
||||||
return subtle.ConstantTimeCompare(tmp[:], mac[:]) == 1
|
|
||||||
}
|
|
||||||
|
|
||||||
// New returns a new MAC computing an authentication
|
|
||||||
// tag of all data written to it with the given key.
|
|
||||||
// This allows writing the message progressively instead
|
|
||||||
// of passing it as a single slice. Common users should use
|
|
||||||
// the Sum function instead.
|
|
||||||
//
|
|
||||||
// The key must be unique for each message, as authenticating
|
|
||||||
// two different messages with the same key allows an attacker
|
|
||||||
// to forge messages at will.
|
|
||||||
func New(key *[32]byte) *MAC {
|
|
||||||
return &MAC{
|
|
||||||
mac: newMAC(key),
|
|
||||||
finalized: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MAC is an io.Writer computing an authentication tag
|
|
||||||
// of the data written to it.
|
|
||||||
//
|
|
||||||
// MAC cannot be used like common hash.Hash implementations,
|
|
||||||
// because using a poly1305 key twice breaks its security.
|
|
||||||
// Therefore writing data to a running MAC after calling
|
|
||||||
// Sum causes it to panic.
|
|
||||||
type MAC struct {
|
|
||||||
mac // platform-dependent implementation
|
|
||||||
|
|
||||||
finalized bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// Size returns the number of bytes Sum will return.
|
|
||||||
func (h *MAC) Size() int { return TagSize }
|
|
||||||
|
|
||||||
// Write adds more data to the running message authentication code.
|
|
||||||
// It never returns an error.
|
|
||||||
//
|
|
||||||
// It must not be called after the first call of Sum.
|
|
||||||
func (h *MAC) Write(p []byte) (n int, err error) {
|
|
||||||
if h.finalized {
|
|
||||||
panic("poly1305: write to MAC after Sum")
|
|
||||||
}
|
|
||||||
return h.mac.Write(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sum computes the authenticator of all data written to the
|
|
||||||
// message authentication code.
|
|
||||||
func (h *MAC) Sum(b []byte) []byte {
|
|
||||||
var mac [TagSize]byte
|
|
||||||
h.mac.Sum(&mac)
|
|
||||||
h.finalized = true
|
|
||||||
return append(b, mac[:]...)
|
|
||||||
}
|
|
68
vendor/golang.org/x/crypto/poly1305/sum_amd64.go
generated
vendored
68
vendor/golang.org/x/crypto/poly1305/sum_amd64.go
generated
vendored
@ -1,68 +0,0 @@
|
|||||||
// 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.
|
|
||||||
|
|
||||||
// +build amd64,!gccgo,!appengine
|
|
||||||
|
|
||||||
package poly1305
|
|
||||||
|
|
||||||
//go:noescape
|
|
||||||
func initialize(state *[7]uint64, key *[32]byte)
|
|
||||||
|
|
||||||
//go:noescape
|
|
||||||
func update(state *[7]uint64, msg []byte)
|
|
||||||
|
|
||||||
//go:noescape
|
|
||||||
func finalize(tag *[TagSize]byte, state *[7]uint64)
|
|
||||||
|
|
||||||
// Sum generates an authenticator for m using a one-time key and puts the
|
|
||||||
// 16-byte result into out. Authenticating two different messages with the same
|
|
||||||
// key allows an attacker to forge messages at will.
|
|
||||||
func Sum(out *[16]byte, m []byte, key *[32]byte) {
|
|
||||||
h := newMAC(key)
|
|
||||||
h.Write(m)
|
|
||||||
h.Sum(out)
|
|
||||||
}
|
|
||||||
|
|
||||||
func newMAC(key *[32]byte) (h mac) {
|
|
||||||
initialize(&h.state, key)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
type mac struct {
|
|
||||||
state [7]uint64 // := uint64{ h0, h1, h2, r0, r1, pad0, pad1 }
|
|
||||||
|
|
||||||
buffer [TagSize]byte
|
|
||||||
offset int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *mac) Write(p []byte) (n int, err error) {
|
|
||||||
n = len(p)
|
|
||||||
if h.offset > 0 {
|
|
||||||
remaining := TagSize - h.offset
|
|
||||||
if n < remaining {
|
|
||||||
h.offset += copy(h.buffer[h.offset:], p)
|
|
||||||
return n, nil
|
|
||||||
}
|
|
||||||
copy(h.buffer[h.offset:], p[:remaining])
|
|
||||||
p = p[remaining:]
|
|
||||||
h.offset = 0
|
|
||||||
update(&h.state, h.buffer[:])
|
|
||||||
}
|
|
||||||
if nn := len(p) - (len(p) % TagSize); nn > 0 {
|
|
||||||
update(&h.state, p[:nn])
|
|
||||||
p = p[nn:]
|
|
||||||
}
|
|
||||||
if len(p) > 0 {
|
|
||||||
h.offset += copy(h.buffer[h.offset:], p)
|
|
||||||
}
|
|
||||||
return n, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *mac) Sum(out *[16]byte) {
|
|
||||||
state := h.state
|
|
||||||
if h.offset > 0 {
|
|
||||||
update(&state, h.buffer[:h.offset])
|
|
||||||
}
|
|
||||||
finalize(out, &state)
|
|
||||||
}
|
|
148
vendor/golang.org/x/crypto/poly1305/sum_amd64.s
generated
vendored
148
vendor/golang.org/x/crypto/poly1305/sum_amd64.s
generated
vendored
@ -1,148 +0,0 @@
|
|||||||
// 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.
|
|
||||||
|
|
||||||
// +build amd64,!gccgo,!appengine
|
|
||||||
|
|
||||||
#include "textflag.h"
|
|
||||||
|
|
||||||
#define POLY1305_ADD(msg, h0, h1, h2) \
|
|
||||||
ADDQ 0(msg), h0; \
|
|
||||||
ADCQ 8(msg), h1; \
|
|
||||||
ADCQ $1, h2; \
|
|
||||||
LEAQ 16(msg), msg
|
|
||||||
|
|
||||||
#define POLY1305_MUL(h0, h1, h2, r0, r1, t0, t1, t2, t3) \
|
|
||||||
MOVQ r0, AX; \
|
|
||||||
MULQ h0; \
|
|
||||||
MOVQ AX, t0; \
|
|
||||||
MOVQ DX, t1; \
|
|
||||||
MOVQ r0, AX; \
|
|
||||||
MULQ h1; \
|
|
||||||
ADDQ AX, t1; \
|
|
||||||
ADCQ $0, DX; \
|
|
||||||
MOVQ r0, t2; \
|
|
||||||
IMULQ h2, t2; \
|
|
||||||
ADDQ DX, t2; \
|
|
||||||
\
|
|
||||||
MOVQ r1, AX; \
|
|
||||||
MULQ h0; \
|
|
||||||
ADDQ AX, t1; \
|
|
||||||
ADCQ $0, DX; \
|
|
||||||
MOVQ DX, h0; \
|
|
||||||
MOVQ r1, t3; \
|
|
||||||
IMULQ h2, t3; \
|
|
||||||
MOVQ r1, AX; \
|
|
||||||
MULQ h1; \
|
|
||||||
ADDQ AX, t2; \
|
|
||||||
ADCQ DX, t3; \
|
|
||||||
ADDQ h0, t2; \
|
|
||||||
ADCQ $0, t3; \
|
|
||||||
\
|
|
||||||
MOVQ t0, h0; \
|
|
||||||
MOVQ t1, h1; \
|
|
||||||
MOVQ t2, h2; \
|
|
||||||
ANDQ $3, h2; \
|
|
||||||
MOVQ t2, t0; \
|
|
||||||
ANDQ $0xFFFFFFFFFFFFFFFC, t0; \
|
|
||||||
ADDQ t0, h0; \
|
|
||||||
ADCQ t3, h1; \
|
|
||||||
ADCQ $0, h2; \
|
|
||||||
SHRQ $2, t3, t2; \
|
|
||||||
SHRQ $2, t3; \
|
|
||||||
ADDQ t2, h0; \
|
|
||||||
ADCQ t3, h1; \
|
|
||||||
ADCQ $0, h2
|
|
||||||
|
|
||||||
DATA ·poly1305Mask<>+0x00(SB)/8, $0x0FFFFFFC0FFFFFFF
|
|
||||||
DATA ·poly1305Mask<>+0x08(SB)/8, $0x0FFFFFFC0FFFFFFC
|
|
||||||
GLOBL ·poly1305Mask<>(SB), RODATA, $16
|
|
||||||
|
|
||||||
// func update(state *[7]uint64, msg []byte)
|
|
||||||
TEXT ·update(SB), $0-32
|
|
||||||
MOVQ state+0(FP), DI
|
|
||||||
MOVQ msg_base+8(FP), SI
|
|
||||||
MOVQ msg_len+16(FP), R15
|
|
||||||
|
|
||||||
MOVQ 0(DI), R8 // h0
|
|
||||||
MOVQ 8(DI), R9 // h1
|
|
||||||
MOVQ 16(DI), R10 // h2
|
|
||||||
MOVQ 24(DI), R11 // r0
|
|
||||||
MOVQ 32(DI), R12 // r1
|
|
||||||
|
|
||||||
CMPQ R15, $16
|
|
||||||
JB bytes_between_0_and_15
|
|
||||||
|
|
||||||
loop:
|
|
||||||
POLY1305_ADD(SI, R8, R9, R10)
|
|
||||||
|
|
||||||
multiply:
|
|
||||||
POLY1305_MUL(R8, R9, R10, R11, R12, BX, CX, R13, R14)
|
|
||||||
SUBQ $16, R15
|
|
||||||
CMPQ R15, $16
|
|
||||||
JAE loop
|
|
||||||
|
|
||||||
bytes_between_0_and_15:
|
|
||||||
TESTQ R15, R15
|
|
||||||
JZ done
|
|
||||||
MOVQ $1, BX
|
|
||||||
XORQ CX, CX
|
|
||||||
XORQ R13, R13
|
|
||||||
ADDQ R15, SI
|
|
||||||
|
|
||||||
flush_buffer:
|
|
||||||
SHLQ $8, BX, CX
|
|
||||||
SHLQ $8, BX
|
|
||||||
MOVB -1(SI), R13
|
|
||||||
XORQ R13, BX
|
|
||||||
DECQ SI
|
|
||||||
DECQ R15
|
|
||||||
JNZ flush_buffer
|
|
||||||
|
|
||||||
ADDQ BX, R8
|
|
||||||
ADCQ CX, R9
|
|
||||||
ADCQ $0, R10
|
|
||||||
MOVQ $16, R15
|
|
||||||
JMP multiply
|
|
||||||
|
|
||||||
done:
|
|
||||||
MOVQ R8, 0(DI)
|
|
||||||
MOVQ R9, 8(DI)
|
|
||||||
MOVQ R10, 16(DI)
|
|
||||||
RET
|
|
||||||
|
|
||||||
// func initialize(state *[7]uint64, key *[32]byte)
|
|
||||||
TEXT ·initialize(SB), $0-16
|
|
||||||
MOVQ state+0(FP), DI
|
|
||||||
MOVQ key+8(FP), SI
|
|
||||||
|
|
||||||
// state[0...7] is initialized with zero
|
|
||||||
MOVOU 0(SI), X0
|
|
||||||
MOVOU 16(SI), X1
|
|
||||||
MOVOU ·poly1305Mask<>(SB), X2
|
|
||||||
PAND X2, X0
|
|
||||||
MOVOU X0, 24(DI)
|
|
||||||
MOVOU X1, 40(DI)
|
|
||||||
RET
|
|
||||||
|
|
||||||
// func finalize(tag *[TagSize]byte, state *[7]uint64)
|
|
||||||
TEXT ·finalize(SB), $0-16
|
|
||||||
MOVQ tag+0(FP), DI
|
|
||||||
MOVQ state+8(FP), SI
|
|
||||||
|
|
||||||
MOVQ 0(SI), AX
|
|
||||||
MOVQ 8(SI), BX
|
|
||||||
MOVQ 16(SI), CX
|
|
||||||
MOVQ AX, R8
|
|
||||||
MOVQ BX, R9
|
|
||||||
SUBQ $0xFFFFFFFFFFFFFFFB, AX
|
|
||||||
SBBQ $0xFFFFFFFFFFFFFFFF, BX
|
|
||||||
SBBQ $3, CX
|
|
||||||
CMOVQCS R8, AX
|
|
||||||
CMOVQCS R9, BX
|
|
||||||
ADDQ 40(SI), AX
|
|
||||||
ADCQ 48(SI), BX
|
|
||||||
|
|
||||||
MOVQ AX, 0(DI)
|
|
||||||
MOVQ BX, 8(DI)
|
|
||||||
RET
|
|
22
vendor/golang.org/x/crypto/poly1305/sum_arm.go
generated
vendored
22
vendor/golang.org/x/crypto/poly1305/sum_arm.go
generated
vendored
@ -1,22 +0,0 @@
|
|||||||
// Copyright 2015 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.
|
|
||||||
|
|
||||||
// +build arm,!gccgo,!appengine,!nacl
|
|
||||||
|
|
||||||
package poly1305
|
|
||||||
|
|
||||||
// This function is implemented in sum_arm.s
|
|
||||||
//go:noescape
|
|
||||||
func poly1305_auth_armv6(out *[16]byte, m *byte, mlen uint32, key *[32]byte)
|
|
||||||
|
|
||||||
// Sum generates an authenticator for m using a one-time key and puts the
|
|
||||||
// 16-byte result into out. Authenticating two different messages with the same
|
|
||||||
// key allows an attacker to forge messages at will.
|
|
||||||
func Sum(out *[16]byte, m []byte, key *[32]byte) {
|
|
||||||
var mPtr *byte
|
|
||||||
if len(m) > 0 {
|
|
||||||
mPtr = &m[0]
|
|
||||||
}
|
|
||||||
poly1305_auth_armv6(out, mPtr, uint32(len(m)), key)
|
|
||||||
}
|
|
427
vendor/golang.org/x/crypto/poly1305/sum_arm.s
generated
vendored
427
vendor/golang.org/x/crypto/poly1305/sum_arm.s
generated
vendored
@ -1,427 +0,0 @@
|
|||||||
// Copyright 2015 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.
|
|
||||||
|
|
||||||
// +build arm,!gccgo,!appengine,!nacl
|
|
||||||
|
|
||||||
#include "textflag.h"
|
|
||||||
|
|
||||||
// This code was translated into a form compatible with 5a from the public
|
|
||||||
// domain source by Andrew Moon: github.com/floodyberry/poly1305-opt/blob/master/app/extensions/poly1305.
|
|
||||||
|
|
||||||
DATA ·poly1305_init_constants_armv6<>+0x00(SB)/4, $0x3ffffff
|
|
||||||
DATA ·poly1305_init_constants_armv6<>+0x04(SB)/4, $0x3ffff03
|
|
||||||
DATA ·poly1305_init_constants_armv6<>+0x08(SB)/4, $0x3ffc0ff
|
|
||||||
DATA ·poly1305_init_constants_armv6<>+0x0c(SB)/4, $0x3f03fff
|
|
||||||
DATA ·poly1305_init_constants_armv6<>+0x10(SB)/4, $0x00fffff
|
|
||||||
GLOBL ·poly1305_init_constants_armv6<>(SB), 8, $20
|
|
||||||
|
|
||||||
// Warning: the linker may use R11 to synthesize certain instructions. Please
|
|
||||||
// take care and verify that no synthetic instructions use it.
|
|
||||||
|
|
||||||
TEXT poly1305_init_ext_armv6<>(SB), NOSPLIT, $0
|
|
||||||
// Needs 16 bytes of stack and 64 bytes of space pointed to by R0. (It
|
|
||||||
// might look like it's only 60 bytes of space but the final four bytes
|
|
||||||
// will be written by another function.) We need to skip over four
|
|
||||||
// bytes of stack because that's saving the value of 'g'.
|
|
||||||
ADD $4, R13, R8
|
|
||||||
MOVM.IB [R4-R7], (R8)
|
|
||||||
MOVM.IA.W (R1), [R2-R5]
|
|
||||||
MOVW $·poly1305_init_constants_armv6<>(SB), R7
|
|
||||||
MOVW R2, R8
|
|
||||||
MOVW R2>>26, R9
|
|
||||||
MOVW R3>>20, g
|
|
||||||
MOVW R4>>14, R11
|
|
||||||
MOVW R5>>8, R12
|
|
||||||
ORR R3<<6, R9, R9
|
|
||||||
ORR R4<<12, g, g
|
|
||||||
ORR R5<<18, R11, R11
|
|
||||||
MOVM.IA (R7), [R2-R6]
|
|
||||||
AND R8, R2, R2
|
|
||||||
AND R9, R3, R3
|
|
||||||
AND g, R4, R4
|
|
||||||
AND R11, R5, R5
|
|
||||||
AND R12, R6, R6
|
|
||||||
MOVM.IA.W [R2-R6], (R0)
|
|
||||||
EOR R2, R2, R2
|
|
||||||
EOR R3, R3, R3
|
|
||||||
EOR R4, R4, R4
|
|
||||||
EOR R5, R5, R5
|
|
||||||
EOR R6, R6, R6
|
|
||||||
MOVM.IA.W [R2-R6], (R0)
|
|
||||||
MOVM.IA.W (R1), [R2-R5]
|
|
||||||
MOVM.IA [R2-R6], (R0)
|
|
||||||
ADD $20, R13, R0
|
|
||||||
MOVM.DA (R0), [R4-R7]
|
|
||||||
RET
|
|
||||||
|
|
||||||
#define MOVW_UNALIGNED(Rsrc, Rdst, Rtmp, offset) \
|
|
||||||
MOVBU (offset+0)(Rsrc), Rtmp; \
|
|
||||||
MOVBU Rtmp, (offset+0)(Rdst); \
|
|
||||||
MOVBU (offset+1)(Rsrc), Rtmp; \
|
|
||||||
MOVBU Rtmp, (offset+1)(Rdst); \
|
|
||||||
MOVBU (offset+2)(Rsrc), Rtmp; \
|
|
||||||
MOVBU Rtmp, (offset+2)(Rdst); \
|
|
||||||
MOVBU (offset+3)(Rsrc), Rtmp; \
|
|
||||||
MOVBU Rtmp, (offset+3)(Rdst)
|
|
||||||
|
|
||||||
TEXT poly1305_blocks_armv6<>(SB), NOSPLIT, $0
|
|
||||||
// Needs 24 bytes of stack for saved registers and then 88 bytes of
|
|
||||||
// scratch space after that. We assume that 24 bytes at (R13) have
|
|
||||||
// already been used: four bytes for the link register saved in the
|
|
||||||
// prelude of poly1305_auth_armv6, four bytes for saving the value of g
|
|
||||||
// in that function and 16 bytes of scratch space used around
|
|
||||||
// poly1305_finish_ext_armv6_skip1.
|
|
||||||
ADD $24, R13, R12
|
|
||||||
MOVM.IB [R4-R8, R14], (R12)
|
|
||||||
MOVW R0, 88(R13)
|
|
||||||
MOVW R1, 92(R13)
|
|
||||||
MOVW R2, 96(R13)
|
|
||||||
MOVW R1, R14
|
|
||||||
MOVW R2, R12
|
|
||||||
MOVW 56(R0), R8
|
|
||||||
WORD $0xe1180008 // TST R8, R8 not working see issue 5921
|
|
||||||
EOR R6, R6, R6
|
|
||||||
MOVW.EQ $(1<<24), R6
|
|
||||||
MOVW R6, 84(R13)
|
|
||||||
ADD $116, R13, g
|
|
||||||
MOVM.IA (R0), [R0-R9]
|
|
||||||
MOVM.IA [R0-R4], (g)
|
|
||||||
CMP $16, R12
|
|
||||||
BLO poly1305_blocks_armv6_done
|
|
||||||
|
|
||||||
poly1305_blocks_armv6_mainloop:
|
|
||||||
WORD $0xe31e0003 // TST R14, #3 not working see issue 5921
|
|
||||||
BEQ poly1305_blocks_armv6_mainloop_aligned
|
|
||||||
ADD $100, R13, g
|
|
||||||
MOVW_UNALIGNED(R14, g, R0, 0)
|
|
||||||
MOVW_UNALIGNED(R14, g, R0, 4)
|
|
||||||
MOVW_UNALIGNED(R14, g, R0, 8)
|
|
||||||
MOVW_UNALIGNED(R14, g, R0, 12)
|
|
||||||
MOVM.IA (g), [R0-R3]
|
|
||||||
ADD $16, R14
|
|
||||||
B poly1305_blocks_armv6_mainloop_loaded
|
|
||||||
|
|
||||||
poly1305_blocks_armv6_mainloop_aligned:
|
|
||||||
MOVM.IA.W (R14), [R0-R3]
|
|
||||||
|
|
||||||
poly1305_blocks_armv6_mainloop_loaded:
|
|
||||||
MOVW R0>>26, g
|
|
||||||
MOVW R1>>20, R11
|
|
||||||
MOVW R2>>14, R12
|
|
||||||
MOVW R14, 92(R13)
|
|
||||||
MOVW R3>>8, R4
|
|
||||||
ORR R1<<6, g, g
|
|
||||||
ORR R2<<12, R11, R11
|
|
||||||
ORR R3<<18, R12, R12
|
|
||||||
BIC $0xfc000000, R0, R0
|
|
||||||
BIC $0xfc000000, g, g
|
|
||||||
MOVW 84(R13), R3
|
|
||||||
BIC $0xfc000000, R11, R11
|
|
||||||
BIC $0xfc000000, R12, R12
|
|
||||||
ADD R0, R5, R5
|
|
||||||
ADD g, R6, R6
|
|
||||||
ORR R3, R4, R4
|
|
||||||
ADD R11, R7, R7
|
|
||||||
ADD $116, R13, R14
|
|
||||||
ADD R12, R8, R8
|
|
||||||
ADD R4, R9, R9
|
|
||||||
MOVM.IA (R14), [R0-R4]
|
|
||||||
MULLU R4, R5, (R11, g)
|
|
||||||
MULLU R3, R5, (R14, R12)
|
|
||||||
MULALU R3, R6, (R11, g)
|
|
||||||
MULALU R2, R6, (R14, R12)
|
|
||||||
MULALU R2, R7, (R11, g)
|
|
||||||
MULALU R1, R7, (R14, R12)
|
|
||||||
ADD R4<<2, R4, R4
|
|
||||||
ADD R3<<2, R3, R3
|
|
||||||
MULALU R1, R8, (R11, g)
|
|
||||||
MULALU R0, R8, (R14, R12)
|
|
||||||
MULALU R0, R9, (R11, g)
|
|
||||||
MULALU R4, R9, (R14, R12)
|
|
||||||
MOVW g, 76(R13)
|
|
||||||
MOVW R11, 80(R13)
|
|
||||||
MOVW R12, 68(R13)
|
|
||||||
MOVW R14, 72(R13)
|
|
||||||
MULLU R2, R5, (R11, g)
|
|
||||||
MULLU R1, R5, (R14, R12)
|
|
||||||
MULALU R1, R6, (R11, g)
|
|
||||||
MULALU R0, R6, (R14, R12)
|
|
||||||
MULALU R0, R7, (R11, g)
|
|
||||||
MULALU R4, R7, (R14, R12)
|
|
||||||
ADD R2<<2, R2, R2
|
|
||||||
ADD R1<<2, R1, R1
|
|
||||||
MULALU R4, R8, (R11, g)
|
|
||||||
MULALU R3, R8, (R14, R12)
|
|
||||||
MULALU R3, R9, (R11, g)
|
|
||||||
MULALU R2, R9, (R14, R12)
|
|
||||||
MOVW g, 60(R13)
|
|
||||||
MOVW R11, 64(R13)
|
|
||||||
MOVW R12, 52(R13)
|
|
||||||
MOVW R14, 56(R13)
|
|
||||||
MULLU R0, R5, (R11, g)
|
|
||||||
MULALU R4, R6, (R11, g)
|
|
||||||
MULALU R3, R7, (R11, g)
|
|
||||||
MULALU R2, R8, (R11, g)
|
|
||||||
MULALU R1, R9, (R11, g)
|
|
||||||
ADD $52, R13, R0
|
|
||||||
MOVM.IA (R0), [R0-R7]
|
|
||||||
MOVW g>>26, R12
|
|
||||||
MOVW R4>>26, R14
|
|
||||||
ORR R11<<6, R12, R12
|
|
||||||
ORR R5<<6, R14, R14
|
|
||||||
BIC $0xfc000000, g, g
|
|
||||||
BIC $0xfc000000, R4, R4
|
|
||||||
ADD.S R12, R0, R0
|
|
||||||
ADC $0, R1, R1
|
|
||||||
ADD.S R14, R6, R6
|
|
||||||
ADC $0, R7, R7
|
|
||||||
MOVW R0>>26, R12
|
|
||||||
MOVW R6>>26, R14
|
|
||||||
ORR R1<<6, R12, R12
|
|
||||||
ORR R7<<6, R14, R14
|
|
||||||
BIC $0xfc000000, R0, R0
|
|
||||||
BIC $0xfc000000, R6, R6
|
|
||||||
ADD R14<<2, R14, R14
|
|
||||||
ADD.S R12, R2, R2
|
|
||||||
ADC $0, R3, R3
|
|
||||||
ADD R14, g, g
|
|
||||||
MOVW R2>>26, R12
|
|
||||||
MOVW g>>26, R14
|
|
||||||
ORR R3<<6, R12, R12
|
|
||||||
BIC $0xfc000000, g, R5
|
|
||||||
BIC $0xfc000000, R2, R7
|
|
||||||
ADD R12, R4, R4
|
|
||||||
ADD R14, R0, R0
|
|
||||||
MOVW R4>>26, R12
|
|
||||||
BIC $0xfc000000, R4, R8
|
|
||||||
ADD R12, R6, R9
|
|
||||||
MOVW 96(R13), R12
|
|
||||||
MOVW 92(R13), R14
|
|
||||||
MOVW R0, R6
|
|
||||||
CMP $32, R12
|
|
||||||
SUB $16, R12, R12
|
|
||||||
MOVW R12, 96(R13)
|
|
||||||
BHS poly1305_blocks_armv6_mainloop
|
|
||||||
|
|
||||||
poly1305_blocks_armv6_done:
|
|
||||||
MOVW 88(R13), R12
|
|
||||||
MOVW R5, 20(R12)
|
|
||||||
MOVW R6, 24(R12)
|
|
||||||
MOVW R7, 28(R12)
|
|
||||||
MOVW R8, 32(R12)
|
|
||||||
MOVW R9, 36(R12)
|
|
||||||
ADD $48, R13, R0
|
|
||||||
MOVM.DA (R0), [R4-R8, R14]
|
|
||||||
RET
|
|
||||||
|
|
||||||
#define MOVHUP_UNALIGNED(Rsrc, Rdst, Rtmp) \
|
|
||||||
MOVBU.P 1(Rsrc), Rtmp; \
|
|
||||||
MOVBU.P Rtmp, 1(Rdst); \
|
|
||||||
MOVBU.P 1(Rsrc), Rtmp; \
|
|
||||||
MOVBU.P Rtmp, 1(Rdst)
|
|
||||||
|
|
||||||
#define MOVWP_UNALIGNED(Rsrc, Rdst, Rtmp) \
|
|
||||||
MOVHUP_UNALIGNED(Rsrc, Rdst, Rtmp); \
|
|
||||||
MOVHUP_UNALIGNED(Rsrc, Rdst, Rtmp)
|
|
||||||
|
|
||||||
// func poly1305_auth_armv6(out *[16]byte, m *byte, mlen uint32, key *[32]key)
|
|
||||||
TEXT ·poly1305_auth_armv6(SB), $196-16
|
|
||||||
// The value 196, just above, is the sum of 64 (the size of the context
|
|
||||||
// structure) and 132 (the amount of stack needed).
|
|
||||||
//
|
|
||||||
// At this point, the stack pointer (R13) has been moved down. It
|
|
||||||
// points to the saved link register and there's 196 bytes of free
|
|
||||||
// space above it.
|
|
||||||
//
|
|
||||||
// The stack for this function looks like:
|
|
||||||
//
|
|
||||||
// +---------------------
|
|
||||||
// |
|
|
||||||
// | 64 bytes of context structure
|
|
||||||
// |
|
|
||||||
// +---------------------
|
|
||||||
// |
|
|
||||||
// | 112 bytes for poly1305_blocks_armv6
|
|
||||||
// |
|
|
||||||
// +---------------------
|
|
||||||
// | 16 bytes of final block, constructed at
|
|
||||||
// | poly1305_finish_ext_armv6_skip8
|
|
||||||
// +---------------------
|
|
||||||
// | four bytes of saved 'g'
|
|
||||||
// +---------------------
|
|
||||||
// | lr, saved by prelude <- R13 points here
|
|
||||||
// +---------------------
|
|
||||||
MOVW g, 4(R13)
|
|
||||||
|
|
||||||
MOVW out+0(FP), R4
|
|
||||||
MOVW m+4(FP), R5
|
|
||||||
MOVW mlen+8(FP), R6
|
|
||||||
MOVW key+12(FP), R7
|
|
||||||
|
|
||||||
ADD $136, R13, R0 // 136 = 4 + 4 + 16 + 112
|
|
||||||
MOVW R7, R1
|
|
||||||
|
|
||||||
// poly1305_init_ext_armv6 will write to the stack from R13+4, but
|
|
||||||
// that's ok because none of the other values have been written yet.
|
|
||||||
BL poly1305_init_ext_armv6<>(SB)
|
|
||||||
BIC.S $15, R6, R2
|
|
||||||
BEQ poly1305_auth_armv6_noblocks
|
|
||||||
ADD $136, R13, R0
|
|
||||||
MOVW R5, R1
|
|
||||||
ADD R2, R5, R5
|
|
||||||
SUB R2, R6, R6
|
|
||||||
BL poly1305_blocks_armv6<>(SB)
|
|
||||||
|
|
||||||
poly1305_auth_armv6_noblocks:
|
|
||||||
ADD $136, R13, R0
|
|
||||||
MOVW R5, R1
|
|
||||||
MOVW R6, R2
|
|
||||||
MOVW R4, R3
|
|
||||||
|
|
||||||
MOVW R0, R5
|
|
||||||
MOVW R1, R6
|
|
||||||
MOVW R2, R7
|
|
||||||
MOVW R3, R8
|
|
||||||
AND.S R2, R2, R2
|
|
||||||
BEQ poly1305_finish_ext_armv6_noremaining
|
|
||||||
EOR R0, R0
|
|
||||||
ADD $8, R13, R9 // 8 = offset to 16 byte scratch space
|
|
||||||
MOVW R0, (R9)
|
|
||||||
MOVW R0, 4(R9)
|
|
||||||
MOVW R0, 8(R9)
|
|
||||||
MOVW R0, 12(R9)
|
|
||||||
WORD $0xe3110003 // TST R1, #3 not working see issue 5921
|
|
||||||
BEQ poly1305_finish_ext_armv6_aligned
|
|
||||||
WORD $0xe3120008 // TST R2, #8 not working see issue 5921
|
|
||||||
BEQ poly1305_finish_ext_armv6_skip8
|
|
||||||
MOVWP_UNALIGNED(R1, R9, g)
|
|
||||||
MOVWP_UNALIGNED(R1, R9, g)
|
|
||||||
|
|
||||||
poly1305_finish_ext_armv6_skip8:
|
|
||||||
WORD $0xe3120004 // TST $4, R2 not working see issue 5921
|
|
||||||
BEQ poly1305_finish_ext_armv6_skip4
|
|
||||||
MOVWP_UNALIGNED(R1, R9, g)
|
|
||||||
|
|
||||||
poly1305_finish_ext_armv6_skip4:
|
|
||||||
WORD $0xe3120002 // TST $2, R2 not working see issue 5921
|
|
||||||
BEQ poly1305_finish_ext_armv6_skip2
|
|
||||||
MOVHUP_UNALIGNED(R1, R9, g)
|
|
||||||
B poly1305_finish_ext_armv6_skip2
|
|
||||||
|
|
||||||
poly1305_finish_ext_armv6_aligned:
|
|
||||||
WORD $0xe3120008 // TST R2, #8 not working see issue 5921
|
|
||||||
BEQ poly1305_finish_ext_armv6_skip8_aligned
|
|
||||||
MOVM.IA.W (R1), [g-R11]
|
|
||||||
MOVM.IA.W [g-R11], (R9)
|
|
||||||
|
|
||||||
poly1305_finish_ext_armv6_skip8_aligned:
|
|
||||||
WORD $0xe3120004 // TST $4, R2 not working see issue 5921
|
|
||||||
BEQ poly1305_finish_ext_armv6_skip4_aligned
|
|
||||||
MOVW.P 4(R1), g
|
|
||||||
MOVW.P g, 4(R9)
|
|
||||||
|
|
||||||
poly1305_finish_ext_armv6_skip4_aligned:
|
|
||||||
WORD $0xe3120002 // TST $2, R2 not working see issue 5921
|
|
||||||
BEQ poly1305_finish_ext_armv6_skip2
|
|
||||||
MOVHU.P 2(R1), g
|
|
||||||
MOVH.P g, 2(R9)
|
|
||||||
|
|
||||||
poly1305_finish_ext_armv6_skip2:
|
|
||||||
WORD $0xe3120001 // TST $1, R2 not working see issue 5921
|
|
||||||
BEQ poly1305_finish_ext_armv6_skip1
|
|
||||||
MOVBU.P 1(R1), g
|
|
||||||
MOVBU.P g, 1(R9)
|
|
||||||
|
|
||||||
poly1305_finish_ext_armv6_skip1:
|
|
||||||
MOVW $1, R11
|
|
||||||
MOVBU R11, 0(R9)
|
|
||||||
MOVW R11, 56(R5)
|
|
||||||
MOVW R5, R0
|
|
||||||
ADD $8, R13, R1
|
|
||||||
MOVW $16, R2
|
|
||||||
BL poly1305_blocks_armv6<>(SB)
|
|
||||||
|
|
||||||
poly1305_finish_ext_armv6_noremaining:
|
|
||||||
MOVW 20(R5), R0
|
|
||||||
MOVW 24(R5), R1
|
|
||||||
MOVW 28(R5), R2
|
|
||||||
MOVW 32(R5), R3
|
|
||||||
MOVW 36(R5), R4
|
|
||||||
MOVW R4>>26, R12
|
|
||||||
BIC $0xfc000000, R4, R4
|
|
||||||
ADD R12<<2, R12, R12
|
|
||||||
ADD R12, R0, R0
|
|
||||||
MOVW R0>>26, R12
|
|
||||||
BIC $0xfc000000, R0, R0
|
|
||||||
ADD R12, R1, R1
|
|
||||||
MOVW R1>>26, R12
|
|
||||||
BIC $0xfc000000, R1, R1
|
|
||||||
ADD R12, R2, R2
|
|
||||||
MOVW R2>>26, R12
|
|
||||||
BIC $0xfc000000, R2, R2
|
|
||||||
ADD R12, R3, R3
|
|
||||||
MOVW R3>>26, R12
|
|
||||||
BIC $0xfc000000, R3, R3
|
|
||||||
ADD R12, R4, R4
|
|
||||||
ADD $5, R0, R6
|
|
||||||
MOVW R6>>26, R12
|
|
||||||
BIC $0xfc000000, R6, R6
|
|
||||||
ADD R12, R1, R7
|
|
||||||
MOVW R7>>26, R12
|
|
||||||
BIC $0xfc000000, R7, R7
|
|
||||||
ADD R12, R2, g
|
|
||||||
MOVW g>>26, R12
|
|
||||||
BIC $0xfc000000, g, g
|
|
||||||
ADD R12, R3, R11
|
|
||||||
MOVW $-(1<<26), R12
|
|
||||||
ADD R11>>26, R12, R12
|
|
||||||
BIC $0xfc000000, R11, R11
|
|
||||||
ADD R12, R4, R9
|
|
||||||
MOVW R9>>31, R12
|
|
||||||
SUB $1, R12
|
|
||||||
AND R12, R6, R6
|
|
||||||
AND R12, R7, R7
|
|
||||||
AND R12, g, g
|
|
||||||
AND R12, R11, R11
|
|
||||||
AND R12, R9, R9
|
|
||||||
MVN R12, R12
|
|
||||||
AND R12, R0, R0
|
|
||||||
AND R12, R1, R1
|
|
||||||
AND R12, R2, R2
|
|
||||||
AND R12, R3, R3
|
|
||||||
AND R12, R4, R4
|
|
||||||
ORR R6, R0, R0
|
|
||||||
ORR R7, R1, R1
|
|
||||||
ORR g, R2, R2
|
|
||||||
ORR R11, R3, R3
|
|
||||||
ORR R9, R4, R4
|
|
||||||
ORR R1<<26, R0, R0
|
|
||||||
MOVW R1>>6, R1
|
|
||||||
ORR R2<<20, R1, R1
|
|
||||||
MOVW R2>>12, R2
|
|
||||||
ORR R3<<14, R2, R2
|
|
||||||
MOVW R3>>18, R3
|
|
||||||
ORR R4<<8, R3, R3
|
|
||||||
MOVW 40(R5), R6
|
|
||||||
MOVW 44(R5), R7
|
|
||||||
MOVW 48(R5), g
|
|
||||||
MOVW 52(R5), R11
|
|
||||||
ADD.S R6, R0, R0
|
|
||||||
ADC.S R7, R1, R1
|
|
||||||
ADC.S g, R2, R2
|
|
||||||
ADC.S R11, R3, R3
|
|
||||||
MOVM.IA [R0-R3], (R8)
|
|
||||||
MOVW R5, R12
|
|
||||||
EOR R0, R0, R0
|
|
||||||
EOR R1, R1, R1
|
|
||||||
EOR R2, R2, R2
|
|
||||||
EOR R3, R3, R3
|
|
||||||
EOR R4, R4, R4
|
|
||||||
EOR R5, R5, R5
|
|
||||||
EOR R6, R6, R6
|
|
||||||
EOR R7, R7, R7
|
|
||||||
MOVM.IA.W [R0-R7], (R12)
|
|
||||||
MOVM.IA [R0-R7], (R12)
|
|
||||||
MOVW 4(R13), g
|
|
||||||
RET
|
|
172
vendor/golang.org/x/crypto/poly1305/sum_generic.go
generated
vendored
172
vendor/golang.org/x/crypto/poly1305/sum_generic.go
generated
vendored
@ -1,172 +0,0 @@
|
|||||||
// Copyright 2018 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 poly1305
|
|
||||||
|
|
||||||
import "encoding/binary"
|
|
||||||
|
|
||||||
const (
|
|
||||||
msgBlock = uint32(1 << 24)
|
|
||||||
finalBlock = uint32(0)
|
|
||||||
)
|
|
||||||
|
|
||||||
// sumGeneric generates an authenticator for msg using a one-time key and
|
|
||||||
// puts the 16-byte result into out. This is the generic implementation of
|
|
||||||
// Sum and should be called if no assembly implementation is available.
|
|
||||||
func sumGeneric(out *[TagSize]byte, msg []byte, key *[32]byte) {
|
|
||||||
h := newMACGeneric(key)
|
|
||||||
h.Write(msg)
|
|
||||||
h.Sum(out)
|
|
||||||
}
|
|
||||||
|
|
||||||
func newMACGeneric(key *[32]byte) (h macGeneric) {
|
|
||||||
h.r[0] = binary.LittleEndian.Uint32(key[0:]) & 0x3ffffff
|
|
||||||
h.r[1] = (binary.LittleEndian.Uint32(key[3:]) >> 2) & 0x3ffff03
|
|
||||||
h.r[2] = (binary.LittleEndian.Uint32(key[6:]) >> 4) & 0x3ffc0ff
|
|
||||||
h.r[3] = (binary.LittleEndian.Uint32(key[9:]) >> 6) & 0x3f03fff
|
|
||||||
h.r[4] = (binary.LittleEndian.Uint32(key[12:]) >> 8) & 0x00fffff
|
|
||||||
|
|
||||||
h.s[0] = binary.LittleEndian.Uint32(key[16:])
|
|
||||||
h.s[1] = binary.LittleEndian.Uint32(key[20:])
|
|
||||||
h.s[2] = binary.LittleEndian.Uint32(key[24:])
|
|
||||||
h.s[3] = binary.LittleEndian.Uint32(key[28:])
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
type macGeneric struct {
|
|
||||||
h, r [5]uint32
|
|
||||||
s [4]uint32
|
|
||||||
|
|
||||||
buffer [TagSize]byte
|
|
||||||
offset int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *macGeneric) Write(p []byte) (n int, err error) {
|
|
||||||
n = len(p)
|
|
||||||
if h.offset > 0 {
|
|
||||||
remaining := TagSize - h.offset
|
|
||||||
if n < remaining {
|
|
||||||
h.offset += copy(h.buffer[h.offset:], p)
|
|
||||||
return n, nil
|
|
||||||
}
|
|
||||||
copy(h.buffer[h.offset:], p[:remaining])
|
|
||||||
p = p[remaining:]
|
|
||||||
h.offset = 0
|
|
||||||
updateGeneric(h.buffer[:], msgBlock, &(h.h), &(h.r))
|
|
||||||
}
|
|
||||||
if nn := len(p) - (len(p) % TagSize); nn > 0 {
|
|
||||||
updateGeneric(p, msgBlock, &(h.h), &(h.r))
|
|
||||||
p = p[nn:]
|
|
||||||
}
|
|
||||||
if len(p) > 0 {
|
|
||||||
h.offset += copy(h.buffer[h.offset:], p)
|
|
||||||
}
|
|
||||||
return n, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *macGeneric) Sum(out *[16]byte) {
|
|
||||||
H, R := h.h, h.r
|
|
||||||
if h.offset > 0 {
|
|
||||||
var buffer [TagSize]byte
|
|
||||||
copy(buffer[:], h.buffer[:h.offset])
|
|
||||||
buffer[h.offset] = 1 // invariant: h.offset < TagSize
|
|
||||||
updateGeneric(buffer[:], finalBlock, &H, &R)
|
|
||||||
}
|
|
||||||
finalizeGeneric(out, &H, &(h.s))
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateGeneric(msg []byte, flag uint32, h, r *[5]uint32) {
|
|
||||||
h0, h1, h2, h3, h4 := h[0], h[1], h[2], h[3], h[4]
|
|
||||||
r0, r1, r2, r3, r4 := uint64(r[0]), uint64(r[1]), uint64(r[2]), uint64(r[3]), uint64(r[4])
|
|
||||||
R1, R2, R3, R4 := r1*5, r2*5, r3*5, r4*5
|
|
||||||
|
|
||||||
for len(msg) >= TagSize {
|
|
||||||
// h += msg
|
|
||||||
h0 += binary.LittleEndian.Uint32(msg[0:]) & 0x3ffffff
|
|
||||||
h1 += (binary.LittleEndian.Uint32(msg[3:]) >> 2) & 0x3ffffff
|
|
||||||
h2 += (binary.LittleEndian.Uint32(msg[6:]) >> 4) & 0x3ffffff
|
|
||||||
h3 += (binary.LittleEndian.Uint32(msg[9:]) >> 6) & 0x3ffffff
|
|
||||||
h4 += (binary.LittleEndian.Uint32(msg[12:]) >> 8) | flag
|
|
||||||
|
|
||||||
// h *= r
|
|
||||||
d0 := (uint64(h0) * r0) + (uint64(h1) * R4) + (uint64(h2) * R3) + (uint64(h3) * R2) + (uint64(h4) * R1)
|
|
||||||
d1 := (d0 >> 26) + (uint64(h0) * r1) + (uint64(h1) * r0) + (uint64(h2) * R4) + (uint64(h3) * R3) + (uint64(h4) * R2)
|
|
||||||
d2 := (d1 >> 26) + (uint64(h0) * r2) + (uint64(h1) * r1) + (uint64(h2) * r0) + (uint64(h3) * R4) + (uint64(h4) * R3)
|
|
||||||
d3 := (d2 >> 26) + (uint64(h0) * r3) + (uint64(h1) * r2) + (uint64(h2) * r1) + (uint64(h3) * r0) + (uint64(h4) * R4)
|
|
||||||
d4 := (d3 >> 26) + (uint64(h0) * r4) + (uint64(h1) * r3) + (uint64(h2) * r2) + (uint64(h3) * r1) + (uint64(h4) * r0)
|
|
||||||
|
|
||||||
// h %= p
|
|
||||||
h0 = uint32(d0) & 0x3ffffff
|
|
||||||
h1 = uint32(d1) & 0x3ffffff
|
|
||||||
h2 = uint32(d2) & 0x3ffffff
|
|
||||||
h3 = uint32(d3) & 0x3ffffff
|
|
||||||
h4 = uint32(d4) & 0x3ffffff
|
|
||||||
|
|
||||||
h0 += uint32(d4>>26) * 5
|
|
||||||
h1 += h0 >> 26
|
|
||||||
h0 = h0 & 0x3ffffff
|
|
||||||
|
|
||||||
msg = msg[TagSize:]
|
|
||||||
}
|
|
||||||
|
|
||||||
h[0], h[1], h[2], h[3], h[4] = h0, h1, h2, h3, h4
|
|
||||||
}
|
|
||||||
|
|
||||||
func finalizeGeneric(out *[TagSize]byte, h *[5]uint32, s *[4]uint32) {
|
|
||||||
h0, h1, h2, h3, h4 := h[0], h[1], h[2], h[3], h[4]
|
|
||||||
|
|
||||||
// h %= p reduction
|
|
||||||
h2 += h1 >> 26
|
|
||||||
h1 &= 0x3ffffff
|
|
||||||
h3 += h2 >> 26
|
|
||||||
h2 &= 0x3ffffff
|
|
||||||
h4 += h3 >> 26
|
|
||||||
h3 &= 0x3ffffff
|
|
||||||
h0 += 5 * (h4 >> 26)
|
|
||||||
h4 &= 0x3ffffff
|
|
||||||
h1 += h0 >> 26
|
|
||||||
h0 &= 0x3ffffff
|
|
||||||
|
|
||||||
// h - p
|
|
||||||
t0 := h0 + 5
|
|
||||||
t1 := h1 + (t0 >> 26)
|
|
||||||
t2 := h2 + (t1 >> 26)
|
|
||||||
t3 := h3 + (t2 >> 26)
|
|
||||||
t4 := h4 + (t3 >> 26) - (1 << 26)
|
|
||||||
t0 &= 0x3ffffff
|
|
||||||
t1 &= 0x3ffffff
|
|
||||||
t2 &= 0x3ffffff
|
|
||||||
t3 &= 0x3ffffff
|
|
||||||
|
|
||||||
// select h if h < p else h - p
|
|
||||||
t_mask := (t4 >> 31) - 1
|
|
||||||
h_mask := ^t_mask
|
|
||||||
h0 = (h0 & h_mask) | (t0 & t_mask)
|
|
||||||
h1 = (h1 & h_mask) | (t1 & t_mask)
|
|
||||||
h2 = (h2 & h_mask) | (t2 & t_mask)
|
|
||||||
h3 = (h3 & h_mask) | (t3 & t_mask)
|
|
||||||
h4 = (h4 & h_mask) | (t4 & t_mask)
|
|
||||||
|
|
||||||
// h %= 2^128
|
|
||||||
h0 |= h1 << 26
|
|
||||||
h1 = ((h1 >> 6) | (h2 << 20))
|
|
||||||
h2 = ((h2 >> 12) | (h3 << 14))
|
|
||||||
h3 = ((h3 >> 18) | (h4 << 8))
|
|
||||||
|
|
||||||
// s: the s part of the key
|
|
||||||
// tag = (h + s) % (2^128)
|
|
||||||
t := uint64(h0) + uint64(s[0])
|
|
||||||
h0 = uint32(t)
|
|
||||||
t = uint64(h1) + uint64(s[1]) + (t >> 32)
|
|
||||||
h1 = uint32(t)
|
|
||||||
t = uint64(h2) + uint64(s[2]) + (t >> 32)
|
|
||||||
h2 = uint32(t)
|
|
||||||
t = uint64(h3) + uint64(s[3]) + (t >> 32)
|
|
||||||
h3 = uint32(t)
|
|
||||||
|
|
||||||
binary.LittleEndian.PutUint32(out[0:], h0)
|
|
||||||
binary.LittleEndian.PutUint32(out[4:], h1)
|
|
||||||
binary.LittleEndian.PutUint32(out[8:], h2)
|
|
||||||
binary.LittleEndian.PutUint32(out[12:], h3)
|
|
||||||
}
|
|
16
vendor/golang.org/x/crypto/poly1305/sum_noasm.go
generated
vendored
16
vendor/golang.org/x/crypto/poly1305/sum_noasm.go
generated
vendored
@ -1,16 +0,0 @@
|
|||||||
// Copyright 2018 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.
|
|
||||||
|
|
||||||
// +build s390x,!go1.11 !arm,!amd64,!s390x,!ppc64le gccgo appengine nacl
|
|
||||||
|
|
||||||
package poly1305
|
|
||||||
|
|
||||||
// Sum generates an authenticator for msg using a one-time key and puts the
|
|
||||||
// 16-byte result into out. Authenticating two different messages with the same
|
|
||||||
// key allows an attacker to forge messages at will.
|
|
||||||
func Sum(out *[TagSize]byte, msg []byte, key *[32]byte) {
|
|
||||||
h := newMAC(key)
|
|
||||||
h.Write(msg)
|
|
||||||
h.Sum(out)
|
|
||||||
}
|
|
68
vendor/golang.org/x/crypto/poly1305/sum_ppc64le.go
generated
vendored
68
vendor/golang.org/x/crypto/poly1305/sum_ppc64le.go
generated
vendored
@ -1,68 +0,0 @@
|
|||||||
// Copyright 2019 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.
|
|
||||||
|
|
||||||
// +build ppc64le,!gccgo,!appengine
|
|
||||||
|
|
||||||
package poly1305
|
|
||||||
|
|
||||||
//go:noescape
|
|
||||||
func initialize(state *[7]uint64, key *[32]byte)
|
|
||||||
|
|
||||||
//go:noescape
|
|
||||||
func update(state *[7]uint64, msg []byte)
|
|
||||||
|
|
||||||
//go:noescape
|
|
||||||
func finalize(tag *[TagSize]byte, state *[7]uint64)
|
|
||||||
|
|
||||||
// Sum generates an authenticator for m using a one-time key and puts the
|
|
||||||
// 16-byte result into out. Authenticating two different messages with the same
|
|
||||||
// key allows an attacker to forge messages at will.
|
|
||||||
func Sum(out *[16]byte, m []byte, key *[32]byte) {
|
|
||||||
h := newMAC(key)
|
|
||||||
h.Write(m)
|
|
||||||
h.Sum(out)
|
|
||||||
}
|
|
||||||
|
|
||||||
func newMAC(key *[32]byte) (h mac) {
|
|
||||||
initialize(&h.state, key)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
type mac struct {
|
|
||||||
state [7]uint64 // := uint64{ h0, h1, h2, r0, r1, pad0, pad1 }
|
|
||||||
|
|
||||||
buffer [TagSize]byte
|
|
||||||
offset int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *mac) Write(p []byte) (n int, err error) {
|
|
||||||
n = len(p)
|
|
||||||
if h.offset > 0 {
|
|
||||||
remaining := TagSize - h.offset
|
|
||||||
if n < remaining {
|
|
||||||
h.offset += copy(h.buffer[h.offset:], p)
|
|
||||||
return n, nil
|
|
||||||
}
|
|
||||||
copy(h.buffer[h.offset:], p[:remaining])
|
|
||||||
p = p[remaining:]
|
|
||||||
h.offset = 0
|
|
||||||
update(&h.state, h.buffer[:])
|
|
||||||
}
|
|
||||||
if nn := len(p) - (len(p) % TagSize); nn > 0 {
|
|
||||||
update(&h.state, p[:nn])
|
|
||||||
p = p[nn:]
|
|
||||||
}
|
|
||||||
if len(p) > 0 {
|
|
||||||
h.offset += copy(h.buffer[h.offset:], p)
|
|
||||||
}
|
|
||||||
return n, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *mac) Sum(out *[16]byte) {
|
|
||||||
state := h.state
|
|
||||||
if h.offset > 0 {
|
|
||||||
update(&state, h.buffer[:h.offset])
|
|
||||||
}
|
|
||||||
finalize(out, &state)
|
|
||||||
}
|
|
247
vendor/golang.org/x/crypto/poly1305/sum_ppc64le.s
generated
vendored
247
vendor/golang.org/x/crypto/poly1305/sum_ppc64le.s
generated
vendored
@ -1,247 +0,0 @@
|
|||||||
// Copyright 2019 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.
|
|
||||||
|
|
||||||
// +build ppc64le,!gccgo,!appengine
|
|
||||||
|
|
||||||
#include "textflag.h"
|
|
||||||
|
|
||||||
// This was ported from the amd64 implementation.
|
|
||||||
|
|
||||||
#define POLY1305_ADD(msg, h0, h1, h2, t0, t1, t2) \
|
|
||||||
MOVD (msg), t0; \
|
|
||||||
MOVD 8(msg), t1; \
|
|
||||||
MOVD $1, t2; \
|
|
||||||
ADDC t0, h0, h0; \
|
|
||||||
ADDE t1, h1, h1; \
|
|
||||||
ADDE t2, h2; \
|
|
||||||
ADD $16, msg
|
|
||||||
|
|
||||||
#define POLY1305_MUL(h0, h1, h2, r0, r1, t0, t1, t2, t3, t4, t5) \
|
|
||||||
MULLD r0, h0, t0; \
|
|
||||||
MULLD r0, h1, t4; \
|
|
||||||
MULHDU r0, h0, t1; \
|
|
||||||
MULHDU r0, h1, t5; \
|
|
||||||
ADDC t4, t1, t1; \
|
|
||||||
MULLD r0, h2, t2; \
|
|
||||||
ADDZE t5; \
|
|
||||||
MULHDU r1, h0, t4; \
|
|
||||||
MULLD r1, h0, h0; \
|
|
||||||
ADD t5, t2, t2; \
|
|
||||||
ADDC h0, t1, t1; \
|
|
||||||
MULLD h2, r1, t3; \
|
|
||||||
ADDZE t4, h0; \
|
|
||||||
MULHDU r1, h1, t5; \
|
|
||||||
MULLD r1, h1, t4; \
|
|
||||||
ADDC t4, t2, t2; \
|
|
||||||
ADDE t5, t3, t3; \
|
|
||||||
ADDC h0, t2, t2; \
|
|
||||||
MOVD $-4, t4; \
|
|
||||||
MOVD t0, h0; \
|
|
||||||
MOVD t1, h1; \
|
|
||||||
ADDZE t3; \
|
|
||||||
ANDCC $3, t2, h2; \
|
|
||||||
AND t2, t4, t0; \
|
|
||||||
ADDC t0, h0, h0; \
|
|
||||||
ADDE t3, h1, h1; \
|
|
||||||
SLD $62, t3, t4; \
|
|
||||||
SRD $2, t2; \
|
|
||||||
ADDZE h2; \
|
|
||||||
OR t4, t2, t2; \
|
|
||||||
SRD $2, t3; \
|
|
||||||
ADDC t2, h0, h0; \
|
|
||||||
ADDE t3, h1, h1; \
|
|
||||||
ADDZE h2
|
|
||||||
|
|
||||||
DATA ·poly1305Mask<>+0x00(SB)/8, $0x0FFFFFFC0FFFFFFF
|
|
||||||
DATA ·poly1305Mask<>+0x08(SB)/8, $0x0FFFFFFC0FFFFFFC
|
|
||||||
GLOBL ·poly1305Mask<>(SB), RODATA, $16
|
|
||||||
|
|
||||||
// func update(state *[7]uint64, msg []byte)
|
|
||||||
|
|
||||||
TEXT ·update(SB), $0-32
|
|
||||||
MOVD state+0(FP), R3
|
|
||||||
MOVD msg_base+8(FP), R4
|
|
||||||
MOVD msg_len+16(FP), R5
|
|
||||||
|
|
||||||
MOVD 0(R3), R8 // h0
|
|
||||||
MOVD 8(R3), R9 // h1
|
|
||||||
MOVD 16(R3), R10 // h2
|
|
||||||
MOVD 24(R3), R11 // r0
|
|
||||||
MOVD 32(R3), R12 // r1
|
|
||||||
|
|
||||||
CMP R5, $16
|
|
||||||
BLT bytes_between_0_and_15
|
|
||||||
|
|
||||||
loop:
|
|
||||||
POLY1305_ADD(R4, R8, R9, R10, R20, R21, R22)
|
|
||||||
|
|
||||||
multiply:
|
|
||||||
POLY1305_MUL(R8, R9, R10, R11, R12, R16, R17, R18, R14, R20, R21)
|
|
||||||
ADD $-16, R5
|
|
||||||
CMP R5, $16
|
|
||||||
BGE loop
|
|
||||||
|
|
||||||
bytes_between_0_and_15:
|
|
||||||
CMP $0, R5
|
|
||||||
BEQ done
|
|
||||||
MOVD $0, R16 // h0
|
|
||||||
MOVD $0, R17 // h1
|
|
||||||
|
|
||||||
flush_buffer:
|
|
||||||
CMP R5, $8
|
|
||||||
BLE just1
|
|
||||||
|
|
||||||
MOVD $8, R21
|
|
||||||
SUB R21, R5, R21
|
|
||||||
|
|
||||||
// Greater than 8 -- load the rightmost remaining bytes in msg
|
|
||||||
// and put into R17 (h1)
|
|
||||||
MOVD (R4)(R21), R17
|
|
||||||
MOVD $16, R22
|
|
||||||
|
|
||||||
// Find the offset to those bytes
|
|
||||||
SUB R5, R22, R22
|
|
||||||
SLD $3, R22
|
|
||||||
|
|
||||||
// Shift to get only the bytes in msg
|
|
||||||
SRD R22, R17, R17
|
|
||||||
|
|
||||||
// Put 1 at high end
|
|
||||||
MOVD $1, R23
|
|
||||||
SLD $3, R21
|
|
||||||
SLD R21, R23, R23
|
|
||||||
OR R23, R17, R17
|
|
||||||
|
|
||||||
// Remainder is 8
|
|
||||||
MOVD $8, R5
|
|
||||||
|
|
||||||
just1:
|
|
||||||
CMP R5, $8
|
|
||||||
BLT less8
|
|
||||||
|
|
||||||
// Exactly 8
|
|
||||||
MOVD (R4), R16
|
|
||||||
|
|
||||||
CMP $0, R17
|
|
||||||
|
|
||||||
// Check if we've already set R17; if not
|
|
||||||
// set 1 to indicate end of msg.
|
|
||||||
BNE carry
|
|
||||||
MOVD $1, R17
|
|
||||||
BR carry
|
|
||||||
|
|
||||||
less8:
|
|
||||||
MOVD $0, R16 // h0
|
|
||||||
MOVD $0, R22 // shift count
|
|
||||||
CMP R5, $4
|
|
||||||
BLT less4
|
|
||||||
MOVWZ (R4), R16
|
|
||||||
ADD $4, R4
|
|
||||||
ADD $-4, R5
|
|
||||||
MOVD $32, R22
|
|
||||||
|
|
||||||
less4:
|
|
||||||
CMP R5, $2
|
|
||||||
BLT less2
|
|
||||||
MOVHZ (R4), R21
|
|
||||||
SLD R22, R21, R21
|
|
||||||
OR R16, R21, R16
|
|
||||||
ADD $16, R22
|
|
||||||
ADD $-2, R5
|
|
||||||
ADD $2, R4
|
|
||||||
|
|
||||||
less2:
|
|
||||||
CMP $0, R5
|
|
||||||
BEQ insert1
|
|
||||||
MOVBZ (R4), R21
|
|
||||||
SLD R22, R21, R21
|
|
||||||
OR R16, R21, R16
|
|
||||||
ADD $8, R22
|
|
||||||
|
|
||||||
insert1:
|
|
||||||
// Insert 1 at end of msg
|
|
||||||
MOVD $1, R21
|
|
||||||
SLD R22, R21, R21
|
|
||||||
OR R16, R21, R16
|
|
||||||
|
|
||||||
carry:
|
|
||||||
// Add new values to h0, h1, h2
|
|
||||||
ADDC R16, R8
|
|
||||||
ADDE R17, R9
|
|
||||||
ADDE $0, R10
|
|
||||||
MOVD $16, R5
|
|
||||||
ADD R5, R4
|
|
||||||
BR multiply
|
|
||||||
|
|
||||||
done:
|
|
||||||
// Save h0, h1, h2 in state
|
|
||||||
MOVD R8, 0(R3)
|
|
||||||
MOVD R9, 8(R3)
|
|
||||||
MOVD R10, 16(R3)
|
|
||||||
RET
|
|
||||||
|
|
||||||
// func initialize(state *[7]uint64, key *[32]byte)
|
|
||||||
TEXT ·initialize(SB), $0-16
|
|
||||||
MOVD state+0(FP), R3
|
|
||||||
MOVD key+8(FP), R4
|
|
||||||
|
|
||||||
// state[0...7] is initialized with zero
|
|
||||||
// Load key
|
|
||||||
MOVD 0(R4), R5
|
|
||||||
MOVD 8(R4), R6
|
|
||||||
MOVD 16(R4), R7
|
|
||||||
MOVD 24(R4), R8
|
|
||||||
|
|
||||||
// Address of key mask
|
|
||||||
MOVD $·poly1305Mask<>(SB), R9
|
|
||||||
|
|
||||||
// Save original key in state
|
|
||||||
MOVD R7, 40(R3)
|
|
||||||
MOVD R8, 48(R3)
|
|
||||||
|
|
||||||
// Get mask
|
|
||||||
MOVD (R9), R7
|
|
||||||
MOVD 8(R9), R8
|
|
||||||
|
|
||||||
// And with key
|
|
||||||
AND R5, R7, R5
|
|
||||||
AND R6, R8, R6
|
|
||||||
|
|
||||||
// Save masked key in state
|
|
||||||
MOVD R5, 24(R3)
|
|
||||||
MOVD R6, 32(R3)
|
|
||||||
RET
|
|
||||||
|
|
||||||
// func finalize(tag *[TagSize]byte, state *[7]uint64)
|
|
||||||
TEXT ·finalize(SB), $0-16
|
|
||||||
MOVD tag+0(FP), R3
|
|
||||||
MOVD state+8(FP), R4
|
|
||||||
|
|
||||||
// Get h0, h1, h2 from state
|
|
||||||
MOVD 0(R4), R5
|
|
||||||
MOVD 8(R4), R6
|
|
||||||
MOVD 16(R4), R7
|
|
||||||
|
|
||||||
// Save h0, h1
|
|
||||||
MOVD R5, R8
|
|
||||||
MOVD R6, R9
|
|
||||||
MOVD $3, R20
|
|
||||||
MOVD $-1, R21
|
|
||||||
SUBC $-5, R5
|
|
||||||
SUBE R21, R6
|
|
||||||
SUBE R20, R7
|
|
||||||
MOVD $0, R21
|
|
||||||
SUBZE R21
|
|
||||||
|
|
||||||
// Check for carry
|
|
||||||
CMP $0, R21
|
|
||||||
ISEL $2, R5, R8, R5
|
|
||||||
ISEL $2, R6, R9, R6
|
|
||||||
MOVD 40(R4), R8
|
|
||||||
MOVD 48(R4), R9
|
|
||||||
ADDC R8, R5
|
|
||||||
ADDE R9, R6
|
|
||||||
MOVD R5, 0(R3)
|
|
||||||
MOVD R6, 8(R3)
|
|
||||||
RET
|
|
42
vendor/golang.org/x/crypto/poly1305/sum_s390x.go
generated
vendored
42
vendor/golang.org/x/crypto/poly1305/sum_s390x.go
generated
vendored
@ -1,42 +0,0 @@
|
|||||||
// Copyright 2018 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.
|
|
||||||
|
|
||||||
// +build s390x,go1.11,!gccgo,!appengine
|
|
||||||
|
|
||||||
package poly1305
|
|
||||||
|
|
||||||
import (
|
|
||||||
"golang.org/x/sys/cpu"
|
|
||||||
)
|
|
||||||
|
|
||||||
// poly1305vx is an assembly implementation of Poly1305 that uses vector
|
|
||||||
// instructions. It must only be called if the vector facility (vx) is
|
|
||||||
// available.
|
|
||||||
//go:noescape
|
|
||||||
func poly1305vx(out *[16]byte, m *byte, mlen uint64, key *[32]byte)
|
|
||||||
|
|
||||||
// poly1305vmsl is an assembly implementation of Poly1305 that uses vector
|
|
||||||
// instructions, including VMSL. It must only be called if the vector facility (vx) is
|
|
||||||
// available and if VMSL is supported.
|
|
||||||
//go:noescape
|
|
||||||
func poly1305vmsl(out *[16]byte, m *byte, mlen uint64, key *[32]byte)
|
|
||||||
|
|
||||||
// Sum generates an authenticator for m using a one-time key and puts the
|
|
||||||
// 16-byte result into out. Authenticating two different messages with the same
|
|
||||||
// key allows an attacker to forge messages at will.
|
|
||||||
func Sum(out *[16]byte, m []byte, key *[32]byte) {
|
|
||||||
if cpu.S390X.HasVX {
|
|
||||||
var mPtr *byte
|
|
||||||
if len(m) > 0 {
|
|
||||||
mPtr = &m[0]
|
|
||||||
}
|
|
||||||
if cpu.S390X.HasVXE && len(m) > 256 {
|
|
||||||
poly1305vmsl(out, mPtr, uint64(len(m)), key)
|
|
||||||
} else {
|
|
||||||
poly1305vx(out, mPtr, uint64(len(m)), key)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
sumGeneric(out, m, key)
|
|
||||||
}
|
|
||||||
}
|
|
378
vendor/golang.org/x/crypto/poly1305/sum_s390x.s
generated
vendored
378
vendor/golang.org/x/crypto/poly1305/sum_s390x.s
generated
vendored
@ -1,378 +0,0 @@
|
|||||||
// Copyright 2018 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.
|
|
||||||
|
|
||||||
// +build s390x,go1.11,!gccgo,!appengine
|
|
||||||
|
|
||||||
#include "textflag.h"
|
|
||||||
|
|
||||||
// Implementation of Poly1305 using the vector facility (vx).
|
|
||||||
|
|
||||||
// constants
|
|
||||||
#define MOD26 V0
|
|
||||||
#define EX0 V1
|
|
||||||
#define EX1 V2
|
|
||||||
#define EX2 V3
|
|
||||||
|
|
||||||
// temporaries
|
|
||||||
#define T_0 V4
|
|
||||||
#define T_1 V5
|
|
||||||
#define T_2 V6
|
|
||||||
#define T_3 V7
|
|
||||||
#define T_4 V8
|
|
||||||
|
|
||||||
// key (r)
|
|
||||||
#define R_0 V9
|
|
||||||
#define R_1 V10
|
|
||||||
#define R_2 V11
|
|
||||||
#define R_3 V12
|
|
||||||
#define R_4 V13
|
|
||||||
#define R5_1 V14
|
|
||||||
#define R5_2 V15
|
|
||||||
#define R5_3 V16
|
|
||||||
#define R5_4 V17
|
|
||||||
#define RSAVE_0 R5
|
|
||||||
#define RSAVE_1 R6
|
|
||||||
#define RSAVE_2 R7
|
|
||||||
#define RSAVE_3 R8
|
|
||||||
#define RSAVE_4 R9
|
|
||||||
#define R5SAVE_1 V28
|
|
||||||
#define R5SAVE_2 V29
|
|
||||||
#define R5SAVE_3 V30
|
|
||||||
#define R5SAVE_4 V31
|
|
||||||
|
|
||||||
// message block
|
|
||||||
#define F_0 V18
|
|
||||||
#define F_1 V19
|
|
||||||
#define F_2 V20
|
|
||||||
#define F_3 V21
|
|
||||||
#define F_4 V22
|
|
||||||
|
|
||||||
// accumulator
|
|
||||||
#define H_0 V23
|
|
||||||
#define H_1 V24
|
|
||||||
#define H_2 V25
|
|
||||||
#define H_3 V26
|
|
||||||
#define H_4 V27
|
|
||||||
|
|
||||||
GLOBL ·keyMask<>(SB), RODATA, $16
|
|
||||||
DATA ·keyMask<>+0(SB)/8, $0xffffff0ffcffff0f
|
|
||||||
DATA ·keyMask<>+8(SB)/8, $0xfcffff0ffcffff0f
|
|
||||||
|
|
||||||
GLOBL ·bswapMask<>(SB), RODATA, $16
|
|
||||||
DATA ·bswapMask<>+0(SB)/8, $0x0f0e0d0c0b0a0908
|
|
||||||
DATA ·bswapMask<>+8(SB)/8, $0x0706050403020100
|
|
||||||
|
|
||||||
GLOBL ·constants<>(SB), RODATA, $64
|
|
||||||
// MOD26
|
|
||||||
DATA ·constants<>+0(SB)/8, $0x3ffffff
|
|
||||||
DATA ·constants<>+8(SB)/8, $0x3ffffff
|
|
||||||
// EX0
|
|
||||||
DATA ·constants<>+16(SB)/8, $0x0006050403020100
|
|
||||||
DATA ·constants<>+24(SB)/8, $0x1016151413121110
|
|
||||||
// EX1
|
|
||||||
DATA ·constants<>+32(SB)/8, $0x060c0b0a09080706
|
|
||||||
DATA ·constants<>+40(SB)/8, $0x161c1b1a19181716
|
|
||||||
// EX2
|
|
||||||
DATA ·constants<>+48(SB)/8, $0x0d0d0d0d0d0f0e0d
|
|
||||||
DATA ·constants<>+56(SB)/8, $0x1d1d1d1d1d1f1e1d
|
|
||||||
|
|
||||||
// h = (f*g) % (2**130-5) [partial reduction]
|
|
||||||
#define MULTIPLY(f0, f1, f2, f3, f4, g0, g1, g2, g3, g4, g51, g52, g53, g54, h0, h1, h2, h3, h4) \
|
|
||||||
VMLOF f0, g0, h0 \
|
|
||||||
VMLOF f0, g1, h1 \
|
|
||||||
VMLOF f0, g2, h2 \
|
|
||||||
VMLOF f0, g3, h3 \
|
|
||||||
VMLOF f0, g4, h4 \
|
|
||||||
VMLOF f1, g54, T_0 \
|
|
||||||
VMLOF f1, g0, T_1 \
|
|
||||||
VMLOF f1, g1, T_2 \
|
|
||||||
VMLOF f1, g2, T_3 \
|
|
||||||
VMLOF f1, g3, T_4 \
|
|
||||||
VMALOF f2, g53, h0, h0 \
|
|
||||||
VMALOF f2, g54, h1, h1 \
|
|
||||||
VMALOF f2, g0, h2, h2 \
|
|
||||||
VMALOF f2, g1, h3, h3 \
|
|
||||||
VMALOF f2, g2, h4, h4 \
|
|
||||||
VMALOF f3, g52, T_0, T_0 \
|
|
||||||
VMALOF f3, g53, T_1, T_1 \
|
|
||||||
VMALOF f3, g54, T_2, T_2 \
|
|
||||||
VMALOF f3, g0, T_3, T_3 \
|
|
||||||
VMALOF f3, g1, T_4, T_4 \
|
|
||||||
VMALOF f4, g51, h0, h0 \
|
|
||||||
VMALOF f4, g52, h1, h1 \
|
|
||||||
VMALOF f4, g53, h2, h2 \
|
|
||||||
VMALOF f4, g54, h3, h3 \
|
|
||||||
VMALOF f4, g0, h4, h4 \
|
|
||||||
VAG T_0, h0, h0 \
|
|
||||||
VAG T_1, h1, h1 \
|
|
||||||
VAG T_2, h2, h2 \
|
|
||||||
VAG T_3, h3, h3 \
|
|
||||||
VAG T_4, h4, h4
|
|
||||||
|
|
||||||
// carry h0->h1 h3->h4, h1->h2 h4->h0, h0->h1 h2->h3, h3->h4
|
|
||||||
#define REDUCE(h0, h1, h2, h3, h4) \
|
|
||||||
VESRLG $26, h0, T_0 \
|
|
||||||
VESRLG $26, h3, T_1 \
|
|
||||||
VN MOD26, h0, h0 \
|
|
||||||
VN MOD26, h3, h3 \
|
|
||||||
VAG T_0, h1, h1 \
|
|
||||||
VAG T_1, h4, h4 \
|
|
||||||
VESRLG $26, h1, T_2 \
|
|
||||||
VESRLG $26, h4, T_3 \
|
|
||||||
VN MOD26, h1, h1 \
|
|
||||||
VN MOD26, h4, h4 \
|
|
||||||
VESLG $2, T_3, T_4 \
|
|
||||||
VAG T_3, T_4, T_4 \
|
|
||||||
VAG T_2, h2, h2 \
|
|
||||||
VAG T_4, h0, h0 \
|
|
||||||
VESRLG $26, h2, T_0 \
|
|
||||||
VESRLG $26, h0, T_1 \
|
|
||||||
VN MOD26, h2, h2 \
|
|
||||||
VN MOD26, h0, h0 \
|
|
||||||
VAG T_0, h3, h3 \
|
|
||||||
VAG T_1, h1, h1 \
|
|
||||||
VESRLG $26, h3, T_2 \
|
|
||||||
VN MOD26, h3, h3 \
|
|
||||||
VAG T_2, h4, h4
|
|
||||||
|
|
||||||
// expand in0 into d[0] and in1 into d[1]
|
|
||||||
#define EXPAND(in0, in1, d0, d1, d2, d3, d4) \
|
|
||||||
VGBM $0x0707, d1 \ // d1=tmp
|
|
||||||
VPERM in0, in1, EX2, d4 \
|
|
||||||
VPERM in0, in1, EX0, d0 \
|
|
||||||
VPERM in0, in1, EX1, d2 \
|
|
||||||
VN d1, d4, d4 \
|
|
||||||
VESRLG $26, d0, d1 \
|
|
||||||
VESRLG $30, d2, d3 \
|
|
||||||
VESRLG $4, d2, d2 \
|
|
||||||
VN MOD26, d0, d0 \
|
|
||||||
VN MOD26, d1, d1 \
|
|
||||||
VN MOD26, d2, d2 \
|
|
||||||
VN MOD26, d3, d3
|
|
||||||
|
|
||||||
// pack h4:h0 into h1:h0 (no carry)
|
|
||||||
#define PACK(h0, h1, h2, h3, h4) \
|
|
||||||
VESLG $26, h1, h1 \
|
|
||||||
VESLG $26, h3, h3 \
|
|
||||||
VO h0, h1, h0 \
|
|
||||||
VO h2, h3, h2 \
|
|
||||||
VESLG $4, h2, h2 \
|
|
||||||
VLEIB $7, $48, h1 \
|
|
||||||
VSLB h1, h2, h2 \
|
|
||||||
VO h0, h2, h0 \
|
|
||||||
VLEIB $7, $104, h1 \
|
|
||||||
VSLB h1, h4, h3 \
|
|
||||||
VO h3, h0, h0 \
|
|
||||||
VLEIB $7, $24, h1 \
|
|
||||||
VSRLB h1, h4, h1
|
|
||||||
|
|
||||||
// if h > 2**130-5 then h -= 2**130-5
|
|
||||||
#define MOD(h0, h1, t0, t1, t2) \
|
|
||||||
VZERO t0 \
|
|
||||||
VLEIG $1, $5, t0 \
|
|
||||||
VACCQ h0, t0, t1 \
|
|
||||||
VAQ h0, t0, t0 \
|
|
||||||
VONE t2 \
|
|
||||||
VLEIG $1, $-4, t2 \
|
|
||||||
VAQ t2, t1, t1 \
|
|
||||||
VACCQ h1, t1, t1 \
|
|
||||||
VONE t2 \
|
|
||||||
VAQ t2, t1, t1 \
|
|
||||||
VN h0, t1, t2 \
|
|
||||||
VNC t0, t1, t1 \
|
|
||||||
VO t1, t2, h0
|
|
||||||
|
|
||||||
// func poly1305vx(out *[16]byte, m *byte, mlen uint64, key *[32]key)
|
|
||||||
TEXT ·poly1305vx(SB), $0-32
|
|
||||||
// This code processes up to 2 blocks (32 bytes) per iteration
|
|
||||||
// using the algorithm described in:
|
|
||||||
// NEON crypto, Daniel J. Bernstein & Peter Schwabe
|
|
||||||
// https://cryptojedi.org/papers/neoncrypto-20120320.pdf
|
|
||||||
LMG out+0(FP), R1, R4 // R1=out, R2=m, R3=mlen, R4=key
|
|
||||||
|
|
||||||
// load MOD26, EX0, EX1 and EX2
|
|
||||||
MOVD $·constants<>(SB), R5
|
|
||||||
VLM (R5), MOD26, EX2
|
|
||||||
|
|
||||||
// setup r
|
|
||||||
VL (R4), T_0
|
|
||||||
MOVD $·keyMask<>(SB), R6
|
|
||||||
VL (R6), T_1
|
|
||||||
VN T_0, T_1, T_0
|
|
||||||
EXPAND(T_0, T_0, R_0, R_1, R_2, R_3, R_4)
|
|
||||||
|
|
||||||
// setup r*5
|
|
||||||
VLEIG $0, $5, T_0
|
|
||||||
VLEIG $1, $5, T_0
|
|
||||||
|
|
||||||
// store r (for final block)
|
|
||||||
VMLOF T_0, R_1, R5SAVE_1
|
|
||||||
VMLOF T_0, R_2, R5SAVE_2
|
|
||||||
VMLOF T_0, R_3, R5SAVE_3
|
|
||||||
VMLOF T_0, R_4, R5SAVE_4
|
|
||||||
VLGVG $0, R_0, RSAVE_0
|
|
||||||
VLGVG $0, R_1, RSAVE_1
|
|
||||||
VLGVG $0, R_2, RSAVE_2
|
|
||||||
VLGVG $0, R_3, RSAVE_3
|
|
||||||
VLGVG $0, R_4, RSAVE_4
|
|
||||||
|
|
||||||
// skip r**2 calculation
|
|
||||||
CMPBLE R3, $16, skip
|
|
||||||
|
|
||||||
// calculate r**2
|
|
||||||
MULTIPLY(R_0, R_1, R_2, R_3, R_4, R_0, R_1, R_2, R_3, R_4, R5SAVE_1, R5SAVE_2, R5SAVE_3, R5SAVE_4, H_0, H_1, H_2, H_3, H_4)
|
|
||||||
REDUCE(H_0, H_1, H_2, H_3, H_4)
|
|
||||||
VLEIG $0, $5, T_0
|
|
||||||
VLEIG $1, $5, T_0
|
|
||||||
VMLOF T_0, H_1, R5_1
|
|
||||||
VMLOF T_0, H_2, R5_2
|
|
||||||
VMLOF T_0, H_3, R5_3
|
|
||||||
VMLOF T_0, H_4, R5_4
|
|
||||||
VLR H_0, R_0
|
|
||||||
VLR H_1, R_1
|
|
||||||
VLR H_2, R_2
|
|
||||||
VLR H_3, R_3
|
|
||||||
VLR H_4, R_4
|
|
||||||
|
|
||||||
// initialize h
|
|
||||||
VZERO H_0
|
|
||||||
VZERO H_1
|
|
||||||
VZERO H_2
|
|
||||||
VZERO H_3
|
|
||||||
VZERO H_4
|
|
||||||
|
|
||||||
loop:
|
|
||||||
CMPBLE R3, $32, b2
|
|
||||||
VLM (R2), T_0, T_1
|
|
||||||
SUB $32, R3
|
|
||||||
MOVD $32(R2), R2
|
|
||||||
EXPAND(T_0, T_1, F_0, F_1, F_2, F_3, F_4)
|
|
||||||
VLEIB $4, $1, F_4
|
|
||||||
VLEIB $12, $1, F_4
|
|
||||||
|
|
||||||
multiply:
|
|
||||||
VAG H_0, F_0, F_0
|
|
||||||
VAG H_1, F_1, F_1
|
|
||||||
VAG H_2, F_2, F_2
|
|
||||||
VAG H_3, F_3, F_3
|
|
||||||
VAG H_4, F_4, F_4
|
|
||||||
MULTIPLY(F_0, F_1, F_2, F_3, F_4, R_0, R_1, R_2, R_3, R_4, R5_1, R5_2, R5_3, R5_4, H_0, H_1, H_2, H_3, H_4)
|
|
||||||
REDUCE(H_0, H_1, H_2, H_3, H_4)
|
|
||||||
CMPBNE R3, $0, loop
|
|
||||||
|
|
||||||
finish:
|
|
||||||
// sum vectors
|
|
||||||
VZERO T_0
|
|
||||||
VSUMQG H_0, T_0, H_0
|
|
||||||
VSUMQG H_1, T_0, H_1
|
|
||||||
VSUMQG H_2, T_0, H_2
|
|
||||||
VSUMQG H_3, T_0, H_3
|
|
||||||
VSUMQG H_4, T_0, H_4
|
|
||||||
|
|
||||||
// h may be >= 2*(2**130-5) so we need to reduce it again
|
|
||||||
REDUCE(H_0, H_1, H_2, H_3, H_4)
|
|
||||||
|
|
||||||
// carry h1->h4
|
|
||||||
VESRLG $26, H_1, T_1
|
|
||||||
VN MOD26, H_1, H_1
|
|
||||||
VAQ T_1, H_2, H_2
|
|
||||||
VESRLG $26, H_2, T_2
|
|
||||||
VN MOD26, H_2, H_2
|
|
||||||
VAQ T_2, H_3, H_3
|
|
||||||
VESRLG $26, H_3, T_3
|
|
||||||
VN MOD26, H_3, H_3
|
|
||||||
VAQ T_3, H_4, H_4
|
|
||||||
|
|
||||||
// h is now < 2*(2**130-5)
|
|
||||||
// pack h into h1 (hi) and h0 (lo)
|
|
||||||
PACK(H_0, H_1, H_2, H_3, H_4)
|
|
||||||
|
|
||||||
// if h > 2**130-5 then h -= 2**130-5
|
|
||||||
MOD(H_0, H_1, T_0, T_1, T_2)
|
|
||||||
|
|
||||||
// h += s
|
|
||||||
MOVD $·bswapMask<>(SB), R5
|
|
||||||
VL (R5), T_1
|
|
||||||
VL 16(R4), T_0
|
|
||||||
VPERM T_0, T_0, T_1, T_0 // reverse bytes (to big)
|
|
||||||
VAQ T_0, H_0, H_0
|
|
||||||
VPERM H_0, H_0, T_1, H_0 // reverse bytes (to little)
|
|
||||||
VST H_0, (R1)
|
|
||||||
|
|
||||||
RET
|
|
||||||
|
|
||||||
b2:
|
|
||||||
CMPBLE R3, $16, b1
|
|
||||||
|
|
||||||
// 2 blocks remaining
|
|
||||||
SUB $17, R3
|
|
||||||
VL (R2), T_0
|
|
||||||
VLL R3, 16(R2), T_1
|
|
||||||
ADD $1, R3
|
|
||||||
MOVBZ $1, R0
|
|
||||||
CMPBEQ R3, $16, 2(PC)
|
|
||||||
VLVGB R3, R0, T_1
|
|
||||||
EXPAND(T_0, T_1, F_0, F_1, F_2, F_3, F_4)
|
|
||||||
CMPBNE R3, $16, 2(PC)
|
|
||||||
VLEIB $12, $1, F_4
|
|
||||||
VLEIB $4, $1, F_4
|
|
||||||
|
|
||||||
// setup [r²,r]
|
|
||||||
VLVGG $1, RSAVE_0, R_0
|
|
||||||
VLVGG $1, RSAVE_1, R_1
|
|
||||||
VLVGG $1, RSAVE_2, R_2
|
|
||||||
VLVGG $1, RSAVE_3, R_3
|
|
||||||
VLVGG $1, RSAVE_4, R_4
|
|
||||||
VPDI $0, R5_1, R5SAVE_1, R5_1
|
|
||||||
VPDI $0, R5_2, R5SAVE_2, R5_2
|
|
||||||
VPDI $0, R5_3, R5SAVE_3, R5_3
|
|
||||||
VPDI $0, R5_4, R5SAVE_4, R5_4
|
|
||||||
|
|
||||||
MOVD $0, R3
|
|
||||||
BR multiply
|
|
||||||
|
|
||||||
skip:
|
|
||||||
VZERO H_0
|
|
||||||
VZERO H_1
|
|
||||||
VZERO H_2
|
|
||||||
VZERO H_3
|
|
||||||
VZERO H_4
|
|
||||||
|
|
||||||
CMPBEQ R3, $0, finish
|
|
||||||
|
|
||||||
b1:
|
|
||||||
// 1 block remaining
|
|
||||||
SUB $1, R3
|
|
||||||
VLL R3, (R2), T_0
|
|
||||||
ADD $1, R3
|
|
||||||
MOVBZ $1, R0
|
|
||||||
CMPBEQ R3, $16, 2(PC)
|
|
||||||
VLVGB R3, R0, T_0
|
|
||||||
VZERO T_1
|
|
||||||
EXPAND(T_0, T_1, F_0, F_1, F_2, F_3, F_4)
|
|
||||||
CMPBNE R3, $16, 2(PC)
|
|
||||||
VLEIB $4, $1, F_4
|
|
||||||
VLEIG $1, $1, R_0
|
|
||||||
VZERO R_1
|
|
||||||
VZERO R_2
|
|
||||||
VZERO R_3
|
|
||||||
VZERO R_4
|
|
||||||
VZERO R5_1
|
|
||||||
VZERO R5_2
|
|
||||||
VZERO R5_3
|
|
||||||
VZERO R5_4
|
|
||||||
|
|
||||||
// setup [r, 1]
|
|
||||||
VLVGG $0, RSAVE_0, R_0
|
|
||||||
VLVGG $0, RSAVE_1, R_1
|
|
||||||
VLVGG $0, RSAVE_2, R_2
|
|
||||||
VLVGG $0, RSAVE_3, R_3
|
|
||||||
VLVGG $0, RSAVE_4, R_4
|
|
||||||
VPDI $0, R5SAVE_1, R5_1, R5_1
|
|
||||||
VPDI $0, R5SAVE_2, R5_2, R5_2
|
|
||||||
VPDI $0, R5SAVE_3, R5_3, R5_3
|
|
||||||
VPDI $0, R5SAVE_4, R5_4, R5_4
|
|
||||||
|
|
||||||
MOVD $0, R3
|
|
||||||
BR multiply
|
|
909
vendor/golang.org/x/crypto/poly1305/sum_vmsl_s390x.s
generated
vendored
909
vendor/golang.org/x/crypto/poly1305/sum_vmsl_s390x.s
generated
vendored
@ -1,909 +0,0 @@
|
|||||||
// Copyright 2018 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.
|
|
||||||
|
|
||||||
// +build s390x,go1.11,!gccgo,!appengine
|
|
||||||
|
|
||||||
#include "textflag.h"
|
|
||||||
|
|
||||||
// Implementation of Poly1305 using the vector facility (vx) and the VMSL instruction.
|
|
||||||
|
|
||||||
// constants
|
|
||||||
#define EX0 V1
|
|
||||||
#define EX1 V2
|
|
||||||
#define EX2 V3
|
|
||||||
|
|
||||||
// temporaries
|
|
||||||
#define T_0 V4
|
|
||||||
#define T_1 V5
|
|
||||||
#define T_2 V6
|
|
||||||
#define T_3 V7
|
|
||||||
#define T_4 V8
|
|
||||||
#define T_5 V9
|
|
||||||
#define T_6 V10
|
|
||||||
#define T_7 V11
|
|
||||||
#define T_8 V12
|
|
||||||
#define T_9 V13
|
|
||||||
#define T_10 V14
|
|
||||||
|
|
||||||
// r**2 & r**4
|
|
||||||
#define R_0 V15
|
|
||||||
#define R_1 V16
|
|
||||||
#define R_2 V17
|
|
||||||
#define R5_1 V18
|
|
||||||
#define R5_2 V19
|
|
||||||
// key (r)
|
|
||||||
#define RSAVE_0 R7
|
|
||||||
#define RSAVE_1 R8
|
|
||||||
#define RSAVE_2 R9
|
|
||||||
#define R5SAVE_1 R10
|
|
||||||
#define R5SAVE_2 R11
|
|
||||||
|
|
||||||
// message block
|
|
||||||
#define M0 V20
|
|
||||||
#define M1 V21
|
|
||||||
#define M2 V22
|
|
||||||
#define M3 V23
|
|
||||||
#define M4 V24
|
|
||||||
#define M5 V25
|
|
||||||
|
|
||||||
// accumulator
|
|
||||||
#define H0_0 V26
|
|
||||||
#define H1_0 V27
|
|
||||||
#define H2_0 V28
|
|
||||||
#define H0_1 V29
|
|
||||||
#define H1_1 V30
|
|
||||||
#define H2_1 V31
|
|
||||||
|
|
||||||
GLOBL ·keyMask<>(SB), RODATA, $16
|
|
||||||
DATA ·keyMask<>+0(SB)/8, $0xffffff0ffcffff0f
|
|
||||||
DATA ·keyMask<>+8(SB)/8, $0xfcffff0ffcffff0f
|
|
||||||
|
|
||||||
GLOBL ·bswapMask<>(SB), RODATA, $16
|
|
||||||
DATA ·bswapMask<>+0(SB)/8, $0x0f0e0d0c0b0a0908
|
|
||||||
DATA ·bswapMask<>+8(SB)/8, $0x0706050403020100
|
|
||||||
|
|
||||||
GLOBL ·constants<>(SB), RODATA, $48
|
|
||||||
// EX0
|
|
||||||
DATA ·constants<>+0(SB)/8, $0x18191a1b1c1d1e1f
|
|
||||||
DATA ·constants<>+8(SB)/8, $0x0000050403020100
|
|
||||||
// EX1
|
|
||||||
DATA ·constants<>+16(SB)/8, $0x18191a1b1c1d1e1f
|
|
||||||
DATA ·constants<>+24(SB)/8, $0x00000a0908070605
|
|
||||||
// EX2
|
|
||||||
DATA ·constants<>+32(SB)/8, $0x18191a1b1c1d1e1f
|
|
||||||
DATA ·constants<>+40(SB)/8, $0x0000000f0e0d0c0b
|
|
||||||
|
|
||||||
GLOBL ·c<>(SB), RODATA, $48
|
|
||||||
// EX0
|
|
||||||
DATA ·c<>+0(SB)/8, $0x0000050403020100
|
|
||||||
DATA ·c<>+8(SB)/8, $0x0000151413121110
|
|
||||||
// EX1
|
|
||||||
DATA ·c<>+16(SB)/8, $0x00000a0908070605
|
|
||||||
DATA ·c<>+24(SB)/8, $0x00001a1918171615
|
|
||||||
// EX2
|
|
||||||
DATA ·c<>+32(SB)/8, $0x0000000f0e0d0c0b
|
|
||||||
DATA ·c<>+40(SB)/8, $0x0000001f1e1d1c1b
|
|
||||||
|
|
||||||
GLOBL ·reduce<>(SB), RODATA, $32
|
|
||||||
// 44 bit
|
|
||||||
DATA ·reduce<>+0(SB)/8, $0x0
|
|
||||||
DATA ·reduce<>+8(SB)/8, $0xfffffffffff
|
|
||||||
// 42 bit
|
|
||||||
DATA ·reduce<>+16(SB)/8, $0x0
|
|
||||||
DATA ·reduce<>+24(SB)/8, $0x3ffffffffff
|
|
||||||
|
|
||||||
// h = (f*g) % (2**130-5) [partial reduction]
|
|
||||||
// uses T_0...T_9 temporary registers
|
|
||||||
// input: m02_0, m02_1, m02_2, m13_0, m13_1, m13_2, r_0, r_1, r_2, r5_1, r5_2, m4_0, m4_1, m4_2, m5_0, m5_1, m5_2
|
|
||||||
// temp: t0, t1, t2, t3, t4, t5, t6, t7, t8, t9
|
|
||||||
// output: m02_0, m02_1, m02_2, m13_0, m13_1, m13_2
|
|
||||||
#define MULTIPLY(m02_0, m02_1, m02_2, m13_0, m13_1, m13_2, r_0, r_1, r_2, r5_1, r5_2, m4_0, m4_1, m4_2, m5_0, m5_1, m5_2, t0, t1, t2, t3, t4, t5, t6, t7, t8, t9) \
|
|
||||||
\ // Eliminate the dependency for the last 2 VMSLs
|
|
||||||
VMSLG m02_0, r_2, m4_2, m4_2 \
|
|
||||||
VMSLG m13_0, r_2, m5_2, m5_2 \ // 8 VMSLs pipelined
|
|
||||||
VMSLG m02_0, r_0, m4_0, m4_0 \
|
|
||||||
VMSLG m02_1, r5_2, V0, T_0 \
|
|
||||||
VMSLG m02_0, r_1, m4_1, m4_1 \
|
|
||||||
VMSLG m02_1, r_0, V0, T_1 \
|
|
||||||
VMSLG m02_1, r_1, V0, T_2 \
|
|
||||||
VMSLG m02_2, r5_1, V0, T_3 \
|
|
||||||
VMSLG m02_2, r5_2, V0, T_4 \
|
|
||||||
VMSLG m13_0, r_0, m5_0, m5_0 \
|
|
||||||
VMSLG m13_1, r5_2, V0, T_5 \
|
|
||||||
VMSLG m13_0, r_1, m5_1, m5_1 \
|
|
||||||
VMSLG m13_1, r_0, V0, T_6 \
|
|
||||||
VMSLG m13_1, r_1, V0, T_7 \
|
|
||||||
VMSLG m13_2, r5_1, V0, T_8 \
|
|
||||||
VMSLG m13_2, r5_2, V0, T_9 \
|
|
||||||
VMSLG m02_2, r_0, m4_2, m4_2 \
|
|
||||||
VMSLG m13_2, r_0, m5_2, m5_2 \
|
|
||||||
VAQ m4_0, T_0, m02_0 \
|
|
||||||
VAQ m4_1, T_1, m02_1 \
|
|
||||||
VAQ m5_0, T_5, m13_0 \
|
|
||||||
VAQ m5_1, T_6, m13_1 \
|
|
||||||
VAQ m02_0, T_3, m02_0 \
|
|
||||||
VAQ m02_1, T_4, m02_1 \
|
|
||||||
VAQ m13_0, T_8, m13_0 \
|
|
||||||
VAQ m13_1, T_9, m13_1 \
|
|
||||||
VAQ m4_2, T_2, m02_2 \
|
|
||||||
VAQ m5_2, T_7, m13_2 \
|
|
||||||
|
|
||||||
// SQUARE uses three limbs of r and r_2*5 to output square of r
|
|
||||||
// uses T_1, T_5 and T_7 temporary registers
|
|
||||||
// input: r_0, r_1, r_2, r5_2
|
|
||||||
// temp: TEMP0, TEMP1, TEMP2
|
|
||||||
// output: p0, p1, p2
|
|
||||||
#define SQUARE(r_0, r_1, r_2, r5_2, p0, p1, p2, TEMP0, TEMP1, TEMP2) \
|
|
||||||
VMSLG r_0, r_0, p0, p0 \
|
|
||||||
VMSLG r_1, r5_2, V0, TEMP0 \
|
|
||||||
VMSLG r_2, r5_2, p1, p1 \
|
|
||||||
VMSLG r_0, r_1, V0, TEMP1 \
|
|
||||||
VMSLG r_1, r_1, p2, p2 \
|
|
||||||
VMSLG r_0, r_2, V0, TEMP2 \
|
|
||||||
VAQ TEMP0, p0, p0 \
|
|
||||||
VAQ TEMP1, p1, p1 \
|
|
||||||
VAQ TEMP2, p2, p2 \
|
|
||||||
VAQ TEMP0, p0, p0 \
|
|
||||||
VAQ TEMP1, p1, p1 \
|
|
||||||
VAQ TEMP2, p2, p2 \
|
|
||||||
|
|
||||||
// carry h0->h1->h2->h0 || h3->h4->h5->h3
|
|
||||||
// uses T_2, T_4, T_5, T_7, T_8, T_9
|
|
||||||
// t6, t7, t8, t9, t10, t11
|
|
||||||
// input: h0, h1, h2, h3, h4, h5
|
|
||||||
// temp: t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11
|
|
||||||
// output: h0, h1, h2, h3, h4, h5
|
|
||||||
#define REDUCE(h0, h1, h2, h3, h4, h5, t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11) \
|
|
||||||
VLM (R12), t6, t7 \ // 44 and 42 bit clear mask
|
|
||||||
VLEIB $7, $0x28, t10 \ // 5 byte shift mask
|
|
||||||
VREPIB $4, t8 \ // 4 bit shift mask
|
|
||||||
VREPIB $2, t11 \ // 2 bit shift mask
|
|
||||||
VSRLB t10, h0, t0 \ // h0 byte shift
|
|
||||||
VSRLB t10, h1, t1 \ // h1 byte shift
|
|
||||||
VSRLB t10, h2, t2 \ // h2 byte shift
|
|
||||||
VSRLB t10, h3, t3 \ // h3 byte shift
|
|
||||||
VSRLB t10, h4, t4 \ // h4 byte shift
|
|
||||||
VSRLB t10, h5, t5 \ // h5 byte shift
|
|
||||||
VSRL t8, t0, t0 \ // h0 bit shift
|
|
||||||
VSRL t8, t1, t1 \ // h2 bit shift
|
|
||||||
VSRL t11, t2, t2 \ // h2 bit shift
|
|
||||||
VSRL t8, t3, t3 \ // h3 bit shift
|
|
||||||
VSRL t8, t4, t4 \ // h4 bit shift
|
|
||||||
VESLG $2, t2, t9 \ // h2 carry x5
|
|
||||||
VSRL t11, t5, t5 \ // h5 bit shift
|
|
||||||
VN t6, h0, h0 \ // h0 clear carry
|
|
||||||
VAQ t2, t9, t2 \ // h2 carry x5
|
|
||||||
VESLG $2, t5, t9 \ // h5 carry x5
|
|
||||||
VN t6, h1, h1 \ // h1 clear carry
|
|
||||||
VN t7, h2, h2 \ // h2 clear carry
|
|
||||||
VAQ t5, t9, t5 \ // h5 carry x5
|
|
||||||
VN t6, h3, h3 \ // h3 clear carry
|
|
||||||
VN t6, h4, h4 \ // h4 clear carry
|
|
||||||
VN t7, h5, h5 \ // h5 clear carry
|
|
||||||
VAQ t0, h1, h1 \ // h0->h1
|
|
||||||
VAQ t3, h4, h4 \ // h3->h4
|
|
||||||
VAQ t1, h2, h2 \ // h1->h2
|
|
||||||
VAQ t4, h5, h5 \ // h4->h5
|
|
||||||
VAQ t2, h0, h0 \ // h2->h0
|
|
||||||
VAQ t5, h3, h3 \ // h5->h3
|
|
||||||
VREPG $1, t6, t6 \ // 44 and 42 bit masks across both halves
|
|
||||||
VREPG $1, t7, t7 \
|
|
||||||
VSLDB $8, h0, h0, h0 \ // set up [h0/1/2, h3/4/5]
|
|
||||||
VSLDB $8, h1, h1, h1 \
|
|
||||||
VSLDB $8, h2, h2, h2 \
|
|
||||||
VO h0, h3, h3 \
|
|
||||||
VO h1, h4, h4 \
|
|
||||||
VO h2, h5, h5 \
|
|
||||||
VESRLG $44, h3, t0 \ // 44 bit shift right
|
|
||||||
VESRLG $44, h4, t1 \
|
|
||||||
VESRLG $42, h5, t2 \
|
|
||||||
VN t6, h3, h3 \ // clear carry bits
|
|
||||||
VN t6, h4, h4 \
|
|
||||||
VN t7, h5, h5 \
|
|
||||||
VESLG $2, t2, t9 \ // multiply carry by 5
|
|
||||||
VAQ t9, t2, t2 \
|
|
||||||
VAQ t0, h4, h4 \
|
|
||||||
VAQ t1, h5, h5 \
|
|
||||||
VAQ t2, h3, h3 \
|
|
||||||
|
|
||||||
// carry h0->h1->h2->h0
|
|
||||||
// input: h0, h1, h2
|
|
||||||
// temp: t0, t1, t2, t3, t4, t5, t6, t7, t8
|
|
||||||
// output: h0, h1, h2
|
|
||||||
#define REDUCE2(h0, h1, h2, t0, t1, t2, t3, t4, t5, t6, t7, t8) \
|
|
||||||
VLEIB $7, $0x28, t3 \ // 5 byte shift mask
|
|
||||||
VREPIB $4, t4 \ // 4 bit shift mask
|
|
||||||
VREPIB $2, t7 \ // 2 bit shift mask
|
|
||||||
VGBM $0x003F, t5 \ // mask to clear carry bits
|
|
||||||
VSRLB t3, h0, t0 \
|
|
||||||
VSRLB t3, h1, t1 \
|
|
||||||
VSRLB t3, h2, t2 \
|
|
||||||
VESRLG $4, t5, t5 \ // 44 bit clear mask
|
|
||||||
VSRL t4, t0, t0 \
|
|
||||||
VSRL t4, t1, t1 \
|
|
||||||
VSRL t7, t2, t2 \
|
|
||||||
VESRLG $2, t5, t6 \ // 42 bit clear mask
|
|
||||||
VESLG $2, t2, t8 \
|
|
||||||
VAQ t8, t2, t2 \
|
|
||||||
VN t5, h0, h0 \
|
|
||||||
VN t5, h1, h1 \
|
|
||||||
VN t6, h2, h2 \
|
|
||||||
VAQ t0, h1, h1 \
|
|
||||||
VAQ t1, h2, h2 \
|
|
||||||
VAQ t2, h0, h0 \
|
|
||||||
VSRLB t3, h0, t0 \
|
|
||||||
VSRLB t3, h1, t1 \
|
|
||||||
VSRLB t3, h2, t2 \
|
|
||||||
VSRL t4, t0, t0 \
|
|
||||||
VSRL t4, t1, t1 \
|
|
||||||
VSRL t7, t2, t2 \
|
|
||||||
VN t5, h0, h0 \
|
|
||||||
VN t5, h1, h1 \
|
|
||||||
VESLG $2, t2, t8 \
|
|
||||||
VN t6, h2, h2 \
|
|
||||||
VAQ t0, h1, h1 \
|
|
||||||
VAQ t8, t2, t2 \
|
|
||||||
VAQ t1, h2, h2 \
|
|
||||||
VAQ t2, h0, h0 \
|
|
||||||
|
|
||||||
// expands two message blocks into the lower halfs of the d registers
|
|
||||||
// moves the contents of the d registers into upper halfs
|
|
||||||
// input: in1, in2, d0, d1, d2, d3, d4, d5
|
|
||||||
// temp: TEMP0, TEMP1, TEMP2, TEMP3
|
|
||||||
// output: d0, d1, d2, d3, d4, d5
|
|
||||||
#define EXPACC(in1, in2, d0, d1, d2, d3, d4, d5, TEMP0, TEMP1, TEMP2, TEMP3) \
|
|
||||||
VGBM $0xff3f, TEMP0 \
|
|
||||||
VGBM $0xff1f, TEMP1 \
|
|
||||||
VESLG $4, d1, TEMP2 \
|
|
||||||
VESLG $4, d4, TEMP3 \
|
|
||||||
VESRLG $4, TEMP0, TEMP0 \
|
|
||||||
VPERM in1, d0, EX0, d0 \
|
|
||||||
VPERM in2, d3, EX0, d3 \
|
|
||||||
VPERM in1, d2, EX2, d2 \
|
|
||||||
VPERM in2, d5, EX2, d5 \
|
|
||||||
VPERM in1, TEMP2, EX1, d1 \
|
|
||||||
VPERM in2, TEMP3, EX1, d4 \
|
|
||||||
VN TEMP0, d0, d0 \
|
|
||||||
VN TEMP0, d3, d3 \
|
|
||||||
VESRLG $4, d1, d1 \
|
|
||||||
VESRLG $4, d4, d4 \
|
|
||||||
VN TEMP1, d2, d2 \
|
|
||||||
VN TEMP1, d5, d5 \
|
|
||||||
VN TEMP0, d1, d1 \
|
|
||||||
VN TEMP0, d4, d4 \
|
|
||||||
|
|
||||||
// expands one message block into the lower halfs of the d registers
|
|
||||||
// moves the contents of the d registers into upper halfs
|
|
||||||
// input: in, d0, d1, d2
|
|
||||||
// temp: TEMP0, TEMP1, TEMP2
|
|
||||||
// output: d0, d1, d2
|
|
||||||
#define EXPACC2(in, d0, d1, d2, TEMP0, TEMP1, TEMP2) \
|
|
||||||
VGBM $0xff3f, TEMP0 \
|
|
||||||
VESLG $4, d1, TEMP2 \
|
|
||||||
VGBM $0xff1f, TEMP1 \
|
|
||||||
VPERM in, d0, EX0, d0 \
|
|
||||||
VESRLG $4, TEMP0, TEMP0 \
|
|
||||||
VPERM in, d2, EX2, d2 \
|
|
||||||
VPERM in, TEMP2, EX1, d1 \
|
|
||||||
VN TEMP0, d0, d0 \
|
|
||||||
VN TEMP1, d2, d2 \
|
|
||||||
VESRLG $4, d1, d1 \
|
|
||||||
VN TEMP0, d1, d1 \
|
|
||||||
|
|
||||||
// pack h2:h0 into h1:h0 (no carry)
|
|
||||||
// input: h0, h1, h2
|
|
||||||
// output: h0, h1, h2
|
|
||||||
#define PACK(h0, h1, h2) \
|
|
||||||
VMRLG h1, h2, h2 \ // copy h1 to upper half h2
|
|
||||||
VESLG $44, h1, h1 \ // shift limb 1 44 bits, leaving 20
|
|
||||||
VO h0, h1, h0 \ // combine h0 with 20 bits from limb 1
|
|
||||||
VESRLG $20, h2, h1 \ // put top 24 bits of limb 1 into h1
|
|
||||||
VLEIG $1, $0, h1 \ // clear h2 stuff from lower half of h1
|
|
||||||
VO h0, h1, h0 \ // h0 now has 88 bits (limb 0 and 1)
|
|
||||||
VLEIG $0, $0, h2 \ // clear upper half of h2
|
|
||||||
VESRLG $40, h2, h1 \ // h1 now has upper two bits of result
|
|
||||||
VLEIB $7, $88, h1 \ // for byte shift (11 bytes)
|
|
||||||
VSLB h1, h2, h2 \ // shift h2 11 bytes to the left
|
|
||||||
VO h0, h2, h0 \ // combine h0 with 20 bits from limb 1
|
|
||||||
VLEIG $0, $0, h1 \ // clear upper half of h1
|
|
||||||
|
|
||||||
// if h > 2**130-5 then h -= 2**130-5
|
|
||||||
// input: h0, h1
|
|
||||||
// temp: t0, t1, t2
|
|
||||||
// output: h0
|
|
||||||
#define MOD(h0, h1, t0, t1, t2) \
|
|
||||||
VZERO t0 \
|
|
||||||
VLEIG $1, $5, t0 \
|
|
||||||
VACCQ h0, t0, t1 \
|
|
||||||
VAQ h0, t0, t0 \
|
|
||||||
VONE t2 \
|
|
||||||
VLEIG $1, $-4, t2 \
|
|
||||||
VAQ t2, t1, t1 \
|
|
||||||
VACCQ h1, t1, t1 \
|
|
||||||
VONE t2 \
|
|
||||||
VAQ t2, t1, t1 \
|
|
||||||
VN h0, t1, t2 \
|
|
||||||
VNC t0, t1, t1 \
|
|
||||||
VO t1, t2, h0 \
|
|
||||||
|
|
||||||
// func poly1305vmsl(out *[16]byte, m *byte, mlen uint64, key *[32]key)
|
|
||||||
TEXT ·poly1305vmsl(SB), $0-32
|
|
||||||
// This code processes 6 + up to 4 blocks (32 bytes) per iteration
|
|
||||||
// using the algorithm described in:
|
|
||||||
// NEON crypto, Daniel J. Bernstein & Peter Schwabe
|
|
||||||
// https://cryptojedi.org/papers/neoncrypto-20120320.pdf
|
|
||||||
// And as moddified for VMSL as described in
|
|
||||||
// Accelerating Poly1305 Cryptographic Message Authentication on the z14
|
|
||||||
// O'Farrell et al, CASCON 2017, p48-55
|
|
||||||
// https://ibm.ent.box.com/s/jf9gedj0e9d2vjctfyh186shaztavnht
|
|
||||||
|
|
||||||
LMG out+0(FP), R1, R4 // R1=out, R2=m, R3=mlen, R4=key
|
|
||||||
VZERO V0 // c
|
|
||||||
|
|
||||||
// load EX0, EX1 and EX2
|
|
||||||
MOVD $·constants<>(SB), R5
|
|
||||||
VLM (R5), EX0, EX2 // c
|
|
||||||
|
|
||||||
// setup r
|
|
||||||
VL (R4), T_0
|
|
||||||
MOVD $·keyMask<>(SB), R6
|
|
||||||
VL (R6), T_1
|
|
||||||
VN T_0, T_1, T_0
|
|
||||||
VZERO T_2 // limbs for r
|
|
||||||
VZERO T_3
|
|
||||||
VZERO T_4
|
|
||||||
EXPACC2(T_0, T_2, T_3, T_4, T_1, T_5, T_7)
|
|
||||||
|
|
||||||
// T_2, T_3, T_4: [0, r]
|
|
||||||
|
|
||||||
// setup r*20
|
|
||||||
VLEIG $0, $0, T_0
|
|
||||||
VLEIG $1, $20, T_0 // T_0: [0, 20]
|
|
||||||
VZERO T_5
|
|
||||||
VZERO T_6
|
|
||||||
VMSLG T_0, T_3, T_5, T_5
|
|
||||||
VMSLG T_0, T_4, T_6, T_6
|
|
||||||
|
|
||||||
// store r for final block in GR
|
|
||||||
VLGVG $1, T_2, RSAVE_0 // c
|
|
||||||
VLGVG $1, T_3, RSAVE_1 // c
|
|
||||||
VLGVG $1, T_4, RSAVE_2 // c
|
|
||||||
VLGVG $1, T_5, R5SAVE_1 // c
|
|
||||||
VLGVG $1, T_6, R5SAVE_2 // c
|
|
||||||
|
|
||||||
// initialize h
|
|
||||||
VZERO H0_0
|
|
||||||
VZERO H1_0
|
|
||||||
VZERO H2_0
|
|
||||||
VZERO H0_1
|
|
||||||
VZERO H1_1
|
|
||||||
VZERO H2_1
|
|
||||||
|
|
||||||
// initialize pointer for reduce constants
|
|
||||||
MOVD $·reduce<>(SB), R12
|
|
||||||
|
|
||||||
// calculate r**2 and 20*(r**2)
|
|
||||||
VZERO R_0
|
|
||||||
VZERO R_1
|
|
||||||
VZERO R_2
|
|
||||||
SQUARE(T_2, T_3, T_4, T_6, R_0, R_1, R_2, T_1, T_5, T_7)
|
|
||||||
REDUCE2(R_0, R_1, R_2, M0, M1, M2, M3, M4, R5_1, R5_2, M5, T_1)
|
|
||||||
VZERO R5_1
|
|
||||||
VZERO R5_2
|
|
||||||
VMSLG T_0, R_1, R5_1, R5_1
|
|
||||||
VMSLG T_0, R_2, R5_2, R5_2
|
|
||||||
|
|
||||||
// skip r**4 calculation if 3 blocks or less
|
|
||||||
CMPBLE R3, $48, b4
|
|
||||||
|
|
||||||
// calculate r**4 and 20*(r**4)
|
|
||||||
VZERO T_8
|
|
||||||
VZERO T_9
|
|
||||||
VZERO T_10
|
|
||||||
SQUARE(R_0, R_1, R_2, R5_2, T_8, T_9, T_10, T_1, T_5, T_7)
|
|
||||||
REDUCE2(T_8, T_9, T_10, M0, M1, M2, M3, M4, T_2, T_3, M5, T_1)
|
|
||||||
VZERO T_2
|
|
||||||
VZERO T_3
|
|
||||||
VMSLG T_0, T_9, T_2, T_2
|
|
||||||
VMSLG T_0, T_10, T_3, T_3
|
|
||||||
|
|
||||||
// put r**2 to the right and r**4 to the left of R_0, R_1, R_2
|
|
||||||
VSLDB $8, T_8, T_8, T_8
|
|
||||||
VSLDB $8, T_9, T_9, T_9
|
|
||||||
VSLDB $8, T_10, T_10, T_10
|
|
||||||
VSLDB $8, T_2, T_2, T_2
|
|
||||||
VSLDB $8, T_3, T_3, T_3
|
|
||||||
|
|
||||||
VO T_8, R_0, R_0
|
|
||||||
VO T_9, R_1, R_1
|
|
||||||
VO T_10, R_2, R_2
|
|
||||||
VO T_2, R5_1, R5_1
|
|
||||||
VO T_3, R5_2, R5_2
|
|
||||||
|
|
||||||
CMPBLE R3, $80, load // less than or equal to 5 blocks in message
|
|
||||||
|
|
||||||
// 6(or 5+1) blocks
|
|
||||||
SUB $81, R3
|
|
||||||
VLM (R2), M0, M4
|
|
||||||
VLL R3, 80(R2), M5
|
|
||||||
ADD $1, R3
|
|
||||||
MOVBZ $1, R0
|
|
||||||
CMPBGE R3, $16, 2(PC)
|
|
||||||
VLVGB R3, R0, M5
|
|
||||||
MOVD $96(R2), R2
|
|
||||||
EXPACC(M0, M1, H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, T_0, T_1, T_2, T_3)
|
|
||||||
EXPACC(M2, M3, H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, T_0, T_1, T_2, T_3)
|
|
||||||
VLEIB $2, $1, H2_0
|
|
||||||
VLEIB $2, $1, H2_1
|
|
||||||
VLEIB $10, $1, H2_0
|
|
||||||
VLEIB $10, $1, H2_1
|
|
||||||
|
|
||||||
VZERO M0
|
|
||||||
VZERO M1
|
|
||||||
VZERO M2
|
|
||||||
VZERO M3
|
|
||||||
VZERO T_4
|
|
||||||
VZERO T_10
|
|
||||||
EXPACC(M4, M5, M0, M1, M2, M3, T_4, T_10, T_0, T_1, T_2, T_3)
|
|
||||||
VLR T_4, M4
|
|
||||||
VLEIB $10, $1, M2
|
|
||||||
CMPBLT R3, $16, 2(PC)
|
|
||||||
VLEIB $10, $1, T_10
|
|
||||||
MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M2, M3, M4, T_10, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9)
|
|
||||||
REDUCE(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, T_10, M0, M1, M2, M3, M4, T_4, T_5, T_2, T_7, T_8, T_9)
|
|
||||||
VMRHG V0, H0_1, H0_0
|
|
||||||
VMRHG V0, H1_1, H1_0
|
|
||||||
VMRHG V0, H2_1, H2_0
|
|
||||||
VMRLG V0, H0_1, H0_1
|
|
||||||
VMRLG V0, H1_1, H1_1
|
|
||||||
VMRLG V0, H2_1, H2_1
|
|
||||||
|
|
||||||
SUB $16, R3
|
|
||||||
CMPBLE R3, $0, square
|
|
||||||
|
|
||||||
load:
|
|
||||||
// load EX0, EX1 and EX2
|
|
||||||
MOVD $·c<>(SB), R5
|
|
||||||
VLM (R5), EX0, EX2
|
|
||||||
|
|
||||||
loop:
|
|
||||||
CMPBLE R3, $64, add // b4 // last 4 or less blocks left
|
|
||||||
|
|
||||||
// next 4 full blocks
|
|
||||||
VLM (R2), M2, M5
|
|
||||||
SUB $64, R3
|
|
||||||
MOVD $64(R2), R2
|
|
||||||
REDUCE(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, T_10, M0, M1, T_0, T_1, T_3, T_4, T_5, T_2, T_7, T_8, T_9)
|
|
||||||
|
|
||||||
// expacc in-lined to create [m2, m3] limbs
|
|
||||||
VGBM $0x3f3f, T_0 // 44 bit clear mask
|
|
||||||
VGBM $0x1f1f, T_1 // 40 bit clear mask
|
|
||||||
VPERM M2, M3, EX0, T_3
|
|
||||||
VESRLG $4, T_0, T_0 // 44 bit clear mask ready
|
|
||||||
VPERM M2, M3, EX1, T_4
|
|
||||||
VPERM M2, M3, EX2, T_5
|
|
||||||
VN T_0, T_3, T_3
|
|
||||||
VESRLG $4, T_4, T_4
|
|
||||||
VN T_1, T_5, T_5
|
|
||||||
VN T_0, T_4, T_4
|
|
||||||
VMRHG H0_1, T_3, H0_0
|
|
||||||
VMRHG H1_1, T_4, H1_0
|
|
||||||
VMRHG H2_1, T_5, H2_0
|
|
||||||
VMRLG H0_1, T_3, H0_1
|
|
||||||
VMRLG H1_1, T_4, H1_1
|
|
||||||
VMRLG H2_1, T_5, H2_1
|
|
||||||
VLEIB $10, $1, H2_0
|
|
||||||
VLEIB $10, $1, H2_1
|
|
||||||
VPERM M4, M5, EX0, T_3
|
|
||||||
VPERM M4, M5, EX1, T_4
|
|
||||||
VPERM M4, M5, EX2, T_5
|
|
||||||
VN T_0, T_3, T_3
|
|
||||||
VESRLG $4, T_4, T_4
|
|
||||||
VN T_1, T_5, T_5
|
|
||||||
VN T_0, T_4, T_4
|
|
||||||
VMRHG V0, T_3, M0
|
|
||||||
VMRHG V0, T_4, M1
|
|
||||||
VMRHG V0, T_5, M2
|
|
||||||
VMRLG V0, T_3, M3
|
|
||||||
VMRLG V0, T_4, M4
|
|
||||||
VMRLG V0, T_5, M5
|
|
||||||
VLEIB $10, $1, M2
|
|
||||||
VLEIB $10, $1, M5
|
|
||||||
|
|
||||||
MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M2, M3, M4, M5, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9)
|
|
||||||
CMPBNE R3, $0, loop
|
|
||||||
REDUCE(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, T_10, M0, M1, M3, M4, M5, T_4, T_5, T_2, T_7, T_8, T_9)
|
|
||||||
VMRHG V0, H0_1, H0_0
|
|
||||||
VMRHG V0, H1_1, H1_0
|
|
||||||
VMRHG V0, H2_1, H2_0
|
|
||||||
VMRLG V0, H0_1, H0_1
|
|
||||||
VMRLG V0, H1_1, H1_1
|
|
||||||
VMRLG V0, H2_1, H2_1
|
|
||||||
|
|
||||||
// load EX0, EX1, EX2
|
|
||||||
MOVD $·constants<>(SB), R5
|
|
||||||
VLM (R5), EX0, EX2
|
|
||||||
|
|
||||||
// sum vectors
|
|
||||||
VAQ H0_0, H0_1, H0_0
|
|
||||||
VAQ H1_0, H1_1, H1_0
|
|
||||||
VAQ H2_0, H2_1, H2_0
|
|
||||||
|
|
||||||
// h may be >= 2*(2**130-5) so we need to reduce it again
|
|
||||||
// M0...M4 are used as temps here
|
|
||||||
REDUCE2(H0_0, H1_0, H2_0, M0, M1, M2, M3, M4, T_9, T_10, H0_1, M5)
|
|
||||||
|
|
||||||
next: // carry h1->h2
|
|
||||||
VLEIB $7, $0x28, T_1
|
|
||||||
VREPIB $4, T_2
|
|
||||||
VGBM $0x003F, T_3
|
|
||||||
VESRLG $4, T_3
|
|
||||||
|
|
||||||
// byte shift
|
|
||||||
VSRLB T_1, H1_0, T_4
|
|
||||||
|
|
||||||
// bit shift
|
|
||||||
VSRL T_2, T_4, T_4
|
|
||||||
|
|
||||||
// clear h1 carry bits
|
|
||||||
VN T_3, H1_0, H1_0
|
|
||||||
|
|
||||||
// add carry
|
|
||||||
VAQ T_4, H2_0, H2_0
|
|
||||||
|
|
||||||
// h is now < 2*(2**130-5)
|
|
||||||
// pack h into h1 (hi) and h0 (lo)
|
|
||||||
PACK(H0_0, H1_0, H2_0)
|
|
||||||
|
|
||||||
// if h > 2**130-5 then h -= 2**130-5
|
|
||||||
MOD(H0_0, H1_0, T_0, T_1, T_2)
|
|
||||||
|
|
||||||
// h += s
|
|
||||||
MOVD $·bswapMask<>(SB), R5
|
|
||||||
VL (R5), T_1
|
|
||||||
VL 16(R4), T_0
|
|
||||||
VPERM T_0, T_0, T_1, T_0 // reverse bytes (to big)
|
|
||||||
VAQ T_0, H0_0, H0_0
|
|
||||||
VPERM H0_0, H0_0, T_1, H0_0 // reverse bytes (to little)
|
|
||||||
VST H0_0, (R1)
|
|
||||||
RET
|
|
||||||
|
|
||||||
add:
|
|
||||||
// load EX0, EX1, EX2
|
|
||||||
MOVD $·constants<>(SB), R5
|
|
||||||
VLM (R5), EX0, EX2
|
|
||||||
|
|
||||||
REDUCE(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, T_10, M0, M1, M3, M4, M5, T_4, T_5, T_2, T_7, T_8, T_9)
|
|
||||||
VMRHG V0, H0_1, H0_0
|
|
||||||
VMRHG V0, H1_1, H1_0
|
|
||||||
VMRHG V0, H2_1, H2_0
|
|
||||||
VMRLG V0, H0_1, H0_1
|
|
||||||
VMRLG V0, H1_1, H1_1
|
|
||||||
VMRLG V0, H2_1, H2_1
|
|
||||||
CMPBLE R3, $64, b4
|
|
||||||
|
|
||||||
b4:
|
|
||||||
CMPBLE R3, $48, b3 // 3 blocks or less
|
|
||||||
|
|
||||||
// 4(3+1) blocks remaining
|
|
||||||
SUB $49, R3
|
|
||||||
VLM (R2), M0, M2
|
|
||||||
VLL R3, 48(R2), M3
|
|
||||||
ADD $1, R3
|
|
||||||
MOVBZ $1, R0
|
|
||||||
CMPBEQ R3, $16, 2(PC)
|
|
||||||
VLVGB R3, R0, M3
|
|
||||||
MOVD $64(R2), R2
|
|
||||||
EXPACC(M0, M1, H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, T_0, T_1, T_2, T_3)
|
|
||||||
VLEIB $10, $1, H2_0
|
|
||||||
VLEIB $10, $1, H2_1
|
|
||||||
VZERO M0
|
|
||||||
VZERO M1
|
|
||||||
VZERO M4
|
|
||||||
VZERO M5
|
|
||||||
VZERO T_4
|
|
||||||
VZERO T_10
|
|
||||||
EXPACC(M2, M3, M0, M1, M4, M5, T_4, T_10, T_0, T_1, T_2, T_3)
|
|
||||||
VLR T_4, M2
|
|
||||||
VLEIB $10, $1, M4
|
|
||||||
CMPBNE R3, $16, 2(PC)
|
|
||||||
VLEIB $10, $1, T_10
|
|
||||||
MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M4, M5, M2, T_10, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9)
|
|
||||||
REDUCE(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, T_10, M0, M1, M3, M4, M5, T_4, T_5, T_2, T_7, T_8, T_9)
|
|
||||||
VMRHG V0, H0_1, H0_0
|
|
||||||
VMRHG V0, H1_1, H1_0
|
|
||||||
VMRHG V0, H2_1, H2_0
|
|
||||||
VMRLG V0, H0_1, H0_1
|
|
||||||
VMRLG V0, H1_1, H1_1
|
|
||||||
VMRLG V0, H2_1, H2_1
|
|
||||||
SUB $16, R3
|
|
||||||
CMPBLE R3, $0, square // this condition must always hold true!
|
|
||||||
|
|
||||||
b3:
|
|
||||||
CMPBLE R3, $32, b2
|
|
||||||
|
|
||||||
// 3 blocks remaining
|
|
||||||
|
|
||||||
// setup [r²,r]
|
|
||||||
VSLDB $8, R_0, R_0, R_0
|
|
||||||
VSLDB $8, R_1, R_1, R_1
|
|
||||||
VSLDB $8, R_2, R_2, R_2
|
|
||||||
VSLDB $8, R5_1, R5_1, R5_1
|
|
||||||
VSLDB $8, R5_2, R5_2, R5_2
|
|
||||||
|
|
||||||
VLVGG $1, RSAVE_0, R_0
|
|
||||||
VLVGG $1, RSAVE_1, R_1
|
|
||||||
VLVGG $1, RSAVE_2, R_2
|
|
||||||
VLVGG $1, R5SAVE_1, R5_1
|
|
||||||
VLVGG $1, R5SAVE_2, R5_2
|
|
||||||
|
|
||||||
// setup [h0, h1]
|
|
||||||
VSLDB $8, H0_0, H0_0, H0_0
|
|
||||||
VSLDB $8, H1_0, H1_0, H1_0
|
|
||||||
VSLDB $8, H2_0, H2_0, H2_0
|
|
||||||
VO H0_1, H0_0, H0_0
|
|
||||||
VO H1_1, H1_0, H1_0
|
|
||||||
VO H2_1, H2_0, H2_0
|
|
||||||
VZERO H0_1
|
|
||||||
VZERO H1_1
|
|
||||||
VZERO H2_1
|
|
||||||
|
|
||||||
VZERO M0
|
|
||||||
VZERO M1
|
|
||||||
VZERO M2
|
|
||||||
VZERO M3
|
|
||||||
VZERO M4
|
|
||||||
VZERO M5
|
|
||||||
|
|
||||||
// H*[r**2, r]
|
|
||||||
MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M2, M3, M4, M5, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9)
|
|
||||||
REDUCE2(H0_0, H1_0, H2_0, M0, M1, M2, M3, M4, H0_1, H1_1, T_10, M5)
|
|
||||||
|
|
||||||
SUB $33, R3
|
|
||||||
VLM (R2), M0, M1
|
|
||||||
VLL R3, 32(R2), M2
|
|
||||||
ADD $1, R3
|
|
||||||
MOVBZ $1, R0
|
|
||||||
CMPBEQ R3, $16, 2(PC)
|
|
||||||
VLVGB R3, R0, M2
|
|
||||||
|
|
||||||
// H += m0
|
|
||||||
VZERO T_1
|
|
||||||
VZERO T_2
|
|
||||||
VZERO T_3
|
|
||||||
EXPACC2(M0, T_1, T_2, T_3, T_4, T_5, T_6)
|
|
||||||
VLEIB $10, $1, T_3
|
|
||||||
VAG H0_0, T_1, H0_0
|
|
||||||
VAG H1_0, T_2, H1_0
|
|
||||||
VAG H2_0, T_3, H2_0
|
|
||||||
|
|
||||||
VZERO M0
|
|
||||||
VZERO M3
|
|
||||||
VZERO M4
|
|
||||||
VZERO M5
|
|
||||||
VZERO T_10
|
|
||||||
|
|
||||||
// (H+m0)*r
|
|
||||||
MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M3, M4, M5, V0, T_10, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9)
|
|
||||||
REDUCE2(H0_0, H1_0, H2_0, M0, M3, M4, M5, T_10, H0_1, H1_1, H2_1, T_9)
|
|
||||||
|
|
||||||
// H += m1
|
|
||||||
VZERO V0
|
|
||||||
VZERO T_1
|
|
||||||
VZERO T_2
|
|
||||||
VZERO T_3
|
|
||||||
EXPACC2(M1, T_1, T_2, T_3, T_4, T_5, T_6)
|
|
||||||
VLEIB $10, $1, T_3
|
|
||||||
VAQ H0_0, T_1, H0_0
|
|
||||||
VAQ H1_0, T_2, H1_0
|
|
||||||
VAQ H2_0, T_3, H2_0
|
|
||||||
REDUCE2(H0_0, H1_0, H2_0, M0, M3, M4, M5, T_9, H0_1, H1_1, H2_1, T_10)
|
|
||||||
|
|
||||||
// [H, m2] * [r**2, r]
|
|
||||||
EXPACC2(M2, H0_0, H1_0, H2_0, T_1, T_2, T_3)
|
|
||||||
CMPBNE R3, $16, 2(PC)
|
|
||||||
VLEIB $10, $1, H2_0
|
|
||||||
VZERO M0
|
|
||||||
VZERO M1
|
|
||||||
VZERO M2
|
|
||||||
VZERO M3
|
|
||||||
VZERO M4
|
|
||||||
VZERO M5
|
|
||||||
MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M2, M3, M4, M5, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9)
|
|
||||||
REDUCE2(H0_0, H1_0, H2_0, M0, M1, M2, M3, M4, H0_1, H1_1, M5, T_10)
|
|
||||||
SUB $16, R3
|
|
||||||
CMPBLE R3, $0, next // this condition must always hold true!
|
|
||||||
|
|
||||||
b2:
|
|
||||||
CMPBLE R3, $16, b1
|
|
||||||
|
|
||||||
// 2 blocks remaining
|
|
||||||
|
|
||||||
// setup [r²,r]
|
|
||||||
VSLDB $8, R_0, R_0, R_0
|
|
||||||
VSLDB $8, R_1, R_1, R_1
|
|
||||||
VSLDB $8, R_2, R_2, R_2
|
|
||||||
VSLDB $8, R5_1, R5_1, R5_1
|
|
||||||
VSLDB $8, R5_2, R5_2, R5_2
|
|
||||||
|
|
||||||
VLVGG $1, RSAVE_0, R_0
|
|
||||||
VLVGG $1, RSAVE_1, R_1
|
|
||||||
VLVGG $1, RSAVE_2, R_2
|
|
||||||
VLVGG $1, R5SAVE_1, R5_1
|
|
||||||
VLVGG $1, R5SAVE_2, R5_2
|
|
||||||
|
|
||||||
// setup [h0, h1]
|
|
||||||
VSLDB $8, H0_0, H0_0, H0_0
|
|
||||||
VSLDB $8, H1_0, H1_0, H1_0
|
|
||||||
VSLDB $8, H2_0, H2_0, H2_0
|
|
||||||
VO H0_1, H0_0, H0_0
|
|
||||||
VO H1_1, H1_0, H1_0
|
|
||||||
VO H2_1, H2_0, H2_0
|
|
||||||
VZERO H0_1
|
|
||||||
VZERO H1_1
|
|
||||||
VZERO H2_1
|
|
||||||
|
|
||||||
VZERO M0
|
|
||||||
VZERO M1
|
|
||||||
VZERO M2
|
|
||||||
VZERO M3
|
|
||||||
VZERO M4
|
|
||||||
VZERO M5
|
|
||||||
|
|
||||||
// H*[r**2, r]
|
|
||||||
MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M2, M3, M4, M5, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9)
|
|
||||||
REDUCE(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, T_10, M0, M1, M2, M3, M4, T_4, T_5, T_2, T_7, T_8, T_9)
|
|
||||||
VMRHG V0, H0_1, H0_0
|
|
||||||
VMRHG V0, H1_1, H1_0
|
|
||||||
VMRHG V0, H2_1, H2_0
|
|
||||||
VMRLG V0, H0_1, H0_1
|
|
||||||
VMRLG V0, H1_1, H1_1
|
|
||||||
VMRLG V0, H2_1, H2_1
|
|
||||||
|
|
||||||
// move h to the left and 0s at the right
|
|
||||||
VSLDB $8, H0_0, H0_0, H0_0
|
|
||||||
VSLDB $8, H1_0, H1_0, H1_0
|
|
||||||
VSLDB $8, H2_0, H2_0, H2_0
|
|
||||||
|
|
||||||
// get message blocks and append 1 to start
|
|
||||||
SUB $17, R3
|
|
||||||
VL (R2), M0
|
|
||||||
VLL R3, 16(R2), M1
|
|
||||||
ADD $1, R3
|
|
||||||
MOVBZ $1, R0
|
|
||||||
CMPBEQ R3, $16, 2(PC)
|
|
||||||
VLVGB R3, R0, M1
|
|
||||||
VZERO T_6
|
|
||||||
VZERO T_7
|
|
||||||
VZERO T_8
|
|
||||||
EXPACC2(M0, T_6, T_7, T_8, T_1, T_2, T_3)
|
|
||||||
EXPACC2(M1, T_6, T_7, T_8, T_1, T_2, T_3)
|
|
||||||
VLEIB $2, $1, T_8
|
|
||||||
CMPBNE R3, $16, 2(PC)
|
|
||||||
VLEIB $10, $1, T_8
|
|
||||||
|
|
||||||
// add [m0, m1] to h
|
|
||||||
VAG H0_0, T_6, H0_0
|
|
||||||
VAG H1_0, T_7, H1_0
|
|
||||||
VAG H2_0, T_8, H2_0
|
|
||||||
|
|
||||||
VZERO M2
|
|
||||||
VZERO M3
|
|
||||||
VZERO M4
|
|
||||||
VZERO M5
|
|
||||||
VZERO T_10
|
|
||||||
VZERO M0
|
|
||||||
|
|
||||||
// at this point R_0 .. R5_2 look like [r**2, r]
|
|
||||||
MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M2, M3, M4, M5, T_10, M0, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9)
|
|
||||||
REDUCE2(H0_0, H1_0, H2_0, M2, M3, M4, M5, T_9, H0_1, H1_1, H2_1, T_10)
|
|
||||||
SUB $16, R3, R3
|
|
||||||
CMPBLE R3, $0, next
|
|
||||||
|
|
||||||
b1:
|
|
||||||
CMPBLE R3, $0, next
|
|
||||||
|
|
||||||
// 1 block remaining
|
|
||||||
|
|
||||||
// setup [r²,r]
|
|
||||||
VSLDB $8, R_0, R_0, R_0
|
|
||||||
VSLDB $8, R_1, R_1, R_1
|
|
||||||
VSLDB $8, R_2, R_2, R_2
|
|
||||||
VSLDB $8, R5_1, R5_1, R5_1
|
|
||||||
VSLDB $8, R5_2, R5_2, R5_2
|
|
||||||
|
|
||||||
VLVGG $1, RSAVE_0, R_0
|
|
||||||
VLVGG $1, RSAVE_1, R_1
|
|
||||||
VLVGG $1, RSAVE_2, R_2
|
|
||||||
VLVGG $1, R5SAVE_1, R5_1
|
|
||||||
VLVGG $1, R5SAVE_2, R5_2
|
|
||||||
|
|
||||||
// setup [h0, h1]
|
|
||||||
VSLDB $8, H0_0, H0_0, H0_0
|
|
||||||
VSLDB $8, H1_0, H1_0, H1_0
|
|
||||||
VSLDB $8, H2_0, H2_0, H2_0
|
|
||||||
VO H0_1, H0_0, H0_0
|
|
||||||
VO H1_1, H1_0, H1_0
|
|
||||||
VO H2_1, H2_0, H2_0
|
|
||||||
VZERO H0_1
|
|
||||||
VZERO H1_1
|
|
||||||
VZERO H2_1
|
|
||||||
|
|
||||||
VZERO M0
|
|
||||||
VZERO M1
|
|
||||||
VZERO M2
|
|
||||||
VZERO M3
|
|
||||||
VZERO M4
|
|
||||||
VZERO M5
|
|
||||||
|
|
||||||
// H*[r**2, r]
|
|
||||||
MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M2, M3, M4, M5, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9)
|
|
||||||
REDUCE2(H0_0, H1_0, H2_0, M0, M1, M2, M3, M4, T_9, T_10, H0_1, M5)
|
|
||||||
|
|
||||||
// set up [0, m0] limbs
|
|
||||||
SUB $1, R3
|
|
||||||
VLL R3, (R2), M0
|
|
||||||
ADD $1, R3
|
|
||||||
MOVBZ $1, R0
|
|
||||||
CMPBEQ R3, $16, 2(PC)
|
|
||||||
VLVGB R3, R0, M0
|
|
||||||
VZERO T_1
|
|
||||||
VZERO T_2
|
|
||||||
VZERO T_3
|
|
||||||
EXPACC2(M0, T_1, T_2, T_3, T_4, T_5, T_6)// limbs: [0, m]
|
|
||||||
CMPBNE R3, $16, 2(PC)
|
|
||||||
VLEIB $10, $1, T_3
|
|
||||||
|
|
||||||
// h+m0
|
|
||||||
VAQ H0_0, T_1, H0_0
|
|
||||||
VAQ H1_0, T_2, H1_0
|
|
||||||
VAQ H2_0, T_3, H2_0
|
|
||||||
|
|
||||||
VZERO M0
|
|
||||||
VZERO M1
|
|
||||||
VZERO M2
|
|
||||||
VZERO M3
|
|
||||||
VZERO M4
|
|
||||||
VZERO M5
|
|
||||||
MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M2, M3, M4, M5, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9)
|
|
||||||
REDUCE2(H0_0, H1_0, H2_0, M0, M1, M2, M3, M4, T_9, T_10, H0_1, M5)
|
|
||||||
|
|
||||||
BR next
|
|
||||||
|
|
||||||
square:
|
|
||||||
// setup [r²,r]
|
|
||||||
VSLDB $8, R_0, R_0, R_0
|
|
||||||
VSLDB $8, R_1, R_1, R_1
|
|
||||||
VSLDB $8, R_2, R_2, R_2
|
|
||||||
VSLDB $8, R5_1, R5_1, R5_1
|
|
||||||
VSLDB $8, R5_2, R5_2, R5_2
|
|
||||||
|
|
||||||
VLVGG $1, RSAVE_0, R_0
|
|
||||||
VLVGG $1, RSAVE_1, R_1
|
|
||||||
VLVGG $1, RSAVE_2, R_2
|
|
||||||
VLVGG $1, R5SAVE_1, R5_1
|
|
||||||
VLVGG $1, R5SAVE_2, R5_2
|
|
||||||
|
|
||||||
// setup [h0, h1]
|
|
||||||
VSLDB $8, H0_0, H0_0, H0_0
|
|
||||||
VSLDB $8, H1_0, H1_0, H1_0
|
|
||||||
VSLDB $8, H2_0, H2_0, H2_0
|
|
||||||
VO H0_1, H0_0, H0_0
|
|
||||||
VO H1_1, H1_0, H1_0
|
|
||||||
VO H2_1, H2_0, H2_0
|
|
||||||
VZERO H0_1
|
|
||||||
VZERO H1_1
|
|
||||||
VZERO H2_1
|
|
||||||
|
|
||||||
VZERO M0
|
|
||||||
VZERO M1
|
|
||||||
VZERO M2
|
|
||||||
VZERO M3
|
|
||||||
VZERO M4
|
|
||||||
VZERO M5
|
|
||||||
|
|
||||||
// (h0*r**2) + (h1*r)
|
|
||||||
MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M2, M3, M4, M5, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9)
|
|
||||||
REDUCE2(H0_0, H1_0, H2_0, M0, M1, M2, M3, M4, T_9, T_10, H0_1, M5)
|
|
||||||
BR next
|
|
97
vendor/golang.org/x/crypto/ssh/buffer.go
generated
vendored
97
vendor/golang.org/x/crypto/ssh/buffer.go
generated
vendored
@ -1,97 +0,0 @@
|
|||||||
// 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 ssh
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
// buffer provides a linked list buffer for data exchange
|
|
||||||
// between producer and consumer. Theoretically the buffer is
|
|
||||||
// of unlimited capacity as it does no allocation of its own.
|
|
||||||
type buffer struct {
|
|
||||||
// protects concurrent access to head, tail and closed
|
|
||||||
*sync.Cond
|
|
||||||
|
|
||||||
head *element // the buffer that will be read first
|
|
||||||
tail *element // the buffer that will be read last
|
|
||||||
|
|
||||||
closed bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// An element represents a single link in a linked list.
|
|
||||||
type element struct {
|
|
||||||
buf []byte
|
|
||||||
next *element
|
|
||||||
}
|
|
||||||
|
|
||||||
// newBuffer returns an empty buffer that is not closed.
|
|
||||||
func newBuffer() *buffer {
|
|
||||||
e := new(element)
|
|
||||||
b := &buffer{
|
|
||||||
Cond: newCond(),
|
|
||||||
head: e,
|
|
||||||
tail: e,
|
|
||||||
}
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
// write makes buf available for Read to receive.
|
|
||||||
// buf must not be modified after the call to write.
|
|
||||||
func (b *buffer) write(buf []byte) {
|
|
||||||
b.Cond.L.Lock()
|
|
||||||
e := &element{buf: buf}
|
|
||||||
b.tail.next = e
|
|
||||||
b.tail = e
|
|
||||||
b.Cond.Signal()
|
|
||||||
b.Cond.L.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
// eof closes the buffer. Reads from the buffer once all
|
|
||||||
// the data has been consumed will receive io.EOF.
|
|
||||||
func (b *buffer) eof() {
|
|
||||||
b.Cond.L.Lock()
|
|
||||||
b.closed = true
|
|
||||||
b.Cond.Signal()
|
|
||||||
b.Cond.L.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read reads data from the internal buffer in buf. Reads will block
|
|
||||||
// if no data is available, or until the buffer is closed.
|
|
||||||
func (b *buffer) Read(buf []byte) (n int, err error) {
|
|
||||||
b.Cond.L.Lock()
|
|
||||||
defer b.Cond.L.Unlock()
|
|
||||||
|
|
||||||
for len(buf) > 0 {
|
|
||||||
// if there is data in b.head, copy it
|
|
||||||
if len(b.head.buf) > 0 {
|
|
||||||
r := copy(buf, b.head.buf)
|
|
||||||
buf, b.head.buf = buf[r:], b.head.buf[r:]
|
|
||||||
n += r
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// if there is a next buffer, make it the head
|
|
||||||
if len(b.head.buf) == 0 && b.head != b.tail {
|
|
||||||
b.head = b.head.next
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// if at least one byte has been copied, return
|
|
||||||
if n > 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
// if nothing was read, and there is nothing outstanding
|
|
||||||
// check to see if the buffer is closed.
|
|
||||||
if b.closed {
|
|
||||||
err = io.EOF
|
|
||||||
break
|
|
||||||
}
|
|
||||||
// out of buffers, wait for producer
|
|
||||||
b.Cond.Wait()
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
535
vendor/golang.org/x/crypto/ssh/certs.go
generated
vendored
535
vendor/golang.org/x/crypto/ssh/certs.go
generated
vendored
@ -1,535 +0,0 @@
|
|||||||
// 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 ssh
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"net"
|
|
||||||
"sort"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// These constants from [PROTOCOL.certkeys] represent the algorithm names
|
|
||||||
// for certificate types supported by this package.
|
|
||||||
const (
|
|
||||||
CertAlgoRSAv01 = "ssh-rsa-cert-v01@openssh.com"
|
|
||||||
CertAlgoDSAv01 = "ssh-dss-cert-v01@openssh.com"
|
|
||||||
CertAlgoECDSA256v01 = "ecdsa-sha2-nistp256-cert-v01@openssh.com"
|
|
||||||
CertAlgoECDSA384v01 = "ecdsa-sha2-nistp384-cert-v01@openssh.com"
|
|
||||||
CertAlgoECDSA521v01 = "ecdsa-sha2-nistp521-cert-v01@openssh.com"
|
|
||||||
CertAlgoED25519v01 = "ssh-ed25519-cert-v01@openssh.com"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Certificate types distinguish between host and user
|
|
||||||
// certificates. The values can be set in the CertType field of
|
|
||||||
// Certificate.
|
|
||||||
const (
|
|
||||||
UserCert = 1
|
|
||||||
HostCert = 2
|
|
||||||
)
|
|
||||||
|
|
||||||
// Signature represents a cryptographic signature.
|
|
||||||
type Signature struct {
|
|
||||||
Format string
|
|
||||||
Blob []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
// CertTimeInfinity can be used for OpenSSHCertV01.ValidBefore to indicate that
|
|
||||||
// a certificate does not expire.
|
|
||||||
const CertTimeInfinity = 1<<64 - 1
|
|
||||||
|
|
||||||
// An Certificate represents an OpenSSH certificate as defined in
|
|
||||||
// [PROTOCOL.certkeys]?rev=1.8. The Certificate type implements the
|
|
||||||
// PublicKey interface, so it can be unmarshaled using
|
|
||||||
// ParsePublicKey.
|
|
||||||
type Certificate struct {
|
|
||||||
Nonce []byte
|
|
||||||
Key PublicKey
|
|
||||||
Serial uint64
|
|
||||||
CertType uint32
|
|
||||||
KeyId string
|
|
||||||
ValidPrincipals []string
|
|
||||||
ValidAfter uint64
|
|
||||||
ValidBefore uint64
|
|
||||||
Permissions
|
|
||||||
Reserved []byte
|
|
||||||
SignatureKey PublicKey
|
|
||||||
Signature *Signature
|
|
||||||
}
|
|
||||||
|
|
||||||
// genericCertData holds the key-independent part of the certificate data.
|
|
||||||
// Overall, certificates contain an nonce, public key fields and
|
|
||||||
// key-independent fields.
|
|
||||||
type genericCertData struct {
|
|
||||||
Serial uint64
|
|
||||||
CertType uint32
|
|
||||||
KeyId string
|
|
||||||
ValidPrincipals []byte
|
|
||||||
ValidAfter uint64
|
|
||||||
ValidBefore uint64
|
|
||||||
CriticalOptions []byte
|
|
||||||
Extensions []byte
|
|
||||||
Reserved []byte
|
|
||||||
SignatureKey []byte
|
|
||||||
Signature []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func marshalStringList(namelist []string) []byte {
|
|
||||||
var to []byte
|
|
||||||
for _, name := range namelist {
|
|
||||||
s := struct{ N string }{name}
|
|
||||||
to = append(to, Marshal(&s)...)
|
|
||||||
}
|
|
||||||
return to
|
|
||||||
}
|
|
||||||
|
|
||||||
type optionsTuple struct {
|
|
||||||
Key string
|
|
||||||
Value []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
type optionsTupleValue struct {
|
|
||||||
Value string
|
|
||||||
}
|
|
||||||
|
|
||||||
// serialize a map of critical options or extensions
|
|
||||||
// issue #10569 - per [PROTOCOL.certkeys] and SSH implementation,
|
|
||||||
// we need two length prefixes for a non-empty string value
|
|
||||||
func marshalTuples(tups map[string]string) []byte {
|
|
||||||
keys := make([]string, 0, len(tups))
|
|
||||||
for key := range tups {
|
|
||||||
keys = append(keys, key)
|
|
||||||
}
|
|
||||||
sort.Strings(keys)
|
|
||||||
|
|
||||||
var ret []byte
|
|
||||||
for _, key := range keys {
|
|
||||||
s := optionsTuple{Key: key}
|
|
||||||
if value := tups[key]; len(value) > 0 {
|
|
||||||
s.Value = Marshal(&optionsTupleValue{value})
|
|
||||||
}
|
|
||||||
ret = append(ret, Marshal(&s)...)
|
|
||||||
}
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
// issue #10569 - per [PROTOCOL.certkeys] and SSH implementation,
|
|
||||||
// we need two length prefixes for a non-empty option value
|
|
||||||
func parseTuples(in []byte) (map[string]string, error) {
|
|
||||||
tups := map[string]string{}
|
|
||||||
var lastKey string
|
|
||||||
var haveLastKey bool
|
|
||||||
|
|
||||||
for len(in) > 0 {
|
|
||||||
var key, val, extra []byte
|
|
||||||
var ok bool
|
|
||||||
|
|
||||||
if key, in, ok = parseString(in); !ok {
|
|
||||||
return nil, errShortRead
|
|
||||||
}
|
|
||||||
keyStr := string(key)
|
|
||||||
// according to [PROTOCOL.certkeys], the names must be in
|
|
||||||
// lexical order.
|
|
||||||
if haveLastKey && keyStr <= lastKey {
|
|
||||||
return nil, fmt.Errorf("ssh: certificate options are not in lexical order")
|
|
||||||
}
|
|
||||||
lastKey, haveLastKey = keyStr, true
|
|
||||||
// the next field is a data field, which if non-empty has a string embedded
|
|
||||||
if val, in, ok = parseString(in); !ok {
|
|
||||||
return nil, errShortRead
|
|
||||||
}
|
|
||||||
if len(val) > 0 {
|
|
||||||
val, extra, ok = parseString(val)
|
|
||||||
if !ok {
|
|
||||||
return nil, errShortRead
|
|
||||||
}
|
|
||||||
if len(extra) > 0 {
|
|
||||||
return nil, fmt.Errorf("ssh: unexpected trailing data after certificate option value")
|
|
||||||
}
|
|
||||||
tups[keyStr] = string(val)
|
|
||||||
} else {
|
|
||||||
tups[keyStr] = ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return tups, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseCert(in []byte, privAlgo string) (*Certificate, error) {
|
|
||||||
nonce, rest, ok := parseString(in)
|
|
||||||
if !ok {
|
|
||||||
return nil, errShortRead
|
|
||||||
}
|
|
||||||
|
|
||||||
key, rest, err := parsePubKey(rest, privAlgo)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var g genericCertData
|
|
||||||
if err := Unmarshal(rest, &g); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
c := &Certificate{
|
|
||||||
Nonce: nonce,
|
|
||||||
Key: key,
|
|
||||||
Serial: g.Serial,
|
|
||||||
CertType: g.CertType,
|
|
||||||
KeyId: g.KeyId,
|
|
||||||
ValidAfter: g.ValidAfter,
|
|
||||||
ValidBefore: g.ValidBefore,
|
|
||||||
}
|
|
||||||
|
|
||||||
for principals := g.ValidPrincipals; len(principals) > 0; {
|
|
||||||
principal, rest, ok := parseString(principals)
|
|
||||||
if !ok {
|
|
||||||
return nil, errShortRead
|
|
||||||
}
|
|
||||||
c.ValidPrincipals = append(c.ValidPrincipals, string(principal))
|
|
||||||
principals = rest
|
|
||||||
}
|
|
||||||
|
|
||||||
c.CriticalOptions, err = parseTuples(g.CriticalOptions)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
c.Extensions, err = parseTuples(g.Extensions)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
c.Reserved = g.Reserved
|
|
||||||
k, err := ParsePublicKey(g.SignatureKey)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
c.SignatureKey = k
|
|
||||||
c.Signature, rest, ok = parseSignatureBody(g.Signature)
|
|
||||||
if !ok || len(rest) > 0 {
|
|
||||||
return nil, errors.New("ssh: signature parse error")
|
|
||||||
}
|
|
||||||
|
|
||||||
return c, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type openSSHCertSigner struct {
|
|
||||||
pub *Certificate
|
|
||||||
signer Signer
|
|
||||||
}
|
|
||||||
|
|
||||||
type algorithmOpenSSHCertSigner struct {
|
|
||||||
*openSSHCertSigner
|
|
||||||
algorithmSigner AlgorithmSigner
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewCertSigner returns a Signer that signs with the given Certificate, whose
|
|
||||||
// private key is held by signer. It returns an error if the public key in cert
|
|
||||||
// doesn't match the key used by signer.
|
|
||||||
func NewCertSigner(cert *Certificate, signer Signer) (Signer, error) {
|
|
||||||
if bytes.Compare(cert.Key.Marshal(), signer.PublicKey().Marshal()) != 0 {
|
|
||||||
return nil, errors.New("ssh: signer and cert have different public key")
|
|
||||||
}
|
|
||||||
|
|
||||||
if algorithmSigner, ok := signer.(AlgorithmSigner); ok {
|
|
||||||
return &algorithmOpenSSHCertSigner{
|
|
||||||
&openSSHCertSigner{cert, signer}, algorithmSigner}, nil
|
|
||||||
} else {
|
|
||||||
return &openSSHCertSigner{cert, signer}, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *openSSHCertSigner) Sign(rand io.Reader, data []byte) (*Signature, error) {
|
|
||||||
return s.signer.Sign(rand, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *openSSHCertSigner) PublicKey() PublicKey {
|
|
||||||
return s.pub
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *algorithmOpenSSHCertSigner) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) {
|
|
||||||
return s.algorithmSigner.SignWithAlgorithm(rand, data, algorithm)
|
|
||||||
}
|
|
||||||
|
|
||||||
const sourceAddressCriticalOption = "source-address"
|
|
||||||
|
|
||||||
// CertChecker does the work of verifying a certificate. Its methods
|
|
||||||
// can be plugged into ClientConfig.HostKeyCallback and
|
|
||||||
// ServerConfig.PublicKeyCallback. For the CertChecker to work,
|
|
||||||
// minimally, the IsAuthority callback should be set.
|
|
||||||
type CertChecker struct {
|
|
||||||
// SupportedCriticalOptions lists the CriticalOptions that the
|
|
||||||
// server application layer understands. These are only used
|
|
||||||
// for user certificates.
|
|
||||||
SupportedCriticalOptions []string
|
|
||||||
|
|
||||||
// IsUserAuthority should return true if the key is recognized as an
|
|
||||||
// authority for the given user certificate. This allows for
|
|
||||||
// certificates to be signed by other certificates. This must be set
|
|
||||||
// if this CertChecker will be checking user certificates.
|
|
||||||
IsUserAuthority func(auth PublicKey) bool
|
|
||||||
|
|
||||||
// IsHostAuthority should report whether the key is recognized as
|
|
||||||
// an authority for this host. This allows for certificates to be
|
|
||||||
// signed by other keys, and for those other keys to only be valid
|
|
||||||
// signers for particular hostnames. This must be set if this
|
|
||||||
// CertChecker will be checking host certificates.
|
|
||||||
IsHostAuthority func(auth PublicKey, address string) bool
|
|
||||||
|
|
||||||
// Clock is used for verifying time stamps. If nil, time.Now
|
|
||||||
// is used.
|
|
||||||
Clock func() time.Time
|
|
||||||
|
|
||||||
// UserKeyFallback is called when CertChecker.Authenticate encounters a
|
|
||||||
// public key that is not a certificate. It must implement validation
|
|
||||||
// of user keys or else, if nil, all such keys are rejected.
|
|
||||||
UserKeyFallback func(conn ConnMetadata, key PublicKey) (*Permissions, error)
|
|
||||||
|
|
||||||
// HostKeyFallback is called when CertChecker.CheckHostKey encounters a
|
|
||||||
// public key that is not a certificate. It must implement host key
|
|
||||||
// validation or else, if nil, all such keys are rejected.
|
|
||||||
HostKeyFallback HostKeyCallback
|
|
||||||
|
|
||||||
// IsRevoked is called for each certificate so that revocation checking
|
|
||||||
// can be implemented. It should return true if the given certificate
|
|
||||||
// is revoked and false otherwise. If nil, no certificates are
|
|
||||||
// considered to have been revoked.
|
|
||||||
IsRevoked func(cert *Certificate) bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// CheckHostKey checks a host key certificate. This method can be
|
|
||||||
// plugged into ClientConfig.HostKeyCallback.
|
|
||||||
func (c *CertChecker) CheckHostKey(addr string, remote net.Addr, key PublicKey) error {
|
|
||||||
cert, ok := key.(*Certificate)
|
|
||||||
if !ok {
|
|
||||||
if c.HostKeyFallback != nil {
|
|
||||||
return c.HostKeyFallback(addr, remote, key)
|
|
||||||
}
|
|
||||||
return errors.New("ssh: non-certificate host key")
|
|
||||||
}
|
|
||||||
if cert.CertType != HostCert {
|
|
||||||
return fmt.Errorf("ssh: certificate presented as a host key has type %d", cert.CertType)
|
|
||||||
}
|
|
||||||
if !c.IsHostAuthority(cert.SignatureKey, addr) {
|
|
||||||
return fmt.Errorf("ssh: no authorities for hostname: %v", addr)
|
|
||||||
}
|
|
||||||
|
|
||||||
hostname, _, err := net.SplitHostPort(addr)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pass hostname only as principal for host certificates (consistent with OpenSSH)
|
|
||||||
return c.CheckCert(hostname, cert)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Authenticate checks a user certificate. Authenticate can be used as
|
|
||||||
// a value for ServerConfig.PublicKeyCallback.
|
|
||||||
func (c *CertChecker) Authenticate(conn ConnMetadata, pubKey PublicKey) (*Permissions, error) {
|
|
||||||
cert, ok := pubKey.(*Certificate)
|
|
||||||
if !ok {
|
|
||||||
if c.UserKeyFallback != nil {
|
|
||||||
return c.UserKeyFallback(conn, pubKey)
|
|
||||||
}
|
|
||||||
return nil, errors.New("ssh: normal key pairs not accepted")
|
|
||||||
}
|
|
||||||
|
|
||||||
if cert.CertType != UserCert {
|
|
||||||
return nil, fmt.Errorf("ssh: cert has type %d", cert.CertType)
|
|
||||||
}
|
|
||||||
if !c.IsUserAuthority(cert.SignatureKey) {
|
|
||||||
return nil, fmt.Errorf("ssh: certificate signed by unrecognized authority")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := c.CheckCert(conn.User(), cert); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &cert.Permissions, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CheckCert checks CriticalOptions, ValidPrincipals, revocation, timestamp and
|
|
||||||
// the signature of the certificate.
|
|
||||||
func (c *CertChecker) CheckCert(principal string, cert *Certificate) error {
|
|
||||||
if c.IsRevoked != nil && c.IsRevoked(cert) {
|
|
||||||
return fmt.Errorf("ssh: certificate serial %d revoked", cert.Serial)
|
|
||||||
}
|
|
||||||
|
|
||||||
for opt := range cert.CriticalOptions {
|
|
||||||
// sourceAddressCriticalOption will be enforced by
|
|
||||||
// serverAuthenticate
|
|
||||||
if opt == sourceAddressCriticalOption {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
found := false
|
|
||||||
for _, supp := range c.SupportedCriticalOptions {
|
|
||||||
if supp == opt {
|
|
||||||
found = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !found {
|
|
||||||
return fmt.Errorf("ssh: unsupported critical option %q in certificate", opt)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(cert.ValidPrincipals) > 0 {
|
|
||||||
// By default, certs are valid for all users/hosts.
|
|
||||||
found := false
|
|
||||||
for _, p := range cert.ValidPrincipals {
|
|
||||||
if p == principal {
|
|
||||||
found = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !found {
|
|
||||||
return fmt.Errorf("ssh: principal %q not in the set of valid principals for given certificate: %q", principal, cert.ValidPrincipals)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
clock := c.Clock
|
|
||||||
if clock == nil {
|
|
||||||
clock = time.Now
|
|
||||||
}
|
|
||||||
|
|
||||||
unixNow := clock().Unix()
|
|
||||||
if after := int64(cert.ValidAfter); after < 0 || unixNow < int64(cert.ValidAfter) {
|
|
||||||
return fmt.Errorf("ssh: cert is not yet valid")
|
|
||||||
}
|
|
||||||
if before := int64(cert.ValidBefore); cert.ValidBefore != uint64(CertTimeInfinity) && (unixNow >= before || before < 0) {
|
|
||||||
return fmt.Errorf("ssh: cert has expired")
|
|
||||||
}
|
|
||||||
if err := cert.SignatureKey.Verify(cert.bytesForSigning(), cert.Signature); err != nil {
|
|
||||||
return fmt.Errorf("ssh: certificate signature does not verify")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SignCert sets c.SignatureKey to the authority's public key and stores a
|
|
||||||
// Signature, by authority, in the certificate.
|
|
||||||
func (c *Certificate) SignCert(rand io.Reader, authority Signer) error {
|
|
||||||
c.Nonce = make([]byte, 32)
|
|
||||||
if _, err := io.ReadFull(rand, c.Nonce); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
c.SignatureKey = authority.PublicKey()
|
|
||||||
|
|
||||||
sig, err := authority.Sign(rand, c.bytesForSigning())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
c.Signature = sig
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var certAlgoNames = map[string]string{
|
|
||||||
KeyAlgoRSA: CertAlgoRSAv01,
|
|
||||||
KeyAlgoDSA: CertAlgoDSAv01,
|
|
||||||
KeyAlgoECDSA256: CertAlgoECDSA256v01,
|
|
||||||
KeyAlgoECDSA384: CertAlgoECDSA384v01,
|
|
||||||
KeyAlgoECDSA521: CertAlgoECDSA521v01,
|
|
||||||
KeyAlgoED25519: CertAlgoED25519v01,
|
|
||||||
}
|
|
||||||
|
|
||||||
// certToPrivAlgo returns the underlying algorithm for a certificate algorithm.
|
|
||||||
// Panics if a non-certificate algorithm is passed.
|
|
||||||
func certToPrivAlgo(algo string) string {
|
|
||||||
for privAlgo, pubAlgo := range certAlgoNames {
|
|
||||||
if pubAlgo == algo {
|
|
||||||
return privAlgo
|
|
||||||
}
|
|
||||||
}
|
|
||||||
panic("unknown cert algorithm")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cert *Certificate) bytesForSigning() []byte {
|
|
||||||
c2 := *cert
|
|
||||||
c2.Signature = nil
|
|
||||||
out := c2.Marshal()
|
|
||||||
// Drop trailing signature length.
|
|
||||||
return out[:len(out)-4]
|
|
||||||
}
|
|
||||||
|
|
||||||
// Marshal serializes c into OpenSSH's wire format. It is part of the
|
|
||||||
// PublicKey interface.
|
|
||||||
func (c *Certificate) Marshal() []byte {
|
|
||||||
generic := genericCertData{
|
|
||||||
Serial: c.Serial,
|
|
||||||
CertType: c.CertType,
|
|
||||||
KeyId: c.KeyId,
|
|
||||||
ValidPrincipals: marshalStringList(c.ValidPrincipals),
|
|
||||||
ValidAfter: uint64(c.ValidAfter),
|
|
||||||
ValidBefore: uint64(c.ValidBefore),
|
|
||||||
CriticalOptions: marshalTuples(c.CriticalOptions),
|
|
||||||
Extensions: marshalTuples(c.Extensions),
|
|
||||||
Reserved: c.Reserved,
|
|
||||||
SignatureKey: c.SignatureKey.Marshal(),
|
|
||||||
}
|
|
||||||
if c.Signature != nil {
|
|
||||||
generic.Signature = Marshal(c.Signature)
|
|
||||||
}
|
|
||||||
genericBytes := Marshal(&generic)
|
|
||||||
keyBytes := c.Key.Marshal()
|
|
||||||
_, keyBytes, _ = parseString(keyBytes)
|
|
||||||
prefix := Marshal(&struct {
|
|
||||||
Name string
|
|
||||||
Nonce []byte
|
|
||||||
Key []byte `ssh:"rest"`
|
|
||||||
}{c.Type(), c.Nonce, keyBytes})
|
|
||||||
|
|
||||||
result := make([]byte, 0, len(prefix)+len(genericBytes))
|
|
||||||
result = append(result, prefix...)
|
|
||||||
result = append(result, genericBytes...)
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// Type returns the key name. It is part of the PublicKey interface.
|
|
||||||
func (c *Certificate) Type() string {
|
|
||||||
algo, ok := certAlgoNames[c.Key.Type()]
|
|
||||||
if !ok {
|
|
||||||
panic("unknown cert key type " + c.Key.Type())
|
|
||||||
}
|
|
||||||
return algo
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify verifies a signature against the certificate's public
|
|
||||||
// key. It is part of the PublicKey interface.
|
|
||||||
func (c *Certificate) Verify(data []byte, sig *Signature) error {
|
|
||||||
return c.Key.Verify(data, sig)
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseSignatureBody(in []byte) (out *Signature, rest []byte, ok bool) {
|
|
||||||
format, in, ok := parseString(in)
|
|
||||||
if !ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
out = &Signature{
|
|
||||||
Format: string(format),
|
|
||||||
}
|
|
||||||
|
|
||||||
if out.Blob, in, ok = parseString(in); !ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
return out, in, ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseSignature(in []byte) (out *Signature, rest []byte, ok bool) {
|
|
||||||
sigBytes, rest, ok := parseString(in)
|
|
||||||
if !ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
out, trailing, ok := parseSignatureBody(sigBytes)
|
|
||||||
if !ok || len(trailing) > 0 {
|
|
||||||
return nil, nil, false
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
633
vendor/golang.org/x/crypto/ssh/channel.go
generated
vendored
633
vendor/golang.org/x/crypto/ssh/channel.go
generated
vendored
@ -1,633 +0,0 @@
|
|||||||
// 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 ssh
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/binary"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"log"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
minPacketLength = 9
|
|
||||||
// channelMaxPacket contains the maximum number of bytes that will be
|
|
||||||
// sent in a single packet. As per RFC 4253, section 6.1, 32k is also
|
|
||||||
// the minimum.
|
|
||||||
channelMaxPacket = 1 << 15
|
|
||||||
// We follow OpenSSH here.
|
|
||||||
channelWindowSize = 64 * channelMaxPacket
|
|
||||||
)
|
|
||||||
|
|
||||||
// NewChannel represents an incoming request to a channel. It must either be
|
|
||||||
// accepted for use by calling Accept, or rejected by calling Reject.
|
|
||||||
type NewChannel interface {
|
|
||||||
// Accept accepts the channel creation request. It returns the Channel
|
|
||||||
// and a Go channel containing SSH requests. The Go channel must be
|
|
||||||
// serviced otherwise the Channel will hang.
|
|
||||||
Accept() (Channel, <-chan *Request, error)
|
|
||||||
|
|
||||||
// Reject rejects the channel creation request. After calling
|
|
||||||
// this, no other methods on the Channel may be called.
|
|
||||||
Reject(reason RejectionReason, message string) error
|
|
||||||
|
|
||||||
// ChannelType returns the type of the channel, as supplied by the
|
|
||||||
// client.
|
|
||||||
ChannelType() string
|
|
||||||
|
|
||||||
// ExtraData returns the arbitrary payload for this channel, as supplied
|
|
||||||
// by the client. This data is specific to the channel type.
|
|
||||||
ExtraData() []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
// A Channel is an ordered, reliable, flow-controlled, duplex stream
|
|
||||||
// that is multiplexed over an SSH connection.
|
|
||||||
type Channel interface {
|
|
||||||
// Read reads up to len(data) bytes from the channel.
|
|
||||||
Read(data []byte) (int, error)
|
|
||||||
|
|
||||||
// Write writes len(data) bytes to the channel.
|
|
||||||
Write(data []byte) (int, error)
|
|
||||||
|
|
||||||
// Close signals end of channel use. No data may be sent after this
|
|
||||||
// call.
|
|
||||||
Close() error
|
|
||||||
|
|
||||||
// CloseWrite signals the end of sending in-band
|
|
||||||
// data. Requests may still be sent, and the other side may
|
|
||||||
// still send data
|
|
||||||
CloseWrite() error
|
|
||||||
|
|
||||||
// SendRequest sends a channel request. If wantReply is true,
|
|
||||||
// it will wait for a reply and return the result as a
|
|
||||||
// boolean, otherwise the return value will be false. Channel
|
|
||||||
// requests are out-of-band messages so they may be sent even
|
|
||||||
// if the data stream is closed or blocked by flow control.
|
|
||||||
// If the channel is closed before a reply is returned, io.EOF
|
|
||||||
// is returned.
|
|
||||||
SendRequest(name string, wantReply bool, payload []byte) (bool, error)
|
|
||||||
|
|
||||||
// Stderr returns an io.ReadWriter that writes to this channel
|
|
||||||
// with the extended data type set to stderr. Stderr may
|
|
||||||
// safely be read and written from a different goroutine than
|
|
||||||
// Read and Write respectively.
|
|
||||||
Stderr() io.ReadWriter
|
|
||||||
}
|
|
||||||
|
|
||||||
// Request is a request sent outside of the normal stream of
|
|
||||||
// data. Requests can either be specific to an SSH channel, or they
|
|
||||||
// can be global.
|
|
||||||
type Request struct {
|
|
||||||
Type string
|
|
||||||
WantReply bool
|
|
||||||
Payload []byte
|
|
||||||
|
|
||||||
ch *channel
|
|
||||||
mux *mux
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reply sends a response to a request. It must be called for all requests
|
|
||||||
// where WantReply is true and is a no-op otherwise. The payload argument is
|
|
||||||
// ignored for replies to channel-specific requests.
|
|
||||||
func (r *Request) Reply(ok bool, payload []byte) error {
|
|
||||||
if !r.WantReply {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if r.ch == nil {
|
|
||||||
return r.mux.ackRequest(ok, payload)
|
|
||||||
}
|
|
||||||
|
|
||||||
return r.ch.ackRequest(ok)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RejectionReason is an enumeration used when rejecting channel creation
|
|
||||||
// requests. See RFC 4254, section 5.1.
|
|
||||||
type RejectionReason uint32
|
|
||||||
|
|
||||||
const (
|
|
||||||
Prohibited RejectionReason = iota + 1
|
|
||||||
ConnectionFailed
|
|
||||||
UnknownChannelType
|
|
||||||
ResourceShortage
|
|
||||||
)
|
|
||||||
|
|
||||||
// String converts the rejection reason to human readable form.
|
|
||||||
func (r RejectionReason) String() string {
|
|
||||||
switch r {
|
|
||||||
case Prohibited:
|
|
||||||
return "administratively prohibited"
|
|
||||||
case ConnectionFailed:
|
|
||||||
return "connect failed"
|
|
||||||
case UnknownChannelType:
|
|
||||||
return "unknown channel type"
|
|
||||||
case ResourceShortage:
|
|
||||||
return "resource shortage"
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("unknown reason %d", int(r))
|
|
||||||
}
|
|
||||||
|
|
||||||
func min(a uint32, b int) uint32 {
|
|
||||||
if a < uint32(b) {
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
return uint32(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
type channelDirection uint8
|
|
||||||
|
|
||||||
const (
|
|
||||||
channelInbound channelDirection = iota
|
|
||||||
channelOutbound
|
|
||||||
)
|
|
||||||
|
|
||||||
// channel is an implementation of the Channel interface that works
|
|
||||||
// with the mux class.
|
|
||||||
type channel struct {
|
|
||||||
// R/O after creation
|
|
||||||
chanType string
|
|
||||||
extraData []byte
|
|
||||||
localId, remoteId uint32
|
|
||||||
|
|
||||||
// maxIncomingPayload and maxRemotePayload are the maximum
|
|
||||||
// payload sizes of normal and extended data packets for
|
|
||||||
// receiving and sending, respectively. The wire packet will
|
|
||||||
// be 9 or 13 bytes larger (excluding encryption overhead).
|
|
||||||
maxIncomingPayload uint32
|
|
||||||
maxRemotePayload uint32
|
|
||||||
|
|
||||||
mux *mux
|
|
||||||
|
|
||||||
// decided is set to true if an accept or reject message has been sent
|
|
||||||
// (for outbound channels) or received (for inbound channels).
|
|
||||||
decided bool
|
|
||||||
|
|
||||||
// direction contains either channelOutbound, for channels created
|
|
||||||
// locally, or channelInbound, for channels created by the peer.
|
|
||||||
direction channelDirection
|
|
||||||
|
|
||||||
// Pending internal channel messages.
|
|
||||||
msg chan interface{}
|
|
||||||
|
|
||||||
// Since requests have no ID, there can be only one request
|
|
||||||
// with WantReply=true outstanding. This lock is held by a
|
|
||||||
// goroutine that has such an outgoing request pending.
|
|
||||||
sentRequestMu sync.Mutex
|
|
||||||
|
|
||||||
incomingRequests chan *Request
|
|
||||||
|
|
||||||
sentEOF bool
|
|
||||||
|
|
||||||
// thread-safe data
|
|
||||||
remoteWin window
|
|
||||||
pending *buffer
|
|
||||||
extPending *buffer
|
|
||||||
|
|
||||||
// windowMu protects myWindow, the flow-control window.
|
|
||||||
windowMu sync.Mutex
|
|
||||||
myWindow uint32
|
|
||||||
|
|
||||||
// writeMu serializes calls to mux.conn.writePacket() and
|
|
||||||
// protects sentClose and packetPool. This mutex must be
|
|
||||||
// different from windowMu, as writePacket can block if there
|
|
||||||
// is a key exchange pending.
|
|
||||||
writeMu sync.Mutex
|
|
||||||
sentClose bool
|
|
||||||
|
|
||||||
// packetPool has a buffer for each extended channel ID to
|
|
||||||
// save allocations during writes.
|
|
||||||
packetPool map[uint32][]byte
|
|
||||||
}
|
|
||||||
|
|
||||||
// writePacket sends a packet. If the packet is a channel close, it updates
|
|
||||||
// sentClose. This method takes the lock c.writeMu.
|
|
||||||
func (ch *channel) writePacket(packet []byte) error {
|
|
||||||
ch.writeMu.Lock()
|
|
||||||
if ch.sentClose {
|
|
||||||
ch.writeMu.Unlock()
|
|
||||||
return io.EOF
|
|
||||||
}
|
|
||||||
ch.sentClose = (packet[0] == msgChannelClose)
|
|
||||||
err := ch.mux.conn.writePacket(packet)
|
|
||||||
ch.writeMu.Unlock()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ch *channel) sendMessage(msg interface{}) error {
|
|
||||||
if debugMux {
|
|
||||||
log.Printf("send(%d): %#v", ch.mux.chanList.offset, msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
p := Marshal(msg)
|
|
||||||
binary.BigEndian.PutUint32(p[1:], ch.remoteId)
|
|
||||||
return ch.writePacket(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteExtended writes data to a specific extended stream. These streams are
|
|
||||||
// used, for example, for stderr.
|
|
||||||
func (ch *channel) WriteExtended(data []byte, extendedCode uint32) (n int, err error) {
|
|
||||||
if ch.sentEOF {
|
|
||||||
return 0, io.EOF
|
|
||||||
}
|
|
||||||
// 1 byte message type, 4 bytes remoteId, 4 bytes data length
|
|
||||||
opCode := byte(msgChannelData)
|
|
||||||
headerLength := uint32(9)
|
|
||||||
if extendedCode > 0 {
|
|
||||||
headerLength += 4
|
|
||||||
opCode = msgChannelExtendedData
|
|
||||||
}
|
|
||||||
|
|
||||||
ch.writeMu.Lock()
|
|
||||||
packet := ch.packetPool[extendedCode]
|
|
||||||
// We don't remove the buffer from packetPool, so
|
|
||||||
// WriteExtended calls from different goroutines will be
|
|
||||||
// flagged as errors by the race detector.
|
|
||||||
ch.writeMu.Unlock()
|
|
||||||
|
|
||||||
for len(data) > 0 {
|
|
||||||
space := min(ch.maxRemotePayload, len(data))
|
|
||||||
if space, err = ch.remoteWin.reserve(space); err != nil {
|
|
||||||
return n, err
|
|
||||||
}
|
|
||||||
if want := headerLength + space; uint32(cap(packet)) < want {
|
|
||||||
packet = make([]byte, want)
|
|
||||||
} else {
|
|
||||||
packet = packet[:want]
|
|
||||||
}
|
|
||||||
|
|
||||||
todo := data[:space]
|
|
||||||
|
|
||||||
packet[0] = opCode
|
|
||||||
binary.BigEndian.PutUint32(packet[1:], ch.remoteId)
|
|
||||||
if extendedCode > 0 {
|
|
||||||
binary.BigEndian.PutUint32(packet[5:], uint32(extendedCode))
|
|
||||||
}
|
|
||||||
binary.BigEndian.PutUint32(packet[headerLength-4:], uint32(len(todo)))
|
|
||||||
copy(packet[headerLength:], todo)
|
|
||||||
if err = ch.writePacket(packet); err != nil {
|
|
||||||
return n, err
|
|
||||||
}
|
|
||||||
|
|
||||||
n += len(todo)
|
|
||||||
data = data[len(todo):]
|
|
||||||
}
|
|
||||||
|
|
||||||
ch.writeMu.Lock()
|
|
||||||
ch.packetPool[extendedCode] = packet
|
|
||||||
ch.writeMu.Unlock()
|
|
||||||
|
|
||||||
return n, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ch *channel) handleData(packet []byte) error {
|
|
||||||
headerLen := 9
|
|
||||||
isExtendedData := packet[0] == msgChannelExtendedData
|
|
||||||
if isExtendedData {
|
|
||||||
headerLen = 13
|
|
||||||
}
|
|
||||||
if len(packet) < headerLen {
|
|
||||||
// malformed data packet
|
|
||||||
return parseError(packet[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
var extended uint32
|
|
||||||
if isExtendedData {
|
|
||||||
extended = binary.BigEndian.Uint32(packet[5:])
|
|
||||||
}
|
|
||||||
|
|
||||||
length := binary.BigEndian.Uint32(packet[headerLen-4 : headerLen])
|
|
||||||
if length == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if length > ch.maxIncomingPayload {
|
|
||||||
// TODO(hanwen): should send Disconnect?
|
|
||||||
return errors.New("ssh: incoming packet exceeds maximum payload size")
|
|
||||||
}
|
|
||||||
|
|
||||||
data := packet[headerLen:]
|
|
||||||
if length != uint32(len(data)) {
|
|
||||||
return errors.New("ssh: wrong packet length")
|
|
||||||
}
|
|
||||||
|
|
||||||
ch.windowMu.Lock()
|
|
||||||
if ch.myWindow < length {
|
|
||||||
ch.windowMu.Unlock()
|
|
||||||
// TODO(hanwen): should send Disconnect with reason?
|
|
||||||
return errors.New("ssh: remote side wrote too much")
|
|
||||||
}
|
|
||||||
ch.myWindow -= length
|
|
||||||
ch.windowMu.Unlock()
|
|
||||||
|
|
||||||
if extended == 1 {
|
|
||||||
ch.extPending.write(data)
|
|
||||||
} else if extended > 0 {
|
|
||||||
// discard other extended data.
|
|
||||||
} else {
|
|
||||||
ch.pending.write(data)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *channel) adjustWindow(n uint32) error {
|
|
||||||
c.windowMu.Lock()
|
|
||||||
// Since myWindow is managed on our side, and can never exceed
|
|
||||||
// the initial window setting, we don't worry about overflow.
|
|
||||||
c.myWindow += uint32(n)
|
|
||||||
c.windowMu.Unlock()
|
|
||||||
return c.sendMessage(windowAdjustMsg{
|
|
||||||
AdditionalBytes: uint32(n),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *channel) ReadExtended(data []byte, extended uint32) (n int, err error) {
|
|
||||||
switch extended {
|
|
||||||
case 1:
|
|
||||||
n, err = c.extPending.Read(data)
|
|
||||||
case 0:
|
|
||||||
n, err = c.pending.Read(data)
|
|
||||||
default:
|
|
||||||
return 0, fmt.Errorf("ssh: extended code %d unimplemented", extended)
|
|
||||||
}
|
|
||||||
|
|
||||||
if n > 0 {
|
|
||||||
err = c.adjustWindow(uint32(n))
|
|
||||||
// sendWindowAdjust can return io.EOF if the remote
|
|
||||||
// peer has closed the connection, however we want to
|
|
||||||
// defer forwarding io.EOF to the caller of Read until
|
|
||||||
// the buffer has been drained.
|
|
||||||
if n > 0 && err == io.EOF {
|
|
||||||
err = nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return n, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *channel) close() {
|
|
||||||
c.pending.eof()
|
|
||||||
c.extPending.eof()
|
|
||||||
close(c.msg)
|
|
||||||
close(c.incomingRequests)
|
|
||||||
c.writeMu.Lock()
|
|
||||||
// This is not necessary for a normal channel teardown, but if
|
|
||||||
// there was another error, it is.
|
|
||||||
c.sentClose = true
|
|
||||||
c.writeMu.Unlock()
|
|
||||||
// Unblock writers.
|
|
||||||
c.remoteWin.close()
|
|
||||||
}
|
|
||||||
|
|
||||||
// responseMessageReceived is called when a success or failure message is
|
|
||||||
// received on a channel to check that such a message is reasonable for the
|
|
||||||
// given channel.
|
|
||||||
func (ch *channel) responseMessageReceived() error {
|
|
||||||
if ch.direction == channelInbound {
|
|
||||||
return errors.New("ssh: channel response message received on inbound channel")
|
|
||||||
}
|
|
||||||
if ch.decided {
|
|
||||||
return errors.New("ssh: duplicate response received for channel")
|
|
||||||
}
|
|
||||||
ch.decided = true
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ch *channel) handlePacket(packet []byte) error {
|
|
||||||
switch packet[0] {
|
|
||||||
case msgChannelData, msgChannelExtendedData:
|
|
||||||
return ch.handleData(packet)
|
|
||||||
case msgChannelClose:
|
|
||||||
ch.sendMessage(channelCloseMsg{PeersID: ch.remoteId})
|
|
||||||
ch.mux.chanList.remove(ch.localId)
|
|
||||||
ch.close()
|
|
||||||
return nil
|
|
||||||
case msgChannelEOF:
|
|
||||||
// RFC 4254 is mute on how EOF affects dataExt messages but
|
|
||||||
// it is logical to signal EOF at the same time.
|
|
||||||
ch.extPending.eof()
|
|
||||||
ch.pending.eof()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
decoded, err := decode(packet)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
switch msg := decoded.(type) {
|
|
||||||
case *channelOpenFailureMsg:
|
|
||||||
if err := ch.responseMessageReceived(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
ch.mux.chanList.remove(msg.PeersID)
|
|
||||||
ch.msg <- msg
|
|
||||||
case *channelOpenConfirmMsg:
|
|
||||||
if err := ch.responseMessageReceived(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if msg.MaxPacketSize < minPacketLength || msg.MaxPacketSize > 1<<31 {
|
|
||||||
return fmt.Errorf("ssh: invalid MaxPacketSize %d from peer", msg.MaxPacketSize)
|
|
||||||
}
|
|
||||||
ch.remoteId = msg.MyID
|
|
||||||
ch.maxRemotePayload = msg.MaxPacketSize
|
|
||||||
ch.remoteWin.add(msg.MyWindow)
|
|
||||||
ch.msg <- msg
|
|
||||||
case *windowAdjustMsg:
|
|
||||||
if !ch.remoteWin.add(msg.AdditionalBytes) {
|
|
||||||
return fmt.Errorf("ssh: invalid window update for %d bytes", msg.AdditionalBytes)
|
|
||||||
}
|
|
||||||
case *channelRequestMsg:
|
|
||||||
req := Request{
|
|
||||||
Type: msg.Request,
|
|
||||||
WantReply: msg.WantReply,
|
|
||||||
Payload: msg.RequestSpecificData,
|
|
||||||
ch: ch,
|
|
||||||
}
|
|
||||||
|
|
||||||
ch.incomingRequests <- &req
|
|
||||||
default:
|
|
||||||
ch.msg <- msg
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *mux) newChannel(chanType string, direction channelDirection, extraData []byte) *channel {
|
|
||||||
ch := &channel{
|
|
||||||
remoteWin: window{Cond: newCond()},
|
|
||||||
myWindow: channelWindowSize,
|
|
||||||
pending: newBuffer(),
|
|
||||||
extPending: newBuffer(),
|
|
||||||
direction: direction,
|
|
||||||
incomingRequests: make(chan *Request, chanSize),
|
|
||||||
msg: make(chan interface{}, chanSize),
|
|
||||||
chanType: chanType,
|
|
||||||
extraData: extraData,
|
|
||||||
mux: m,
|
|
||||||
packetPool: make(map[uint32][]byte),
|
|
||||||
}
|
|
||||||
ch.localId = m.chanList.add(ch)
|
|
||||||
return ch
|
|
||||||
}
|
|
||||||
|
|
||||||
var errUndecided = errors.New("ssh: must Accept or Reject channel")
|
|
||||||
var errDecidedAlready = errors.New("ssh: can call Accept or Reject only once")
|
|
||||||
|
|
||||||
type extChannel struct {
|
|
||||||
code uint32
|
|
||||||
ch *channel
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *extChannel) Write(data []byte) (n int, err error) {
|
|
||||||
return e.ch.WriteExtended(data, e.code)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *extChannel) Read(data []byte) (n int, err error) {
|
|
||||||
return e.ch.ReadExtended(data, e.code)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ch *channel) Accept() (Channel, <-chan *Request, error) {
|
|
||||||
if ch.decided {
|
|
||||||
return nil, nil, errDecidedAlready
|
|
||||||
}
|
|
||||||
ch.maxIncomingPayload = channelMaxPacket
|
|
||||||
confirm := channelOpenConfirmMsg{
|
|
||||||
PeersID: ch.remoteId,
|
|
||||||
MyID: ch.localId,
|
|
||||||
MyWindow: ch.myWindow,
|
|
||||||
MaxPacketSize: ch.maxIncomingPayload,
|
|
||||||
}
|
|
||||||
ch.decided = true
|
|
||||||
if err := ch.sendMessage(confirm); err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return ch, ch.incomingRequests, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ch *channel) Reject(reason RejectionReason, message string) error {
|
|
||||||
if ch.decided {
|
|
||||||
return errDecidedAlready
|
|
||||||
}
|
|
||||||
reject := channelOpenFailureMsg{
|
|
||||||
PeersID: ch.remoteId,
|
|
||||||
Reason: reason,
|
|
||||||
Message: message,
|
|
||||||
Language: "en",
|
|
||||||
}
|
|
||||||
ch.decided = true
|
|
||||||
return ch.sendMessage(reject)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ch *channel) Read(data []byte) (int, error) {
|
|
||||||
if !ch.decided {
|
|
||||||
return 0, errUndecided
|
|
||||||
}
|
|
||||||
return ch.ReadExtended(data, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ch *channel) Write(data []byte) (int, error) {
|
|
||||||
if !ch.decided {
|
|
||||||
return 0, errUndecided
|
|
||||||
}
|
|
||||||
return ch.WriteExtended(data, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ch *channel) CloseWrite() error {
|
|
||||||
if !ch.decided {
|
|
||||||
return errUndecided
|
|
||||||
}
|
|
||||||
ch.sentEOF = true
|
|
||||||
return ch.sendMessage(channelEOFMsg{
|
|
||||||
PeersID: ch.remoteId})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ch *channel) Close() error {
|
|
||||||
if !ch.decided {
|
|
||||||
return errUndecided
|
|
||||||
}
|
|
||||||
|
|
||||||
return ch.sendMessage(channelCloseMsg{
|
|
||||||
PeersID: ch.remoteId})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extended returns an io.ReadWriter that sends and receives data on the given,
|
|
||||||
// SSH extended stream. Such streams are used, for example, for stderr.
|
|
||||||
func (ch *channel) Extended(code uint32) io.ReadWriter {
|
|
||||||
if !ch.decided {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return &extChannel{code, ch}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ch *channel) Stderr() io.ReadWriter {
|
|
||||||
return ch.Extended(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ch *channel) SendRequest(name string, wantReply bool, payload []byte) (bool, error) {
|
|
||||||
if !ch.decided {
|
|
||||||
return false, errUndecided
|
|
||||||
}
|
|
||||||
|
|
||||||
if wantReply {
|
|
||||||
ch.sentRequestMu.Lock()
|
|
||||||
defer ch.sentRequestMu.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
msg := channelRequestMsg{
|
|
||||||
PeersID: ch.remoteId,
|
|
||||||
Request: name,
|
|
||||||
WantReply: wantReply,
|
|
||||||
RequestSpecificData: payload,
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := ch.sendMessage(msg); err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if wantReply {
|
|
||||||
m, ok := (<-ch.msg)
|
|
||||||
if !ok {
|
|
||||||
return false, io.EOF
|
|
||||||
}
|
|
||||||
switch m.(type) {
|
|
||||||
case *channelRequestFailureMsg:
|
|
||||||
return false, nil
|
|
||||||
case *channelRequestSuccessMsg:
|
|
||||||
return true, nil
|
|
||||||
default:
|
|
||||||
return false, fmt.Errorf("ssh: unexpected response to channel request: %#v", m)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ackRequest either sends an ack or nack to the channel request.
|
|
||||||
func (ch *channel) ackRequest(ok bool) error {
|
|
||||||
if !ch.decided {
|
|
||||||
return errUndecided
|
|
||||||
}
|
|
||||||
|
|
||||||
var msg interface{}
|
|
||||||
if !ok {
|
|
||||||
msg = channelRequestFailureMsg{
|
|
||||||
PeersID: ch.remoteId,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
msg = channelRequestSuccessMsg{
|
|
||||||
PeersID: ch.remoteId,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ch.sendMessage(msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ch *channel) ChannelType() string {
|
|
||||||
return ch.chanType
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ch *channel) ExtraData() []byte {
|
|
||||||
return ch.extraData
|
|
||||||
}
|
|
770
vendor/golang.org/x/crypto/ssh/cipher.go
generated
vendored
770
vendor/golang.org/x/crypto/ssh/cipher.go
generated
vendored
@ -1,770 +0,0 @@
|
|||||||
// 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 ssh
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/aes"
|
|
||||||
"crypto/cipher"
|
|
||||||
"crypto/des"
|
|
||||||
"crypto/rc4"
|
|
||||||
"crypto/subtle"
|
|
||||||
"encoding/binary"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"hash"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"math/bits"
|
|
||||||
|
|
||||||
"golang.org/x/crypto/internal/chacha20"
|
|
||||||
"golang.org/x/crypto/poly1305"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
packetSizeMultiple = 16 // TODO(huin) this should be determined by the cipher.
|
|
||||||
|
|
||||||
// RFC 4253 section 6.1 defines a minimum packet size of 32768 that implementations
|
|
||||||
// MUST be able to process (plus a few more kilobytes for padding and mac). The RFC
|
|
||||||
// indicates implementations SHOULD be able to handle larger packet sizes, but then
|
|
||||||
// waffles on about reasonable limits.
|
|
||||||
//
|
|
||||||
// OpenSSH caps their maxPacket at 256kB so we choose to do
|
|
||||||
// the same. maxPacket is also used to ensure that uint32
|
|
||||||
// length fields do not overflow, so it should remain well
|
|
||||||
// below 4G.
|
|
||||||
maxPacket = 256 * 1024
|
|
||||||
)
|
|
||||||
|
|
||||||
// noneCipher implements cipher.Stream and provides no encryption. It is used
|
|
||||||
// by the transport before the first key-exchange.
|
|
||||||
type noneCipher struct{}
|
|
||||||
|
|
||||||
func (c noneCipher) XORKeyStream(dst, src []byte) {
|
|
||||||
copy(dst, src)
|
|
||||||
}
|
|
||||||
|
|
||||||
func newAESCTR(key, iv []byte) (cipher.Stream, error) {
|
|
||||||
c, err := aes.NewCipher(key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return cipher.NewCTR(c, iv), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func newRC4(key, iv []byte) (cipher.Stream, error) {
|
|
||||||
return rc4.NewCipher(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
type cipherMode struct {
|
|
||||||
keySize int
|
|
||||||
ivSize int
|
|
||||||
create func(key, iv []byte, macKey []byte, algs directionAlgorithms) (packetCipher, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
func streamCipherMode(skip int, createFunc func(key, iv []byte) (cipher.Stream, error)) func(key, iv []byte, macKey []byte, algs directionAlgorithms) (packetCipher, error) {
|
|
||||||
return func(key, iv, macKey []byte, algs directionAlgorithms) (packetCipher, error) {
|
|
||||||
stream, err := createFunc(key, iv)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var streamDump []byte
|
|
||||||
if skip > 0 {
|
|
||||||
streamDump = make([]byte, 512)
|
|
||||||
}
|
|
||||||
|
|
||||||
for remainingToDump := skip; remainingToDump > 0; {
|
|
||||||
dumpThisTime := remainingToDump
|
|
||||||
if dumpThisTime > len(streamDump) {
|
|
||||||
dumpThisTime = len(streamDump)
|
|
||||||
}
|
|
||||||
stream.XORKeyStream(streamDump[:dumpThisTime], streamDump[:dumpThisTime])
|
|
||||||
remainingToDump -= dumpThisTime
|
|
||||||
}
|
|
||||||
|
|
||||||
mac := macModes[algs.MAC].new(macKey)
|
|
||||||
return &streamPacketCipher{
|
|
||||||
mac: mac,
|
|
||||||
etm: macModes[algs.MAC].etm,
|
|
||||||
macResult: make([]byte, mac.Size()),
|
|
||||||
cipher: stream,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// cipherModes documents properties of supported ciphers. Ciphers not included
|
|
||||||
// are not supported and will not be negotiated, even if explicitly requested in
|
|
||||||
// ClientConfig.Crypto.Ciphers.
|
|
||||||
var cipherModes = map[string]*cipherMode{
|
|
||||||
// Ciphers from RFC4344, which introduced many CTR-based ciphers. Algorithms
|
|
||||||
// are defined in the order specified in the RFC.
|
|
||||||
"aes128-ctr": {16, aes.BlockSize, streamCipherMode(0, newAESCTR)},
|
|
||||||
"aes192-ctr": {24, aes.BlockSize, streamCipherMode(0, newAESCTR)},
|
|
||||||
"aes256-ctr": {32, aes.BlockSize, streamCipherMode(0, newAESCTR)},
|
|
||||||
|
|
||||||
// Ciphers from RFC4345, which introduces security-improved arcfour ciphers.
|
|
||||||
// They are defined in the order specified in the RFC.
|
|
||||||
"arcfour128": {16, 0, streamCipherMode(1536, newRC4)},
|
|
||||||
"arcfour256": {32, 0, streamCipherMode(1536, newRC4)},
|
|
||||||
|
|
||||||
// Cipher defined in RFC 4253, which describes SSH Transport Layer Protocol.
|
|
||||||
// Note that this cipher is not safe, as stated in RFC 4253: "Arcfour (and
|
|
||||||
// RC4) has problems with weak keys, and should be used with caution."
|
|
||||||
// RFC4345 introduces improved versions of Arcfour.
|
|
||||||
"arcfour": {16, 0, streamCipherMode(0, newRC4)},
|
|
||||||
|
|
||||||
// AEAD ciphers
|
|
||||||
gcmCipherID: {16, 12, newGCMCipher},
|
|
||||||
chacha20Poly1305ID: {64, 0, newChaCha20Cipher},
|
|
||||||
|
|
||||||
// CBC mode is insecure and so is not included in the default config.
|
|
||||||
// (See http://www.isg.rhul.ac.uk/~kp/SandPfinal.pdf). If absolutely
|
|
||||||
// needed, it's possible to specify a custom Config to enable it.
|
|
||||||
// You should expect that an active attacker can recover plaintext if
|
|
||||||
// you do.
|
|
||||||
aes128cbcID: {16, aes.BlockSize, newAESCBCCipher},
|
|
||||||
|
|
||||||
// 3des-cbc is insecure and is not included in the default
|
|
||||||
// config.
|
|
||||||
tripledescbcID: {24, des.BlockSize, newTripleDESCBCCipher},
|
|
||||||
}
|
|
||||||
|
|
||||||
// prefixLen is the length of the packet prefix that contains the packet length
|
|
||||||
// and number of padding bytes.
|
|
||||||
const prefixLen = 5
|
|
||||||
|
|
||||||
// streamPacketCipher is a packetCipher using a stream cipher.
|
|
||||||
type streamPacketCipher struct {
|
|
||||||
mac hash.Hash
|
|
||||||
cipher cipher.Stream
|
|
||||||
etm bool
|
|
||||||
|
|
||||||
// The following members are to avoid per-packet allocations.
|
|
||||||
prefix [prefixLen]byte
|
|
||||||
seqNumBytes [4]byte
|
|
||||||
padding [2 * packetSizeMultiple]byte
|
|
||||||
packetData []byte
|
|
||||||
macResult []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
// readCipherPacket reads and decrypt a single packet from the reader argument.
|
|
||||||
func (s *streamPacketCipher) readCipherPacket(seqNum uint32, r io.Reader) ([]byte, error) {
|
|
||||||
if _, err := io.ReadFull(r, s.prefix[:]); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var encryptedPaddingLength [1]byte
|
|
||||||
if s.mac != nil && s.etm {
|
|
||||||
copy(encryptedPaddingLength[:], s.prefix[4:5])
|
|
||||||
s.cipher.XORKeyStream(s.prefix[4:5], s.prefix[4:5])
|
|
||||||
} else {
|
|
||||||
s.cipher.XORKeyStream(s.prefix[:], s.prefix[:])
|
|
||||||
}
|
|
||||||
|
|
||||||
length := binary.BigEndian.Uint32(s.prefix[0:4])
|
|
||||||
paddingLength := uint32(s.prefix[4])
|
|
||||||
|
|
||||||
var macSize uint32
|
|
||||||
if s.mac != nil {
|
|
||||||
s.mac.Reset()
|
|
||||||
binary.BigEndian.PutUint32(s.seqNumBytes[:], seqNum)
|
|
||||||
s.mac.Write(s.seqNumBytes[:])
|
|
||||||
if s.etm {
|
|
||||||
s.mac.Write(s.prefix[:4])
|
|
||||||
s.mac.Write(encryptedPaddingLength[:])
|
|
||||||
} else {
|
|
||||||
s.mac.Write(s.prefix[:])
|
|
||||||
}
|
|
||||||
macSize = uint32(s.mac.Size())
|
|
||||||
}
|
|
||||||
|
|
||||||
if length <= paddingLength+1 {
|
|
||||||
return nil, errors.New("ssh: invalid packet length, packet too small")
|
|
||||||
}
|
|
||||||
|
|
||||||
if length > maxPacket {
|
|
||||||
return nil, errors.New("ssh: invalid packet length, packet too large")
|
|
||||||
}
|
|
||||||
|
|
||||||
// the maxPacket check above ensures that length-1+macSize
|
|
||||||
// does not overflow.
|
|
||||||
if uint32(cap(s.packetData)) < length-1+macSize {
|
|
||||||
s.packetData = make([]byte, length-1+macSize)
|
|
||||||
} else {
|
|
||||||
s.packetData = s.packetData[:length-1+macSize]
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := io.ReadFull(r, s.packetData); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
mac := s.packetData[length-1:]
|
|
||||||
data := s.packetData[:length-1]
|
|
||||||
|
|
||||||
if s.mac != nil && s.etm {
|
|
||||||
s.mac.Write(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
s.cipher.XORKeyStream(data, data)
|
|
||||||
|
|
||||||
if s.mac != nil {
|
|
||||||
if !s.etm {
|
|
||||||
s.mac.Write(data)
|
|
||||||
}
|
|
||||||
s.macResult = s.mac.Sum(s.macResult[:0])
|
|
||||||
if subtle.ConstantTimeCompare(s.macResult, mac) != 1 {
|
|
||||||
return nil, errors.New("ssh: MAC failure")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return s.packetData[:length-paddingLength-1], nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// writeCipherPacket encrypts and sends a packet of data to the writer argument
|
|
||||||
func (s *streamPacketCipher) writeCipherPacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error {
|
|
||||||
if len(packet) > maxPacket {
|
|
||||||
return errors.New("ssh: packet too large")
|
|
||||||
}
|
|
||||||
|
|
||||||
aadlen := 0
|
|
||||||
if s.mac != nil && s.etm {
|
|
||||||
// packet length is not encrypted for EtM modes
|
|
||||||
aadlen = 4
|
|
||||||
}
|
|
||||||
|
|
||||||
paddingLength := packetSizeMultiple - (prefixLen+len(packet)-aadlen)%packetSizeMultiple
|
|
||||||
if paddingLength < 4 {
|
|
||||||
paddingLength += packetSizeMultiple
|
|
||||||
}
|
|
||||||
|
|
||||||
length := len(packet) + 1 + paddingLength
|
|
||||||
binary.BigEndian.PutUint32(s.prefix[:], uint32(length))
|
|
||||||
s.prefix[4] = byte(paddingLength)
|
|
||||||
padding := s.padding[:paddingLength]
|
|
||||||
if _, err := io.ReadFull(rand, padding); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if s.mac != nil {
|
|
||||||
s.mac.Reset()
|
|
||||||
binary.BigEndian.PutUint32(s.seqNumBytes[:], seqNum)
|
|
||||||
s.mac.Write(s.seqNumBytes[:])
|
|
||||||
|
|
||||||
if s.etm {
|
|
||||||
// For EtM algorithms, the packet length must stay unencrypted,
|
|
||||||
// but the following data (padding length) must be encrypted
|
|
||||||
s.cipher.XORKeyStream(s.prefix[4:5], s.prefix[4:5])
|
|
||||||
}
|
|
||||||
|
|
||||||
s.mac.Write(s.prefix[:])
|
|
||||||
|
|
||||||
if !s.etm {
|
|
||||||
// For non-EtM algorithms, the algorithm is applied on unencrypted data
|
|
||||||
s.mac.Write(packet)
|
|
||||||
s.mac.Write(padding)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !(s.mac != nil && s.etm) {
|
|
||||||
// For EtM algorithms, the padding length has already been encrypted
|
|
||||||
// and the packet length must remain unencrypted
|
|
||||||
s.cipher.XORKeyStream(s.prefix[:], s.prefix[:])
|
|
||||||
}
|
|
||||||
|
|
||||||
s.cipher.XORKeyStream(packet, packet)
|
|
||||||
s.cipher.XORKeyStream(padding, padding)
|
|
||||||
|
|
||||||
if s.mac != nil && s.etm {
|
|
||||||
// For EtM algorithms, packet and padding must be encrypted
|
|
||||||
s.mac.Write(packet)
|
|
||||||
s.mac.Write(padding)
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := w.Write(s.prefix[:]); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if _, err := w.Write(packet); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if _, err := w.Write(padding); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if s.mac != nil {
|
|
||||||
s.macResult = s.mac.Sum(s.macResult[:0])
|
|
||||||
if _, err := w.Write(s.macResult); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type gcmCipher struct {
|
|
||||||
aead cipher.AEAD
|
|
||||||
prefix [4]byte
|
|
||||||
iv []byte
|
|
||||||
buf []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func newGCMCipher(key, iv, unusedMacKey []byte, unusedAlgs directionAlgorithms) (packetCipher, error) {
|
|
||||||
c, err := aes.NewCipher(key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
aead, err := cipher.NewGCM(c)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &gcmCipher{
|
|
||||||
aead: aead,
|
|
||||||
iv: iv,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
const gcmTagSize = 16
|
|
||||||
|
|
||||||
func (c *gcmCipher) writeCipherPacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error {
|
|
||||||
// Pad out to multiple of 16 bytes. This is different from the
|
|
||||||
// stream cipher because that encrypts the length too.
|
|
||||||
padding := byte(packetSizeMultiple - (1+len(packet))%packetSizeMultiple)
|
|
||||||
if padding < 4 {
|
|
||||||
padding += packetSizeMultiple
|
|
||||||
}
|
|
||||||
|
|
||||||
length := uint32(len(packet) + int(padding) + 1)
|
|
||||||
binary.BigEndian.PutUint32(c.prefix[:], length)
|
|
||||||
if _, err := w.Write(c.prefix[:]); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if cap(c.buf) < int(length) {
|
|
||||||
c.buf = make([]byte, length)
|
|
||||||
} else {
|
|
||||||
c.buf = c.buf[:length]
|
|
||||||
}
|
|
||||||
|
|
||||||
c.buf[0] = padding
|
|
||||||
copy(c.buf[1:], packet)
|
|
||||||
if _, err := io.ReadFull(rand, c.buf[1+len(packet):]); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
c.buf = c.aead.Seal(c.buf[:0], c.iv, c.buf, c.prefix[:])
|
|
||||||
if _, err := w.Write(c.buf); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
c.incIV()
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *gcmCipher) incIV() {
|
|
||||||
for i := 4 + 7; i >= 4; i-- {
|
|
||||||
c.iv[i]++
|
|
||||||
if c.iv[i] != 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *gcmCipher) readCipherPacket(seqNum uint32, r io.Reader) ([]byte, error) {
|
|
||||||
if _, err := io.ReadFull(r, c.prefix[:]); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
length := binary.BigEndian.Uint32(c.prefix[:])
|
|
||||||
if length > maxPacket {
|
|
||||||
return nil, errors.New("ssh: max packet length exceeded")
|
|
||||||
}
|
|
||||||
|
|
||||||
if cap(c.buf) < int(length+gcmTagSize) {
|
|
||||||
c.buf = make([]byte, length+gcmTagSize)
|
|
||||||
} else {
|
|
||||||
c.buf = c.buf[:length+gcmTagSize]
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := io.ReadFull(r, c.buf); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
plain, err := c.aead.Open(c.buf[:0], c.iv, c.buf, c.prefix[:])
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
c.incIV()
|
|
||||||
|
|
||||||
padding := plain[0]
|
|
||||||
if padding < 4 {
|
|
||||||
// padding is a byte, so it automatically satisfies
|
|
||||||
// the maximum size, which is 255.
|
|
||||||
return nil, fmt.Errorf("ssh: illegal padding %d", padding)
|
|
||||||
}
|
|
||||||
|
|
||||||
if int(padding+1) >= len(plain) {
|
|
||||||
return nil, fmt.Errorf("ssh: padding %d too large", padding)
|
|
||||||
}
|
|
||||||
plain = plain[1 : length-uint32(padding)]
|
|
||||||
return plain, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// cbcCipher implements aes128-cbc cipher defined in RFC 4253 section 6.1
|
|
||||||
type cbcCipher struct {
|
|
||||||
mac hash.Hash
|
|
||||||
macSize uint32
|
|
||||||
decrypter cipher.BlockMode
|
|
||||||
encrypter cipher.BlockMode
|
|
||||||
|
|
||||||
// The following members are to avoid per-packet allocations.
|
|
||||||
seqNumBytes [4]byte
|
|
||||||
packetData []byte
|
|
||||||
macResult []byte
|
|
||||||
|
|
||||||
// Amount of data we should still read to hide which
|
|
||||||
// verification error triggered.
|
|
||||||
oracleCamouflage uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
func newCBCCipher(c cipher.Block, key, iv, macKey []byte, algs directionAlgorithms) (packetCipher, error) {
|
|
||||||
cbc := &cbcCipher{
|
|
||||||
mac: macModes[algs.MAC].new(macKey),
|
|
||||||
decrypter: cipher.NewCBCDecrypter(c, iv),
|
|
||||||
encrypter: cipher.NewCBCEncrypter(c, iv),
|
|
||||||
packetData: make([]byte, 1024),
|
|
||||||
}
|
|
||||||
if cbc.mac != nil {
|
|
||||||
cbc.macSize = uint32(cbc.mac.Size())
|
|
||||||
}
|
|
||||||
|
|
||||||
return cbc, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func newAESCBCCipher(key, iv, macKey []byte, algs directionAlgorithms) (packetCipher, error) {
|
|
||||||
c, err := aes.NewCipher(key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
cbc, err := newCBCCipher(c, key, iv, macKey, algs)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return cbc, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func newTripleDESCBCCipher(key, iv, macKey []byte, algs directionAlgorithms) (packetCipher, error) {
|
|
||||||
c, err := des.NewTripleDESCipher(key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
cbc, err := newCBCCipher(c, key, iv, macKey, algs)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return cbc, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func maxUInt32(a, b int) uint32 {
|
|
||||||
if a > b {
|
|
||||||
return uint32(a)
|
|
||||||
}
|
|
||||||
return uint32(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
cbcMinPacketSizeMultiple = 8
|
|
||||||
cbcMinPacketSize = 16
|
|
||||||
cbcMinPaddingSize = 4
|
|
||||||
)
|
|
||||||
|
|
||||||
// cbcError represents a verification error that may leak information.
|
|
||||||
type cbcError string
|
|
||||||
|
|
||||||
func (e cbcError) Error() string { return string(e) }
|
|
||||||
|
|
||||||
func (c *cbcCipher) readCipherPacket(seqNum uint32, r io.Reader) ([]byte, error) {
|
|
||||||
p, err := c.readCipherPacketLeaky(seqNum, r)
|
|
||||||
if err != nil {
|
|
||||||
if _, ok := err.(cbcError); ok {
|
|
||||||
// Verification error: read a fixed amount of
|
|
||||||
// data, to make distinguishing between
|
|
||||||
// failing MAC and failing length check more
|
|
||||||
// difficult.
|
|
||||||
io.CopyN(ioutil.Discard, r, int64(c.oracleCamouflage))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return p, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *cbcCipher) readCipherPacketLeaky(seqNum uint32, r io.Reader) ([]byte, error) {
|
|
||||||
blockSize := c.decrypter.BlockSize()
|
|
||||||
|
|
||||||
// Read the header, which will include some of the subsequent data in the
|
|
||||||
// case of block ciphers - this is copied back to the payload later.
|
|
||||||
// How many bytes of payload/padding will be read with this first read.
|
|
||||||
firstBlockLength := uint32((prefixLen + blockSize - 1) / blockSize * blockSize)
|
|
||||||
firstBlock := c.packetData[:firstBlockLength]
|
|
||||||
if _, err := io.ReadFull(r, firstBlock); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
c.oracleCamouflage = maxPacket + 4 + c.macSize - firstBlockLength
|
|
||||||
|
|
||||||
c.decrypter.CryptBlocks(firstBlock, firstBlock)
|
|
||||||
length := binary.BigEndian.Uint32(firstBlock[:4])
|
|
||||||
if length > maxPacket {
|
|
||||||
return nil, cbcError("ssh: packet too large")
|
|
||||||
}
|
|
||||||
if length+4 < maxUInt32(cbcMinPacketSize, blockSize) {
|
|
||||||
// The minimum size of a packet is 16 (or the cipher block size, whichever
|
|
||||||
// is larger) bytes.
|
|
||||||
return nil, cbcError("ssh: packet too small")
|
|
||||||
}
|
|
||||||
// The length of the packet (including the length field but not the MAC) must
|
|
||||||
// be a multiple of the block size or 8, whichever is larger.
|
|
||||||
if (length+4)%maxUInt32(cbcMinPacketSizeMultiple, blockSize) != 0 {
|
|
||||||
return nil, cbcError("ssh: invalid packet length multiple")
|
|
||||||
}
|
|
||||||
|
|
||||||
paddingLength := uint32(firstBlock[4])
|
|
||||||
if paddingLength < cbcMinPaddingSize || length <= paddingLength+1 {
|
|
||||||
return nil, cbcError("ssh: invalid packet length")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Positions within the c.packetData buffer:
|
|
||||||
macStart := 4 + length
|
|
||||||
paddingStart := macStart - paddingLength
|
|
||||||
|
|
||||||
// Entire packet size, starting before length, ending at end of mac.
|
|
||||||
entirePacketSize := macStart + c.macSize
|
|
||||||
|
|
||||||
// Ensure c.packetData is large enough for the entire packet data.
|
|
||||||
if uint32(cap(c.packetData)) < entirePacketSize {
|
|
||||||
// Still need to upsize and copy, but this should be rare at runtime, only
|
|
||||||
// on upsizing the packetData buffer.
|
|
||||||
c.packetData = make([]byte, entirePacketSize)
|
|
||||||
copy(c.packetData, firstBlock)
|
|
||||||
} else {
|
|
||||||
c.packetData = c.packetData[:entirePacketSize]
|
|
||||||
}
|
|
||||||
|
|
||||||
n, err := io.ReadFull(r, c.packetData[firstBlockLength:])
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
c.oracleCamouflage -= uint32(n)
|
|
||||||
|
|
||||||
remainingCrypted := c.packetData[firstBlockLength:macStart]
|
|
||||||
c.decrypter.CryptBlocks(remainingCrypted, remainingCrypted)
|
|
||||||
|
|
||||||
mac := c.packetData[macStart:]
|
|
||||||
if c.mac != nil {
|
|
||||||
c.mac.Reset()
|
|
||||||
binary.BigEndian.PutUint32(c.seqNumBytes[:], seqNum)
|
|
||||||
c.mac.Write(c.seqNumBytes[:])
|
|
||||||
c.mac.Write(c.packetData[:macStart])
|
|
||||||
c.macResult = c.mac.Sum(c.macResult[:0])
|
|
||||||
if subtle.ConstantTimeCompare(c.macResult, mac) != 1 {
|
|
||||||
return nil, cbcError("ssh: MAC failure")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.packetData[prefixLen:paddingStart], nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *cbcCipher) writeCipherPacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error {
|
|
||||||
effectiveBlockSize := maxUInt32(cbcMinPacketSizeMultiple, c.encrypter.BlockSize())
|
|
||||||
|
|
||||||
// Length of encrypted portion of the packet (header, payload, padding).
|
|
||||||
// Enforce minimum padding and packet size.
|
|
||||||
encLength := maxUInt32(prefixLen+len(packet)+cbcMinPaddingSize, cbcMinPaddingSize)
|
|
||||||
// Enforce block size.
|
|
||||||
encLength = (encLength + effectiveBlockSize - 1) / effectiveBlockSize * effectiveBlockSize
|
|
||||||
|
|
||||||
length := encLength - 4
|
|
||||||
paddingLength := int(length) - (1 + len(packet))
|
|
||||||
|
|
||||||
// Overall buffer contains: header, payload, padding, mac.
|
|
||||||
// Space for the MAC is reserved in the capacity but not the slice length.
|
|
||||||
bufferSize := encLength + c.macSize
|
|
||||||
if uint32(cap(c.packetData)) < bufferSize {
|
|
||||||
c.packetData = make([]byte, encLength, bufferSize)
|
|
||||||
} else {
|
|
||||||
c.packetData = c.packetData[:encLength]
|
|
||||||
}
|
|
||||||
|
|
||||||
p := c.packetData
|
|
||||||
|
|
||||||
// Packet header.
|
|
||||||
binary.BigEndian.PutUint32(p, length)
|
|
||||||
p = p[4:]
|
|
||||||
p[0] = byte(paddingLength)
|
|
||||||
|
|
||||||
// Payload.
|
|
||||||
p = p[1:]
|
|
||||||
copy(p, packet)
|
|
||||||
|
|
||||||
// Padding.
|
|
||||||
p = p[len(packet):]
|
|
||||||
if _, err := io.ReadFull(rand, p); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.mac != nil {
|
|
||||||
c.mac.Reset()
|
|
||||||
binary.BigEndian.PutUint32(c.seqNumBytes[:], seqNum)
|
|
||||||
c.mac.Write(c.seqNumBytes[:])
|
|
||||||
c.mac.Write(c.packetData)
|
|
||||||
// The MAC is now appended into the capacity reserved for it earlier.
|
|
||||||
c.packetData = c.mac.Sum(c.packetData)
|
|
||||||
}
|
|
||||||
|
|
||||||
c.encrypter.CryptBlocks(c.packetData[:encLength], c.packetData[:encLength])
|
|
||||||
|
|
||||||
if _, err := w.Write(c.packetData); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
const chacha20Poly1305ID = "chacha20-poly1305@openssh.com"
|
|
||||||
|
|
||||||
// chacha20Poly1305Cipher implements the chacha20-poly1305@openssh.com
|
|
||||||
// AEAD, which is described here:
|
|
||||||
//
|
|
||||||
// https://tools.ietf.org/html/draft-josefsson-ssh-chacha20-poly1305-openssh-00
|
|
||||||
//
|
|
||||||
// the methods here also implement padding, which RFC4253 Section 6
|
|
||||||
// also requires of stream ciphers.
|
|
||||||
type chacha20Poly1305Cipher struct {
|
|
||||||
lengthKey [8]uint32
|
|
||||||
contentKey [8]uint32
|
|
||||||
buf []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func newChaCha20Cipher(key, unusedIV, unusedMACKey []byte, unusedAlgs directionAlgorithms) (packetCipher, error) {
|
|
||||||
if len(key) != 64 {
|
|
||||||
panic(len(key))
|
|
||||||
}
|
|
||||||
|
|
||||||
c := &chacha20Poly1305Cipher{
|
|
||||||
buf: make([]byte, 256),
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := range c.contentKey {
|
|
||||||
c.contentKey[i] = binary.LittleEndian.Uint32(key[i*4 : (i+1)*4])
|
|
||||||
}
|
|
||||||
for i := range c.lengthKey {
|
|
||||||
c.lengthKey[i] = binary.LittleEndian.Uint32(key[(i+8)*4 : (i+9)*4])
|
|
||||||
}
|
|
||||||
return c, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *chacha20Poly1305Cipher) readCipherPacket(seqNum uint32, r io.Reader) ([]byte, error) {
|
|
||||||
nonce := [3]uint32{0, 0, bits.ReverseBytes32(seqNum)}
|
|
||||||
s := chacha20.New(c.contentKey, nonce)
|
|
||||||
var polyKey [32]byte
|
|
||||||
s.XORKeyStream(polyKey[:], polyKey[:])
|
|
||||||
s.Advance() // skip next 32 bytes
|
|
||||||
|
|
||||||
encryptedLength := c.buf[:4]
|
|
||||||
if _, err := io.ReadFull(r, encryptedLength); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var lenBytes [4]byte
|
|
||||||
chacha20.New(c.lengthKey, nonce).XORKeyStream(lenBytes[:], encryptedLength)
|
|
||||||
|
|
||||||
length := binary.BigEndian.Uint32(lenBytes[:])
|
|
||||||
if length > maxPacket {
|
|
||||||
return nil, errors.New("ssh: invalid packet length, packet too large")
|
|
||||||
}
|
|
||||||
|
|
||||||
contentEnd := 4 + length
|
|
||||||
packetEnd := contentEnd + poly1305.TagSize
|
|
||||||
if uint32(cap(c.buf)) < packetEnd {
|
|
||||||
c.buf = make([]byte, packetEnd)
|
|
||||||
copy(c.buf[:], encryptedLength)
|
|
||||||
} else {
|
|
||||||
c.buf = c.buf[:packetEnd]
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := io.ReadFull(r, c.buf[4:packetEnd]); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var mac [poly1305.TagSize]byte
|
|
||||||
copy(mac[:], c.buf[contentEnd:packetEnd])
|
|
||||||
if !poly1305.Verify(&mac, c.buf[:contentEnd], &polyKey) {
|
|
||||||
return nil, errors.New("ssh: MAC failure")
|
|
||||||
}
|
|
||||||
|
|
||||||
plain := c.buf[4:contentEnd]
|
|
||||||
s.XORKeyStream(plain, plain)
|
|
||||||
|
|
||||||
padding := plain[0]
|
|
||||||
if padding < 4 {
|
|
||||||
// padding is a byte, so it automatically satisfies
|
|
||||||
// the maximum size, which is 255.
|
|
||||||
return nil, fmt.Errorf("ssh: illegal padding %d", padding)
|
|
||||||
}
|
|
||||||
|
|
||||||
if int(padding)+1 >= len(plain) {
|
|
||||||
return nil, fmt.Errorf("ssh: padding %d too large", padding)
|
|
||||||
}
|
|
||||||
|
|
||||||
plain = plain[1 : len(plain)-int(padding)]
|
|
||||||
|
|
||||||
return plain, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *chacha20Poly1305Cipher) writeCipherPacket(seqNum uint32, w io.Writer, rand io.Reader, payload []byte) error {
|
|
||||||
nonce := [3]uint32{0, 0, bits.ReverseBytes32(seqNum)}
|
|
||||||
s := chacha20.New(c.contentKey, nonce)
|
|
||||||
var polyKey [32]byte
|
|
||||||
s.XORKeyStream(polyKey[:], polyKey[:])
|
|
||||||
s.Advance() // skip next 32 bytes
|
|
||||||
|
|
||||||
// There is no blocksize, so fall back to multiple of 8 byte
|
|
||||||
// padding, as described in RFC 4253, Sec 6.
|
|
||||||
const packetSizeMultiple = 8
|
|
||||||
|
|
||||||
padding := packetSizeMultiple - (1+len(payload))%packetSizeMultiple
|
|
||||||
if padding < 4 {
|
|
||||||
padding += packetSizeMultiple
|
|
||||||
}
|
|
||||||
|
|
||||||
// size (4 bytes), padding (1), payload, padding, tag.
|
|
||||||
totalLength := 4 + 1 + len(payload) + padding + poly1305.TagSize
|
|
||||||
if cap(c.buf) < totalLength {
|
|
||||||
c.buf = make([]byte, totalLength)
|
|
||||||
} else {
|
|
||||||
c.buf = c.buf[:totalLength]
|
|
||||||
}
|
|
||||||
|
|
||||||
binary.BigEndian.PutUint32(c.buf, uint32(1+len(payload)+padding))
|
|
||||||
chacha20.New(c.lengthKey, nonce).XORKeyStream(c.buf, c.buf[:4])
|
|
||||||
c.buf[4] = byte(padding)
|
|
||||||
copy(c.buf[5:], payload)
|
|
||||||
packetEnd := 5 + len(payload) + padding
|
|
||||||
if _, err := io.ReadFull(rand, c.buf[5+len(payload):packetEnd]); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
s.XORKeyStream(c.buf[4:], c.buf[4:packetEnd])
|
|
||||||
|
|
||||||
var mac [poly1305.TagSize]byte
|
|
||||||
poly1305.Sum(&mac, c.buf[:packetEnd], &polyKey)
|
|
||||||
|
|
||||||
copy(c.buf[packetEnd:], mac[:])
|
|
||||||
|
|
||||||
if _, err := w.Write(c.buf); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
278
vendor/golang.org/x/crypto/ssh/client.go
generated
vendored
278
vendor/golang.org/x/crypto/ssh/client.go
generated
vendored
@ -1,278 +0,0 @@
|
|||||||
// 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 ssh
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
"os"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Client implements a traditional SSH client that supports shells,
|
|
||||||
// subprocesses, TCP port/streamlocal forwarding and tunneled dialing.
|
|
||||||
type Client struct {
|
|
||||||
Conn
|
|
||||||
|
|
||||||
handleForwardsOnce sync.Once // guards calling (*Client).handleForwards
|
|
||||||
|
|
||||||
forwards forwardList // forwarded tcpip connections from the remote side
|
|
||||||
mu sync.Mutex
|
|
||||||
channelHandlers map[string]chan NewChannel
|
|
||||||
}
|
|
||||||
|
|
||||||
// HandleChannelOpen returns a channel on which NewChannel requests
|
|
||||||
// for the given type are sent. If the type already is being handled,
|
|
||||||
// nil is returned. The channel is closed when the connection is closed.
|
|
||||||
func (c *Client) HandleChannelOpen(channelType string) <-chan NewChannel {
|
|
||||||
c.mu.Lock()
|
|
||||||
defer c.mu.Unlock()
|
|
||||||
if c.channelHandlers == nil {
|
|
||||||
// The SSH channel has been closed.
|
|
||||||
c := make(chan NewChannel)
|
|
||||||
close(c)
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
ch := c.channelHandlers[channelType]
|
|
||||||
if ch != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
ch = make(chan NewChannel, chanSize)
|
|
||||||
c.channelHandlers[channelType] = ch
|
|
||||||
return ch
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewClient creates a Client on top of the given connection.
|
|
||||||
func NewClient(c Conn, chans <-chan NewChannel, reqs <-chan *Request) *Client {
|
|
||||||
conn := &Client{
|
|
||||||
Conn: c,
|
|
||||||
channelHandlers: make(map[string]chan NewChannel, 1),
|
|
||||||
}
|
|
||||||
|
|
||||||
go conn.handleGlobalRequests(reqs)
|
|
||||||
go conn.handleChannelOpens(chans)
|
|
||||||
go func() {
|
|
||||||
conn.Wait()
|
|
||||||
conn.forwards.closeAll()
|
|
||||||
}()
|
|
||||||
return conn
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewClientConn establishes an authenticated SSH connection using c
|
|
||||||
// as the underlying transport. The Request and NewChannel channels
|
|
||||||
// must be serviced or the connection will hang.
|
|
||||||
func NewClientConn(c net.Conn, addr string, config *ClientConfig) (Conn, <-chan NewChannel, <-chan *Request, error) {
|
|
||||||
fullConf := *config
|
|
||||||
fullConf.SetDefaults()
|
|
||||||
if fullConf.HostKeyCallback == nil {
|
|
||||||
c.Close()
|
|
||||||
return nil, nil, nil, errors.New("ssh: must specify HostKeyCallback")
|
|
||||||
}
|
|
||||||
|
|
||||||
conn := &connection{
|
|
||||||
sshConn: sshConn{conn: c},
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := conn.clientHandshake(addr, &fullConf); err != nil {
|
|
||||||
c.Close()
|
|
||||||
return nil, nil, nil, fmt.Errorf("ssh: handshake failed: %v", err)
|
|
||||||
}
|
|
||||||
conn.mux = newMux(conn.transport)
|
|
||||||
return conn, conn.mux.incomingChannels, conn.mux.incomingRequests, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// clientHandshake performs the client side key exchange. See RFC 4253 Section
|
|
||||||
// 7.
|
|
||||||
func (c *connection) clientHandshake(dialAddress string, config *ClientConfig) error {
|
|
||||||
if config.ClientVersion != "" {
|
|
||||||
c.clientVersion = []byte(config.ClientVersion)
|
|
||||||
} else {
|
|
||||||
c.clientVersion = []byte(packageVersion)
|
|
||||||
}
|
|
||||||
var err error
|
|
||||||
c.serverVersion, err = exchangeVersions(c.sshConn.conn, c.clientVersion)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
c.transport = newClientTransport(
|
|
||||||
newTransport(c.sshConn.conn, config.Rand, true /* is client */),
|
|
||||||
c.clientVersion, c.serverVersion, config, dialAddress, c.sshConn.RemoteAddr())
|
|
||||||
if err := c.transport.waitSession(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
c.sessionID = c.transport.getSessionID()
|
|
||||||
return c.clientAuthenticate(config)
|
|
||||||
}
|
|
||||||
|
|
||||||
// verifyHostKeySignature verifies the host key obtained in the key
|
|
||||||
// exchange.
|
|
||||||
func verifyHostKeySignature(hostKey PublicKey, result *kexResult) error {
|
|
||||||
sig, rest, ok := parseSignatureBody(result.Signature)
|
|
||||||
if len(rest) > 0 || !ok {
|
|
||||||
return errors.New("ssh: signature parse error")
|
|
||||||
}
|
|
||||||
|
|
||||||
return hostKey.Verify(result.H, sig)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewSession opens a new Session for this client. (A session is a remote
|
|
||||||
// execution of a program.)
|
|
||||||
func (c *Client) NewSession() (*Session, error) {
|
|
||||||
ch, in, err := c.OpenChannel("session", nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return newSession(ch, in)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) handleGlobalRequests(incoming <-chan *Request) {
|
|
||||||
for r := range incoming {
|
|
||||||
// This handles keepalive messages and matches
|
|
||||||
// the behaviour of OpenSSH.
|
|
||||||
r.Reply(false, nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// handleChannelOpens channel open messages from the remote side.
|
|
||||||
func (c *Client) handleChannelOpens(in <-chan NewChannel) {
|
|
||||||
for ch := range in {
|
|
||||||
c.mu.Lock()
|
|
||||||
handler := c.channelHandlers[ch.ChannelType()]
|
|
||||||
c.mu.Unlock()
|
|
||||||
|
|
||||||
if handler != nil {
|
|
||||||
handler <- ch
|
|
||||||
} else {
|
|
||||||
ch.Reject(UnknownChannelType, fmt.Sprintf("unknown channel type: %v", ch.ChannelType()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
c.mu.Lock()
|
|
||||||
for _, ch := range c.channelHandlers {
|
|
||||||
close(ch)
|
|
||||||
}
|
|
||||||
c.channelHandlers = nil
|
|
||||||
c.mu.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dial starts a client connection to the given SSH server. It is a
|
|
||||||
// convenience function that connects to the given network address,
|
|
||||||
// initiates the SSH handshake, and then sets up a Client. For access
|
|
||||||
// to incoming channels and requests, use net.Dial with NewClientConn
|
|
||||||
// instead.
|
|
||||||
func Dial(network, addr string, config *ClientConfig) (*Client, error) {
|
|
||||||
conn, err := net.DialTimeout(network, addr, config.Timeout)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
c, chans, reqs, err := NewClientConn(conn, addr, config)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return NewClient(c, chans, reqs), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// HostKeyCallback is the function type used for verifying server
|
|
||||||
// keys. A HostKeyCallback must return nil if the host key is OK, or
|
|
||||||
// an error to reject it. It receives the hostname as passed to Dial
|
|
||||||
// or NewClientConn. The remote address is the RemoteAddr of the
|
|
||||||
// net.Conn underlying the SSH connection.
|
|
||||||
type HostKeyCallback func(hostname string, remote net.Addr, key PublicKey) error
|
|
||||||
|
|
||||||
// BannerCallback is the function type used for treat the banner sent by
|
|
||||||
// the server. A BannerCallback receives the message sent by the remote server.
|
|
||||||
type BannerCallback func(message string) error
|
|
||||||
|
|
||||||
// A ClientConfig structure is used to configure a Client. It must not be
|
|
||||||
// modified after having been passed to an SSH function.
|
|
||||||
type ClientConfig struct {
|
|
||||||
// Config contains configuration that is shared between clients and
|
|
||||||
// servers.
|
|
||||||
Config
|
|
||||||
|
|
||||||
// User contains the username to authenticate as.
|
|
||||||
User string
|
|
||||||
|
|
||||||
// Auth contains possible authentication methods to use with the
|
|
||||||
// server. Only the first instance of a particular RFC 4252 method will
|
|
||||||
// be used during authentication.
|
|
||||||
Auth []AuthMethod
|
|
||||||
|
|
||||||
// HostKeyCallback is called during the cryptographic
|
|
||||||
// handshake to validate the server's host key. The client
|
|
||||||
// configuration must supply this callback for the connection
|
|
||||||
// to succeed. The functions InsecureIgnoreHostKey or
|
|
||||||
// FixedHostKey can be used for simplistic host key checks.
|
|
||||||
HostKeyCallback HostKeyCallback
|
|
||||||
|
|
||||||
// BannerCallback is called during the SSH dance to display a custom
|
|
||||||
// server's message. The client configuration can supply this callback to
|
|
||||||
// handle it as wished. The function BannerDisplayStderr can be used for
|
|
||||||
// simplistic display on Stderr.
|
|
||||||
BannerCallback BannerCallback
|
|
||||||
|
|
||||||
// ClientVersion contains the version identification string that will
|
|
||||||
// be used for the connection. If empty, a reasonable default is used.
|
|
||||||
ClientVersion string
|
|
||||||
|
|
||||||
// HostKeyAlgorithms lists the key types that the client will
|
|
||||||
// accept from the server as host key, in order of
|
|
||||||
// preference. If empty, a reasonable default is used. Any
|
|
||||||
// string returned from PublicKey.Type method may be used, or
|
|
||||||
// any of the CertAlgoXxxx and KeyAlgoXxxx constants.
|
|
||||||
HostKeyAlgorithms []string
|
|
||||||
|
|
||||||
// Timeout is the maximum amount of time for the TCP connection to establish.
|
|
||||||
//
|
|
||||||
// A Timeout of zero means no timeout.
|
|
||||||
Timeout time.Duration
|
|
||||||
}
|
|
||||||
|
|
||||||
// InsecureIgnoreHostKey returns a function that can be used for
|
|
||||||
// ClientConfig.HostKeyCallback to accept any host key. It should
|
|
||||||
// not be used for production code.
|
|
||||||
func InsecureIgnoreHostKey() HostKeyCallback {
|
|
||||||
return func(hostname string, remote net.Addr, key PublicKey) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type fixedHostKey struct {
|
|
||||||
key PublicKey
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *fixedHostKey) check(hostname string, remote net.Addr, key PublicKey) error {
|
|
||||||
if f.key == nil {
|
|
||||||
return fmt.Errorf("ssh: required host key was nil")
|
|
||||||
}
|
|
||||||
if !bytes.Equal(key.Marshal(), f.key.Marshal()) {
|
|
||||||
return fmt.Errorf("ssh: host key mismatch")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// FixedHostKey returns a function for use in
|
|
||||||
// ClientConfig.HostKeyCallback to accept only a specific host key.
|
|
||||||
func FixedHostKey(key PublicKey) HostKeyCallback {
|
|
||||||
hk := &fixedHostKey{key}
|
|
||||||
return hk.check
|
|
||||||
}
|
|
||||||
|
|
||||||
// BannerDisplayStderr returns a function that can be used for
|
|
||||||
// ClientConfig.BannerCallback to display banners on os.Stderr.
|
|
||||||
func BannerDisplayStderr() BannerCallback {
|
|
||||||
return func(banner string) error {
|
|
||||||
_, err := os.Stderr.WriteString(banner)
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
639
vendor/golang.org/x/crypto/ssh/client_auth.go
generated
vendored
639
vendor/golang.org/x/crypto/ssh/client_auth.go
generated
vendored
@ -1,639 +0,0 @@
|
|||||||
// 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 ssh
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
)
|
|
||||||
|
|
||||||
type authResult int
|
|
||||||
|
|
||||||
const (
|
|
||||||
authFailure authResult = iota
|
|
||||||
authPartialSuccess
|
|
||||||
authSuccess
|
|
||||||
)
|
|
||||||
|
|
||||||
// clientAuthenticate authenticates with the remote server. See RFC 4252.
|
|
||||||
func (c *connection) clientAuthenticate(config *ClientConfig) error {
|
|
||||||
// initiate user auth session
|
|
||||||
if err := c.transport.writePacket(Marshal(&serviceRequestMsg{serviceUserAuth})); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
packet, err := c.transport.readPacket()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
var serviceAccept serviceAcceptMsg
|
|
||||||
if err := Unmarshal(packet, &serviceAccept); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// during the authentication phase the client first attempts the "none" method
|
|
||||||
// then any untried methods suggested by the server.
|
|
||||||
tried := make(map[string]bool)
|
|
||||||
var lastMethods []string
|
|
||||||
|
|
||||||
sessionID := c.transport.getSessionID()
|
|
||||||
for auth := AuthMethod(new(noneAuth)); auth != nil; {
|
|
||||||
ok, methods, err := auth.auth(sessionID, config.User, c.transport, config.Rand)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if ok == authSuccess {
|
|
||||||
// success
|
|
||||||
return nil
|
|
||||||
} else if ok == authFailure {
|
|
||||||
tried[auth.method()] = true
|
|
||||||
}
|
|
||||||
if methods == nil {
|
|
||||||
methods = lastMethods
|
|
||||||
}
|
|
||||||
lastMethods = methods
|
|
||||||
|
|
||||||
auth = nil
|
|
||||||
|
|
||||||
findNext:
|
|
||||||
for _, a := range config.Auth {
|
|
||||||
candidateMethod := a.method()
|
|
||||||
if tried[candidateMethod] {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
for _, meth := range methods {
|
|
||||||
if meth == candidateMethod {
|
|
||||||
auth = a
|
|
||||||
break findNext
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return fmt.Errorf("ssh: unable to authenticate, attempted methods %v, no supported methods remain", keys(tried))
|
|
||||||
}
|
|
||||||
|
|
||||||
func keys(m map[string]bool) []string {
|
|
||||||
s := make([]string, 0, len(m))
|
|
||||||
|
|
||||||
for key := range m {
|
|
||||||
s = append(s, key)
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
// An AuthMethod represents an instance of an RFC 4252 authentication method.
|
|
||||||
type AuthMethod interface {
|
|
||||||
// auth authenticates user over transport t.
|
|
||||||
// Returns true if authentication is successful.
|
|
||||||
// If authentication is not successful, a []string of alternative
|
|
||||||
// method names is returned. If the slice is nil, it will be ignored
|
|
||||||
// and the previous set of possible methods will be reused.
|
|
||||||
auth(session []byte, user string, p packetConn, rand io.Reader) (authResult, []string, error)
|
|
||||||
|
|
||||||
// method returns the RFC 4252 method name.
|
|
||||||
method() string
|
|
||||||
}
|
|
||||||
|
|
||||||
// "none" authentication, RFC 4252 section 5.2.
|
|
||||||
type noneAuth int
|
|
||||||
|
|
||||||
func (n *noneAuth) auth(session []byte, user string, c packetConn, rand io.Reader) (authResult, []string, error) {
|
|
||||||
if err := c.writePacket(Marshal(&userAuthRequestMsg{
|
|
||||||
User: user,
|
|
||||||
Service: serviceSSH,
|
|
||||||
Method: "none",
|
|
||||||
})); err != nil {
|
|
||||||
return authFailure, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return handleAuthResponse(c)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *noneAuth) method() string {
|
|
||||||
return "none"
|
|
||||||
}
|
|
||||||
|
|
||||||
// passwordCallback is an AuthMethod that fetches the password through
|
|
||||||
// a function call, e.g. by prompting the user.
|
|
||||||
type passwordCallback func() (password string, err error)
|
|
||||||
|
|
||||||
func (cb passwordCallback) auth(session []byte, user string, c packetConn, rand io.Reader) (authResult, []string, error) {
|
|
||||||
type passwordAuthMsg struct {
|
|
||||||
User string `sshtype:"50"`
|
|
||||||
Service string
|
|
||||||
Method string
|
|
||||||
Reply bool
|
|
||||||
Password string
|
|
||||||
}
|
|
||||||
|
|
||||||
pw, err := cb()
|
|
||||||
// REVIEW NOTE: is there a need to support skipping a password attempt?
|
|
||||||
// The program may only find out that the user doesn't have a password
|
|
||||||
// when prompting.
|
|
||||||
if err != nil {
|
|
||||||
return authFailure, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := c.writePacket(Marshal(&passwordAuthMsg{
|
|
||||||
User: user,
|
|
||||||
Service: serviceSSH,
|
|
||||||
Method: cb.method(),
|
|
||||||
Reply: false,
|
|
||||||
Password: pw,
|
|
||||||
})); err != nil {
|
|
||||||
return authFailure, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return handleAuthResponse(c)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cb passwordCallback) method() string {
|
|
||||||
return "password"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Password returns an AuthMethod using the given password.
|
|
||||||
func Password(secret string) AuthMethod {
|
|
||||||
return passwordCallback(func() (string, error) { return secret, nil })
|
|
||||||
}
|
|
||||||
|
|
||||||
// PasswordCallback returns an AuthMethod that uses a callback for
|
|
||||||
// fetching a password.
|
|
||||||
func PasswordCallback(prompt func() (secret string, err error)) AuthMethod {
|
|
||||||
return passwordCallback(prompt)
|
|
||||||
}
|
|
||||||
|
|
||||||
type publickeyAuthMsg struct {
|
|
||||||
User string `sshtype:"50"`
|
|
||||||
Service string
|
|
||||||
Method string
|
|
||||||
// HasSig indicates to the receiver packet that the auth request is signed and
|
|
||||||
// should be used for authentication of the request.
|
|
||||||
HasSig bool
|
|
||||||
Algoname string
|
|
||||||
PubKey []byte
|
|
||||||
// Sig is tagged with "rest" so Marshal will exclude it during
|
|
||||||
// validateKey
|
|
||||||
Sig []byte `ssh:"rest"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// publicKeyCallback is an AuthMethod that uses a set of key
|
|
||||||
// pairs for authentication.
|
|
||||||
type publicKeyCallback func() ([]Signer, error)
|
|
||||||
|
|
||||||
func (cb publicKeyCallback) method() string {
|
|
||||||
return "publickey"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand io.Reader) (authResult, []string, error) {
|
|
||||||
// Authentication is performed by sending an enquiry to test if a key is
|
|
||||||
// acceptable to the remote. If the key is acceptable, the client will
|
|
||||||
// attempt to authenticate with the valid key. If not the client will repeat
|
|
||||||
// the process with the remaining keys.
|
|
||||||
|
|
||||||
signers, err := cb()
|
|
||||||
if err != nil {
|
|
||||||
return authFailure, nil, err
|
|
||||||
}
|
|
||||||
var methods []string
|
|
||||||
for _, signer := range signers {
|
|
||||||
ok, err := validateKey(signer.PublicKey(), user, c)
|
|
||||||
if err != nil {
|
|
||||||
return authFailure, nil, err
|
|
||||||
}
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
pub := signer.PublicKey()
|
|
||||||
pubKey := pub.Marshal()
|
|
||||||
sign, err := signer.Sign(rand, buildDataSignedForAuth(session, userAuthRequestMsg{
|
|
||||||
User: user,
|
|
||||||
Service: serviceSSH,
|
|
||||||
Method: cb.method(),
|
|
||||||
}, []byte(pub.Type()), pubKey))
|
|
||||||
if err != nil {
|
|
||||||
return authFailure, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// manually wrap the serialized signature in a string
|
|
||||||
s := Marshal(sign)
|
|
||||||
sig := make([]byte, stringLength(len(s)))
|
|
||||||
marshalString(sig, s)
|
|
||||||
msg := publickeyAuthMsg{
|
|
||||||
User: user,
|
|
||||||
Service: serviceSSH,
|
|
||||||
Method: cb.method(),
|
|
||||||
HasSig: true,
|
|
||||||
Algoname: pub.Type(),
|
|
||||||
PubKey: pubKey,
|
|
||||||
Sig: sig,
|
|
||||||
}
|
|
||||||
p := Marshal(&msg)
|
|
||||||
if err := c.writePacket(p); err != nil {
|
|
||||||
return authFailure, nil, err
|
|
||||||
}
|
|
||||||
var success authResult
|
|
||||||
success, methods, err = handleAuthResponse(c)
|
|
||||||
if err != nil {
|
|
||||||
return authFailure, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// If authentication succeeds or the list of available methods does not
|
|
||||||
// contain the "publickey" method, do not attempt to authenticate with any
|
|
||||||
// other keys. According to RFC 4252 Section 7, the latter can occur when
|
|
||||||
// additional authentication methods are required.
|
|
||||||
if success == authSuccess || !containsMethod(methods, cb.method()) {
|
|
||||||
return success, methods, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return authFailure, methods, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func containsMethod(methods []string, method string) bool {
|
|
||||||
for _, m := range methods {
|
|
||||||
if m == method {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// validateKey validates the key provided is acceptable to the server.
|
|
||||||
func validateKey(key PublicKey, user string, c packetConn) (bool, error) {
|
|
||||||
pubKey := key.Marshal()
|
|
||||||
msg := publickeyAuthMsg{
|
|
||||||
User: user,
|
|
||||||
Service: serviceSSH,
|
|
||||||
Method: "publickey",
|
|
||||||
HasSig: false,
|
|
||||||
Algoname: key.Type(),
|
|
||||||
PubKey: pubKey,
|
|
||||||
}
|
|
||||||
if err := c.writePacket(Marshal(&msg)); err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return confirmKeyAck(key, c)
|
|
||||||
}
|
|
||||||
|
|
||||||
func confirmKeyAck(key PublicKey, c packetConn) (bool, error) {
|
|
||||||
pubKey := key.Marshal()
|
|
||||||
algoname := key.Type()
|
|
||||||
|
|
||||||
for {
|
|
||||||
packet, err := c.readPacket()
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
switch packet[0] {
|
|
||||||
case msgUserAuthBanner:
|
|
||||||
if err := handleBannerResponse(c, packet); err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
case msgUserAuthPubKeyOk:
|
|
||||||
var msg userAuthPubKeyOkMsg
|
|
||||||
if err := Unmarshal(packet, &msg); err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
if msg.Algo != algoname || !bytes.Equal(msg.PubKey, pubKey) {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
return true, nil
|
|
||||||
case msgUserAuthFailure:
|
|
||||||
return false, nil
|
|
||||||
default:
|
|
||||||
return false, unexpectedMessageError(msgUserAuthSuccess, packet[0])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// PublicKeys returns an AuthMethod that uses the given key
|
|
||||||
// pairs.
|
|
||||||
func PublicKeys(signers ...Signer) AuthMethod {
|
|
||||||
return publicKeyCallback(func() ([]Signer, error) { return signers, nil })
|
|
||||||
}
|
|
||||||
|
|
||||||
// PublicKeysCallback returns an AuthMethod that runs the given
|
|
||||||
// function to obtain a list of key pairs.
|
|
||||||
func PublicKeysCallback(getSigners func() (signers []Signer, err error)) AuthMethod {
|
|
||||||
return publicKeyCallback(getSigners)
|
|
||||||
}
|
|
||||||
|
|
||||||
// handleAuthResponse returns whether the preceding authentication request succeeded
|
|
||||||
// along with a list of remaining authentication methods to try next and
|
|
||||||
// an error if an unexpected response was received.
|
|
||||||
func handleAuthResponse(c packetConn) (authResult, []string, error) {
|
|
||||||
for {
|
|
||||||
packet, err := c.readPacket()
|
|
||||||
if err != nil {
|
|
||||||
return authFailure, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
switch packet[0] {
|
|
||||||
case msgUserAuthBanner:
|
|
||||||
if err := handleBannerResponse(c, packet); err != nil {
|
|
||||||
return authFailure, nil, err
|
|
||||||
}
|
|
||||||
case msgUserAuthFailure:
|
|
||||||
var msg userAuthFailureMsg
|
|
||||||
if err := Unmarshal(packet, &msg); err != nil {
|
|
||||||
return authFailure, nil, err
|
|
||||||
}
|
|
||||||
if msg.PartialSuccess {
|
|
||||||
return authPartialSuccess, msg.Methods, nil
|
|
||||||
}
|
|
||||||
return authFailure, msg.Methods, nil
|
|
||||||
case msgUserAuthSuccess:
|
|
||||||
return authSuccess, nil, nil
|
|
||||||
default:
|
|
||||||
return authFailure, nil, unexpectedMessageError(msgUserAuthSuccess, packet[0])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleBannerResponse(c packetConn, packet []byte) error {
|
|
||||||
var msg userAuthBannerMsg
|
|
||||||
if err := Unmarshal(packet, &msg); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
transport, ok := c.(*handshakeTransport)
|
|
||||||
if !ok {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if transport.bannerCallback != nil {
|
|
||||||
return transport.bannerCallback(msg.Message)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// KeyboardInteractiveChallenge should print questions, optionally
|
|
||||||
// disabling echoing (e.g. for passwords), and return all the answers.
|
|
||||||
// Challenge may be called multiple times in a single session. After
|
|
||||||
// successful authentication, the server may send a challenge with no
|
|
||||||
// questions, for which the user and instruction messages should be
|
|
||||||
// printed. RFC 4256 section 3.3 details how the UI should behave for
|
|
||||||
// both CLI and GUI environments.
|
|
||||||
type KeyboardInteractiveChallenge func(user, instruction string, questions []string, echos []bool) (answers []string, err error)
|
|
||||||
|
|
||||||
// KeyboardInteractive returns an AuthMethod using a prompt/response
|
|
||||||
// sequence controlled by the server.
|
|
||||||
func KeyboardInteractive(challenge KeyboardInteractiveChallenge) AuthMethod {
|
|
||||||
return challenge
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cb KeyboardInteractiveChallenge) method() string {
|
|
||||||
return "keyboard-interactive"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cb KeyboardInteractiveChallenge) auth(session []byte, user string, c packetConn, rand io.Reader) (authResult, []string, error) {
|
|
||||||
type initiateMsg struct {
|
|
||||||
User string `sshtype:"50"`
|
|
||||||
Service string
|
|
||||||
Method string
|
|
||||||
Language string
|
|
||||||
Submethods string
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := c.writePacket(Marshal(&initiateMsg{
|
|
||||||
User: user,
|
|
||||||
Service: serviceSSH,
|
|
||||||
Method: "keyboard-interactive",
|
|
||||||
})); err != nil {
|
|
||||||
return authFailure, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for {
|
|
||||||
packet, err := c.readPacket()
|
|
||||||
if err != nil {
|
|
||||||
return authFailure, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// like handleAuthResponse, but with less options.
|
|
||||||
switch packet[0] {
|
|
||||||
case msgUserAuthBanner:
|
|
||||||
if err := handleBannerResponse(c, packet); err != nil {
|
|
||||||
return authFailure, nil, err
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
case msgUserAuthInfoRequest:
|
|
||||||
// OK
|
|
||||||
case msgUserAuthFailure:
|
|
||||||
var msg userAuthFailureMsg
|
|
||||||
if err := Unmarshal(packet, &msg); err != nil {
|
|
||||||
return authFailure, nil, err
|
|
||||||
}
|
|
||||||
if msg.PartialSuccess {
|
|
||||||
return authPartialSuccess, msg.Methods, nil
|
|
||||||
}
|
|
||||||
return authFailure, msg.Methods, nil
|
|
||||||
case msgUserAuthSuccess:
|
|
||||||
return authSuccess, nil, nil
|
|
||||||
default:
|
|
||||||
return authFailure, nil, unexpectedMessageError(msgUserAuthInfoRequest, packet[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
var msg userAuthInfoRequestMsg
|
|
||||||
if err := Unmarshal(packet, &msg); err != nil {
|
|
||||||
return authFailure, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Manually unpack the prompt/echo pairs.
|
|
||||||
rest := msg.Prompts
|
|
||||||
var prompts []string
|
|
||||||
var echos []bool
|
|
||||||
for i := 0; i < int(msg.NumPrompts); i++ {
|
|
||||||
prompt, r, ok := parseString(rest)
|
|
||||||
if !ok || len(r) == 0 {
|
|
||||||
return authFailure, nil, errors.New("ssh: prompt format error")
|
|
||||||
}
|
|
||||||
prompts = append(prompts, string(prompt))
|
|
||||||
echos = append(echos, r[0] != 0)
|
|
||||||
rest = r[1:]
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(rest) != 0 {
|
|
||||||
return authFailure, nil, errors.New("ssh: extra data following keyboard-interactive pairs")
|
|
||||||
}
|
|
||||||
|
|
||||||
answers, err := cb(msg.User, msg.Instruction, prompts, echos)
|
|
||||||
if err != nil {
|
|
||||||
return authFailure, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(answers) != len(prompts) {
|
|
||||||
return authFailure, nil, errors.New("ssh: not enough answers from keyboard-interactive callback")
|
|
||||||
}
|
|
||||||
responseLength := 1 + 4
|
|
||||||
for _, a := range answers {
|
|
||||||
responseLength += stringLength(len(a))
|
|
||||||
}
|
|
||||||
serialized := make([]byte, responseLength)
|
|
||||||
p := serialized
|
|
||||||
p[0] = msgUserAuthInfoResponse
|
|
||||||
p = p[1:]
|
|
||||||
p = marshalUint32(p, uint32(len(answers)))
|
|
||||||
for _, a := range answers {
|
|
||||||
p = marshalString(p, []byte(a))
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := c.writePacket(serialized); err != nil {
|
|
||||||
return authFailure, nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type retryableAuthMethod struct {
|
|
||||||
authMethod AuthMethod
|
|
||||||
maxTries int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *retryableAuthMethod) auth(session []byte, user string, c packetConn, rand io.Reader) (ok authResult, methods []string, err error) {
|
|
||||||
for i := 0; r.maxTries <= 0 || i < r.maxTries; i++ {
|
|
||||||
ok, methods, err = r.authMethod.auth(session, user, c, rand)
|
|
||||||
if ok != authFailure || err != nil { // either success, partial success or error terminate
|
|
||||||
return ok, methods, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ok, methods, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *retryableAuthMethod) method() string {
|
|
||||||
return r.authMethod.method()
|
|
||||||
}
|
|
||||||
|
|
||||||
// RetryableAuthMethod is a decorator for other auth methods enabling them to
|
|
||||||
// be retried up to maxTries before considering that AuthMethod itself failed.
|
|
||||||
// If maxTries is <= 0, will retry indefinitely
|
|
||||||
//
|
|
||||||
// This is useful for interactive clients using challenge/response type
|
|
||||||
// authentication (e.g. Keyboard-Interactive, Password, etc) where the user
|
|
||||||
// could mistype their response resulting in the server issuing a
|
|
||||||
// SSH_MSG_USERAUTH_FAILURE (rfc4252 #8 [password] and rfc4256 #3.4
|
|
||||||
// [keyboard-interactive]); Without this decorator, the non-retryable
|
|
||||||
// AuthMethod would be removed from future consideration, and never tried again
|
|
||||||
// (and so the user would never be able to retry their entry).
|
|
||||||
func RetryableAuthMethod(auth AuthMethod, maxTries int) AuthMethod {
|
|
||||||
return &retryableAuthMethod{authMethod: auth, maxTries: maxTries}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GSSAPIWithMICAuthMethod is an AuthMethod with "gssapi-with-mic" authentication.
|
|
||||||
// See RFC 4462 section 3
|
|
||||||
// gssAPIClient is implementation of the GSSAPIClient interface, see the definition of the interface for details.
|
|
||||||
// target is the server host you want to log in to.
|
|
||||||
func GSSAPIWithMICAuthMethod(gssAPIClient GSSAPIClient, target string) AuthMethod {
|
|
||||||
if gssAPIClient == nil {
|
|
||||||
panic("gss-api client must be not nil with enable gssapi-with-mic")
|
|
||||||
}
|
|
||||||
return &gssAPIWithMICCallback{gssAPIClient: gssAPIClient, target: target}
|
|
||||||
}
|
|
||||||
|
|
||||||
type gssAPIWithMICCallback struct {
|
|
||||||
gssAPIClient GSSAPIClient
|
|
||||||
target string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *gssAPIWithMICCallback) auth(session []byte, user string, c packetConn, rand io.Reader) (authResult, []string, error) {
|
|
||||||
m := &userAuthRequestMsg{
|
|
||||||
User: user,
|
|
||||||
Service: serviceSSH,
|
|
||||||
Method: g.method(),
|
|
||||||
}
|
|
||||||
// The GSS-API authentication method is initiated when the client sends an SSH_MSG_USERAUTH_REQUEST.
|
|
||||||
// See RFC 4462 section 3.2.
|
|
||||||
m.Payload = appendU32(m.Payload, 1)
|
|
||||||
m.Payload = appendString(m.Payload, string(krb5OID))
|
|
||||||
if err := c.writePacket(Marshal(m)); err != nil {
|
|
||||||
return authFailure, nil, err
|
|
||||||
}
|
|
||||||
// The server responds to the SSH_MSG_USERAUTH_REQUEST with either an
|
|
||||||
// SSH_MSG_USERAUTH_FAILURE if none of the mechanisms are supported or
|
|
||||||
// with an SSH_MSG_USERAUTH_GSSAPI_RESPONSE.
|
|
||||||
// See RFC 4462 section 3.3.
|
|
||||||
// OpenSSH supports Kerberos V5 mechanism only for GSS-API authentication,so I don't want to check
|
|
||||||
// selected mech if it is valid.
|
|
||||||
packet, err := c.readPacket()
|
|
||||||
if err != nil {
|
|
||||||
return authFailure, nil, err
|
|
||||||
}
|
|
||||||
userAuthGSSAPIResp := &userAuthGSSAPIResponse{}
|
|
||||||
if err := Unmarshal(packet, userAuthGSSAPIResp); err != nil {
|
|
||||||
return authFailure, nil, err
|
|
||||||
}
|
|
||||||
// Start the loop into the exchange token.
|
|
||||||
// See RFC 4462 section 3.4.
|
|
||||||
var token []byte
|
|
||||||
defer g.gssAPIClient.DeleteSecContext()
|
|
||||||
for {
|
|
||||||
// Initiates the establishment of a security context between the application and a remote peer.
|
|
||||||
nextToken, needContinue, err := g.gssAPIClient.InitSecContext("host@"+g.target, token, false)
|
|
||||||
if err != nil {
|
|
||||||
return authFailure, nil, err
|
|
||||||
}
|
|
||||||
if len(nextToken) > 0 {
|
|
||||||
if err := c.writePacket(Marshal(&userAuthGSSAPIToken{
|
|
||||||
Token: nextToken,
|
|
||||||
})); err != nil {
|
|
||||||
return authFailure, nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !needContinue {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
packet, err = c.readPacket()
|
|
||||||
if err != nil {
|
|
||||||
return authFailure, nil, err
|
|
||||||
}
|
|
||||||
switch packet[0] {
|
|
||||||
case msgUserAuthFailure:
|
|
||||||
var msg userAuthFailureMsg
|
|
||||||
if err := Unmarshal(packet, &msg); err != nil {
|
|
||||||
return authFailure, nil, err
|
|
||||||
}
|
|
||||||
if msg.PartialSuccess {
|
|
||||||
return authPartialSuccess, msg.Methods, nil
|
|
||||||
}
|
|
||||||
return authFailure, msg.Methods, nil
|
|
||||||
case msgUserAuthGSSAPIError:
|
|
||||||
userAuthGSSAPIErrorResp := &userAuthGSSAPIError{}
|
|
||||||
if err := Unmarshal(packet, userAuthGSSAPIErrorResp); err != nil {
|
|
||||||
return authFailure, nil, err
|
|
||||||
}
|
|
||||||
return authFailure, nil, fmt.Errorf("GSS-API Error:\n"+
|
|
||||||
"Major Status: %d\n"+
|
|
||||||
"Minor Status: %d\n"+
|
|
||||||
"Error Message: %s\n", userAuthGSSAPIErrorResp.MajorStatus, userAuthGSSAPIErrorResp.MinorStatus,
|
|
||||||
userAuthGSSAPIErrorResp.Message)
|
|
||||||
case msgUserAuthGSSAPIToken:
|
|
||||||
userAuthGSSAPITokenReq := &userAuthGSSAPIToken{}
|
|
||||||
if err := Unmarshal(packet, userAuthGSSAPITokenReq); err != nil {
|
|
||||||
return authFailure, nil, err
|
|
||||||
}
|
|
||||||
token = userAuthGSSAPITokenReq.Token
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Binding Encryption Keys.
|
|
||||||
// See RFC 4462 section 3.5.
|
|
||||||
micField := buildMIC(string(session), user, "ssh-connection", "gssapi-with-mic")
|
|
||||||
micToken, err := g.gssAPIClient.GetMIC(micField)
|
|
||||||
if err != nil {
|
|
||||||
return authFailure, nil, err
|
|
||||||
}
|
|
||||||
if err := c.writePacket(Marshal(&userAuthGSSAPIMIC{
|
|
||||||
MIC: micToken,
|
|
||||||
})); err != nil {
|
|
||||||
return authFailure, nil, err
|
|
||||||
}
|
|
||||||
return handleAuthResponse(c)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *gssAPIWithMICCallback) method() string {
|
|
||||||
return "gssapi-with-mic"
|
|
||||||
}
|
|
396
vendor/golang.org/x/crypto/ssh/common.go
generated
vendored
396
vendor/golang.org/x/crypto/ssh/common.go
generated
vendored
@ -1,396 +0,0 @@
|
|||||||
// 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 ssh
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto"
|
|
||||||
"crypto/rand"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"math"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
_ "crypto/sha1"
|
|
||||||
_ "crypto/sha256"
|
|
||||||
_ "crypto/sha512"
|
|
||||||
)
|
|
||||||
|
|
||||||
// These are string constants in the SSH protocol.
|
|
||||||
const (
|
|
||||||
compressionNone = "none"
|
|
||||||
serviceUserAuth = "ssh-userauth"
|
|
||||||
serviceSSH = "ssh-connection"
|
|
||||||
)
|
|
||||||
|
|
||||||
// supportedCiphers lists ciphers we support but might not recommend.
|
|
||||||
var supportedCiphers = []string{
|
|
||||||
"aes128-ctr", "aes192-ctr", "aes256-ctr",
|
|
||||||
"aes128-gcm@openssh.com",
|
|
||||||
chacha20Poly1305ID,
|
|
||||||
"arcfour256", "arcfour128", "arcfour",
|
|
||||||
aes128cbcID,
|
|
||||||
tripledescbcID,
|
|
||||||
}
|
|
||||||
|
|
||||||
// preferredCiphers specifies the default preference for ciphers.
|
|
||||||
var preferredCiphers = []string{
|
|
||||||
"aes128-gcm@openssh.com",
|
|
||||||
chacha20Poly1305ID,
|
|
||||||
"aes128-ctr", "aes192-ctr", "aes256-ctr",
|
|
||||||
}
|
|
||||||
|
|
||||||
// supportedKexAlgos specifies the supported key-exchange algorithms in
|
|
||||||
// preference order.
|
|
||||||
var supportedKexAlgos = []string{
|
|
||||||
kexAlgoCurve25519SHA256,
|
|
||||||
// P384 and P521 are not constant-time yet, but since we don't
|
|
||||||
// reuse ephemeral keys, using them for ECDH should be OK.
|
|
||||||
kexAlgoECDH256, kexAlgoECDH384, kexAlgoECDH521,
|
|
||||||
kexAlgoDH14SHA1, kexAlgoDH1SHA1,
|
|
||||||
}
|
|
||||||
|
|
||||||
// serverForbiddenKexAlgos contains key exchange algorithms, that are forbidden
|
|
||||||
// for the server half.
|
|
||||||
var serverForbiddenKexAlgos = map[string]struct{}{
|
|
||||||
kexAlgoDHGEXSHA1: {}, // server half implementation is only minimal to satisfy the automated tests
|
|
||||||
kexAlgoDHGEXSHA256: {}, // server half implementation is only minimal to satisfy the automated tests
|
|
||||||
}
|
|
||||||
|
|
||||||
// supportedHostKeyAlgos specifies the supported host-key algorithms (i.e. methods
|
|
||||||
// of authenticating servers) in preference order.
|
|
||||||
var supportedHostKeyAlgos = []string{
|
|
||||||
CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01,
|
|
||||||
CertAlgoECDSA384v01, CertAlgoECDSA521v01, CertAlgoED25519v01,
|
|
||||||
|
|
||||||
KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521,
|
|
||||||
KeyAlgoRSA, KeyAlgoDSA,
|
|
||||||
|
|
||||||
KeyAlgoED25519,
|
|
||||||
}
|
|
||||||
|
|
||||||
// supportedMACs specifies a default set of MAC algorithms in preference order.
|
|
||||||
// This is based on RFC 4253, section 6.4, but with hmac-md5 variants removed
|
|
||||||
// because they have reached the end of their useful life.
|
|
||||||
var supportedMACs = []string{
|
|
||||||
"hmac-sha2-256-etm@openssh.com", "hmac-sha2-256", "hmac-sha1", "hmac-sha1-96",
|
|
||||||
}
|
|
||||||
|
|
||||||
var supportedCompressions = []string{compressionNone}
|
|
||||||
|
|
||||||
// hashFuncs keeps the mapping of supported algorithms to their respective
|
|
||||||
// hashes needed for signature verification.
|
|
||||||
var hashFuncs = map[string]crypto.Hash{
|
|
||||||
KeyAlgoRSA: crypto.SHA1,
|
|
||||||
KeyAlgoDSA: crypto.SHA1,
|
|
||||||
KeyAlgoECDSA256: crypto.SHA256,
|
|
||||||
KeyAlgoECDSA384: crypto.SHA384,
|
|
||||||
KeyAlgoECDSA521: crypto.SHA512,
|
|
||||||
CertAlgoRSAv01: crypto.SHA1,
|
|
||||||
CertAlgoDSAv01: crypto.SHA1,
|
|
||||||
CertAlgoECDSA256v01: crypto.SHA256,
|
|
||||||
CertAlgoECDSA384v01: crypto.SHA384,
|
|
||||||
CertAlgoECDSA521v01: crypto.SHA512,
|
|
||||||
}
|
|
||||||
|
|
||||||
// unexpectedMessageError results when the SSH message that we received didn't
|
|
||||||
// match what we wanted.
|
|
||||||
func unexpectedMessageError(expected, got uint8) error {
|
|
||||||
return fmt.Errorf("ssh: unexpected message type %d (expected %d)", got, expected)
|
|
||||||
}
|
|
||||||
|
|
||||||
// parseError results from a malformed SSH message.
|
|
||||||
func parseError(tag uint8) error {
|
|
||||||
return fmt.Errorf("ssh: parse error in message type %d", tag)
|
|
||||||
}
|
|
||||||
|
|
||||||
func findCommon(what string, client []string, server []string) (common string, err error) {
|
|
||||||
for _, c := range client {
|
|
||||||
for _, s := range server {
|
|
||||||
if c == s {
|
|
||||||
return c, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "", fmt.Errorf("ssh: no common algorithm for %s; client offered: %v, server offered: %v", what, client, server)
|
|
||||||
}
|
|
||||||
|
|
||||||
// directionAlgorithms records algorithm choices in one direction (either read or write)
|
|
||||||
type directionAlgorithms struct {
|
|
||||||
Cipher string
|
|
||||||
MAC string
|
|
||||||
Compression string
|
|
||||||
}
|
|
||||||
|
|
||||||
// rekeyBytes returns a rekeying intervals in bytes.
|
|
||||||
func (a *directionAlgorithms) rekeyBytes() int64 {
|
|
||||||
// According to RFC4344 block ciphers should rekey after
|
|
||||||
// 2^(BLOCKSIZE/4) blocks. For all AES flavors BLOCKSIZE is
|
|
||||||
// 128.
|
|
||||||
switch a.Cipher {
|
|
||||||
case "aes128-ctr", "aes192-ctr", "aes256-ctr", gcmCipherID, aes128cbcID:
|
|
||||||
return 16 * (1 << 32)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// For others, stick with RFC4253 recommendation to rekey after 1 Gb of data.
|
|
||||||
return 1 << 30
|
|
||||||
}
|
|
||||||
|
|
||||||
type algorithms struct {
|
|
||||||
kex string
|
|
||||||
hostKey string
|
|
||||||
w directionAlgorithms
|
|
||||||
r directionAlgorithms
|
|
||||||
}
|
|
||||||
|
|
||||||
func findAgreedAlgorithms(isClient bool, clientKexInit, serverKexInit *kexInitMsg) (algs *algorithms, err error) {
|
|
||||||
result := &algorithms{}
|
|
||||||
|
|
||||||
result.kex, err = findCommon("key exchange", clientKexInit.KexAlgos, serverKexInit.KexAlgos)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
result.hostKey, err = findCommon("host key", clientKexInit.ServerHostKeyAlgos, serverKexInit.ServerHostKeyAlgos)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
stoc, ctos := &result.w, &result.r
|
|
||||||
if isClient {
|
|
||||||
ctos, stoc = stoc, ctos
|
|
||||||
}
|
|
||||||
|
|
||||||
ctos.Cipher, err = findCommon("client to server cipher", clientKexInit.CiphersClientServer, serverKexInit.CiphersClientServer)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
stoc.Cipher, err = findCommon("server to client cipher", clientKexInit.CiphersServerClient, serverKexInit.CiphersServerClient)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctos.MAC, err = findCommon("client to server MAC", clientKexInit.MACsClientServer, serverKexInit.MACsClientServer)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
stoc.MAC, err = findCommon("server to client MAC", clientKexInit.MACsServerClient, serverKexInit.MACsServerClient)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctos.Compression, err = findCommon("client to server compression", clientKexInit.CompressionClientServer, serverKexInit.CompressionClientServer)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
stoc.Compression, err = findCommon("server to client compression", clientKexInit.CompressionServerClient, serverKexInit.CompressionServerClient)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// If rekeythreshold is too small, we can't make any progress sending
|
|
||||||
// stuff.
|
|
||||||
const minRekeyThreshold uint64 = 256
|
|
||||||
|
|
||||||
// Config contains configuration data common to both ServerConfig and
|
|
||||||
// ClientConfig.
|
|
||||||
type Config struct {
|
|
||||||
// Rand provides the source of entropy for cryptographic
|
|
||||||
// primitives. If Rand is nil, the cryptographic random reader
|
|
||||||
// in package crypto/rand will be used.
|
|
||||||
Rand io.Reader
|
|
||||||
|
|
||||||
// The maximum number of bytes sent or received after which a
|
|
||||||
// new key is negotiated. It must be at least 256. If
|
|
||||||
// unspecified, a size suitable for the chosen cipher is used.
|
|
||||||
RekeyThreshold uint64
|
|
||||||
|
|
||||||
// The allowed key exchanges algorithms. If unspecified then a
|
|
||||||
// default set of algorithms is used.
|
|
||||||
KeyExchanges []string
|
|
||||||
|
|
||||||
// The allowed cipher algorithms. If unspecified then a sensible
|
|
||||||
// default is used.
|
|
||||||
Ciphers []string
|
|
||||||
|
|
||||||
// The allowed MAC algorithms. If unspecified then a sensible default
|
|
||||||
// is used.
|
|
||||||
MACs []string
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetDefaults sets sensible values for unset fields in config. This is
|
|
||||||
// exported for testing: Configs passed to SSH functions are copied and have
|
|
||||||
// default values set automatically.
|
|
||||||
func (c *Config) SetDefaults() {
|
|
||||||
if c.Rand == nil {
|
|
||||||
c.Rand = rand.Reader
|
|
||||||
}
|
|
||||||
if c.Ciphers == nil {
|
|
||||||
c.Ciphers = preferredCiphers
|
|
||||||
}
|
|
||||||
var ciphers []string
|
|
||||||
for _, c := range c.Ciphers {
|
|
||||||
if cipherModes[c] != nil {
|
|
||||||
// reject the cipher if we have no cipherModes definition
|
|
||||||
ciphers = append(ciphers, c)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
c.Ciphers = ciphers
|
|
||||||
|
|
||||||
if c.KeyExchanges == nil {
|
|
||||||
c.KeyExchanges = supportedKexAlgos
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.MACs == nil {
|
|
||||||
c.MACs = supportedMACs
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.RekeyThreshold == 0 {
|
|
||||||
// cipher specific default
|
|
||||||
} else if c.RekeyThreshold < minRekeyThreshold {
|
|
||||||
c.RekeyThreshold = minRekeyThreshold
|
|
||||||
} else if c.RekeyThreshold >= math.MaxInt64 {
|
|
||||||
// Avoid weirdness if somebody uses -1 as a threshold.
|
|
||||||
c.RekeyThreshold = math.MaxInt64
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// buildDataSignedForAuth returns the data that is signed in order to prove
|
|
||||||
// possession of a private key. See RFC 4252, section 7.
|
|
||||||
func buildDataSignedForAuth(sessionID []byte, req userAuthRequestMsg, algo, pubKey []byte) []byte {
|
|
||||||
data := struct {
|
|
||||||
Session []byte
|
|
||||||
Type byte
|
|
||||||
User string
|
|
||||||
Service string
|
|
||||||
Method string
|
|
||||||
Sign bool
|
|
||||||
Algo []byte
|
|
||||||
PubKey []byte
|
|
||||||
}{
|
|
||||||
sessionID,
|
|
||||||
msgUserAuthRequest,
|
|
||||||
req.User,
|
|
||||||
req.Service,
|
|
||||||
req.Method,
|
|
||||||
true,
|
|
||||||
algo,
|
|
||||||
pubKey,
|
|
||||||
}
|
|
||||||
return Marshal(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
func appendU16(buf []byte, n uint16) []byte {
|
|
||||||
return append(buf, byte(n>>8), byte(n))
|
|
||||||
}
|
|
||||||
|
|
||||||
func appendU32(buf []byte, n uint32) []byte {
|
|
||||||
return append(buf, byte(n>>24), byte(n>>16), byte(n>>8), byte(n))
|
|
||||||
}
|
|
||||||
|
|
||||||
func appendU64(buf []byte, n uint64) []byte {
|
|
||||||
return append(buf,
|
|
||||||
byte(n>>56), byte(n>>48), byte(n>>40), byte(n>>32),
|
|
||||||
byte(n>>24), byte(n>>16), byte(n>>8), byte(n))
|
|
||||||
}
|
|
||||||
|
|
||||||
func appendInt(buf []byte, n int) []byte {
|
|
||||||
return appendU32(buf, uint32(n))
|
|
||||||
}
|
|
||||||
|
|
||||||
func appendString(buf []byte, s string) []byte {
|
|
||||||
buf = appendU32(buf, uint32(len(s)))
|
|
||||||
buf = append(buf, s...)
|
|
||||||
return buf
|
|
||||||
}
|
|
||||||
|
|
||||||
func appendBool(buf []byte, b bool) []byte {
|
|
||||||
if b {
|
|
||||||
return append(buf, 1)
|
|
||||||
}
|
|
||||||
return append(buf, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// newCond is a helper to hide the fact that there is no usable zero
|
|
||||||
// value for sync.Cond.
|
|
||||||
func newCond() *sync.Cond { return sync.NewCond(new(sync.Mutex)) }
|
|
||||||
|
|
||||||
// window represents the buffer available to clients
|
|
||||||
// wishing to write to a channel.
|
|
||||||
type window struct {
|
|
||||||
*sync.Cond
|
|
||||||
win uint32 // RFC 4254 5.2 says the window size can grow to 2^32-1
|
|
||||||
writeWaiters int
|
|
||||||
closed bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// add adds win to the amount of window available
|
|
||||||
// for consumers.
|
|
||||||
func (w *window) add(win uint32) bool {
|
|
||||||
// a zero sized window adjust is a noop.
|
|
||||||
if win == 0 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
w.L.Lock()
|
|
||||||
if w.win+win < win {
|
|
||||||
w.L.Unlock()
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
w.win += win
|
|
||||||
// It is unusual that multiple goroutines would be attempting to reserve
|
|
||||||
// window space, but not guaranteed. Use broadcast to notify all waiters
|
|
||||||
// that additional window is available.
|
|
||||||
w.Broadcast()
|
|
||||||
w.L.Unlock()
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// close sets the window to closed, so all reservations fail
|
|
||||||
// immediately.
|
|
||||||
func (w *window) close() {
|
|
||||||
w.L.Lock()
|
|
||||||
w.closed = true
|
|
||||||
w.Broadcast()
|
|
||||||
w.L.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
// reserve reserves win from the available window capacity.
|
|
||||||
// If no capacity remains, reserve will block. reserve may
|
|
||||||
// return less than requested.
|
|
||||||
func (w *window) reserve(win uint32) (uint32, error) {
|
|
||||||
var err error
|
|
||||||
w.L.Lock()
|
|
||||||
w.writeWaiters++
|
|
||||||
w.Broadcast()
|
|
||||||
for w.win == 0 && !w.closed {
|
|
||||||
w.Wait()
|
|
||||||
}
|
|
||||||
w.writeWaiters--
|
|
||||||
if w.win < win {
|
|
||||||
win = w.win
|
|
||||||
}
|
|
||||||
w.win -= win
|
|
||||||
if w.closed {
|
|
||||||
err = io.EOF
|
|
||||||
}
|
|
||||||
w.L.Unlock()
|
|
||||||
return win, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// waitWriterBlocked waits until some goroutine is blocked for further
|
|
||||||
// writes. It is used in tests only.
|
|
||||||
func (w *window) waitWriterBlocked() {
|
|
||||||
w.Cond.L.Lock()
|
|
||||||
for w.writeWaiters == 0 {
|
|
||||||
w.Cond.Wait()
|
|
||||||
}
|
|
||||||
w.Cond.L.Unlock()
|
|
||||||
}
|
|
143
vendor/golang.org/x/crypto/ssh/connection.go
generated
vendored
143
vendor/golang.org/x/crypto/ssh/connection.go
generated
vendored
@ -1,143 +0,0 @@
|
|||||||
// Copyright 2013 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package ssh
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
)
|
|
||||||
|
|
||||||
// OpenChannelError is returned if the other side rejects an
|
|
||||||
// OpenChannel request.
|
|
||||||
type OpenChannelError struct {
|
|
||||||
Reason RejectionReason
|
|
||||||
Message string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *OpenChannelError) Error() string {
|
|
||||||
return fmt.Sprintf("ssh: rejected: %s (%s)", e.Reason, e.Message)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConnMetadata holds metadata for the connection.
|
|
||||||
type ConnMetadata interface {
|
|
||||||
// User returns the user ID for this connection.
|
|
||||||
User() string
|
|
||||||
|
|
||||||
// SessionID returns the session hash, also denoted by H.
|
|
||||||
SessionID() []byte
|
|
||||||
|
|
||||||
// ClientVersion returns the client's version string as hashed
|
|
||||||
// into the session ID.
|
|
||||||
ClientVersion() []byte
|
|
||||||
|
|
||||||
// ServerVersion returns the server's version string as hashed
|
|
||||||
// into the session ID.
|
|
||||||
ServerVersion() []byte
|
|
||||||
|
|
||||||
// RemoteAddr returns the remote address for this connection.
|
|
||||||
RemoteAddr() net.Addr
|
|
||||||
|
|
||||||
// LocalAddr returns the local address for this connection.
|
|
||||||
LocalAddr() net.Addr
|
|
||||||
}
|
|
||||||
|
|
||||||
// Conn represents an SSH connection for both server and client roles.
|
|
||||||
// Conn is the basis for implementing an application layer, such
|
|
||||||
// as ClientConn, which implements the traditional shell access for
|
|
||||||
// clients.
|
|
||||||
type Conn interface {
|
|
||||||
ConnMetadata
|
|
||||||
|
|
||||||
// SendRequest sends a global request, and returns the
|
|
||||||
// reply. If wantReply is true, it returns the response status
|
|
||||||
// and payload. See also RFC4254, section 4.
|
|
||||||
SendRequest(name string, wantReply bool, payload []byte) (bool, []byte, error)
|
|
||||||
|
|
||||||
// OpenChannel tries to open an channel. If the request is
|
|
||||||
// rejected, it returns *OpenChannelError. On success it returns
|
|
||||||
// the SSH Channel and a Go channel for incoming, out-of-band
|
|
||||||
// requests. The Go channel must be serviced, or the
|
|
||||||
// connection will hang.
|
|
||||||
OpenChannel(name string, data []byte) (Channel, <-chan *Request, error)
|
|
||||||
|
|
||||||
// Close closes the underlying network connection
|
|
||||||
Close() error
|
|
||||||
|
|
||||||
// Wait blocks until the connection has shut down, and returns the
|
|
||||||
// error causing the shutdown.
|
|
||||||
Wait() error
|
|
||||||
|
|
||||||
// TODO(hanwen): consider exposing:
|
|
||||||
// RequestKeyChange
|
|
||||||
// Disconnect
|
|
||||||
}
|
|
||||||
|
|
||||||
// DiscardRequests consumes and rejects all requests from the
|
|
||||||
// passed-in channel.
|
|
||||||
func DiscardRequests(in <-chan *Request) {
|
|
||||||
for req := range in {
|
|
||||||
if req.WantReply {
|
|
||||||
req.Reply(false, nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// A connection represents an incoming connection.
|
|
||||||
type connection struct {
|
|
||||||
transport *handshakeTransport
|
|
||||||
sshConn
|
|
||||||
|
|
||||||
// The connection protocol.
|
|
||||||
*mux
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *connection) Close() error {
|
|
||||||
return c.sshConn.conn.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
// sshconn provides net.Conn metadata, but disallows direct reads and
|
|
||||||
// writes.
|
|
||||||
type sshConn struct {
|
|
||||||
conn net.Conn
|
|
||||||
|
|
||||||
user string
|
|
||||||
sessionID []byte
|
|
||||||
clientVersion []byte
|
|
||||||
serverVersion []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func dup(src []byte) []byte {
|
|
||||||
dst := make([]byte, len(src))
|
|
||||||
copy(dst, src)
|
|
||||||
return dst
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *sshConn) User() string {
|
|
||||||
return c.user
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *sshConn) RemoteAddr() net.Addr {
|
|
||||||
return c.conn.RemoteAddr()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *sshConn) Close() error {
|
|
||||||
return c.conn.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *sshConn) LocalAddr() net.Addr {
|
|
||||||
return c.conn.LocalAddr()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *sshConn) SessionID() []byte {
|
|
||||||
return dup(c.sessionID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *sshConn) ClientVersion() []byte {
|
|
||||||
return dup(c.clientVersion)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *sshConn) ServerVersion() []byte {
|
|
||||||
return dup(c.serverVersion)
|
|
||||||
}
|
|
21
vendor/golang.org/x/crypto/ssh/doc.go
generated
vendored
21
vendor/golang.org/x/crypto/ssh/doc.go
generated
vendored
@ -1,21 +0,0 @@
|
|||||||
// 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 ssh implements an SSH client and server.
|
|
||||||
|
|
||||||
SSH is a transport security protocol, an authentication protocol and a
|
|
||||||
family of application protocols. The most typical application level
|
|
||||||
protocol is a remote shell and this is specifically implemented. However,
|
|
||||||
the multiplexed nature of SSH is exposed to users that wish to support
|
|
||||||
others.
|
|
||||||
|
|
||||||
References:
|
|
||||||
[PROTOCOL.certkeys]: http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.certkeys?rev=HEAD
|
|
||||||
[SSH-PARAMETERS]: http://www.iana.org/assignments/ssh-parameters/ssh-parameters.xml#ssh-parameters-1
|
|
||||||
|
|
||||||
This package does not fall under the stability promise of the Go language itself,
|
|
||||||
so its API may be changed when pressing needs arise.
|
|
||||||
*/
|
|
||||||
package ssh // import "golang.org/x/crypto/ssh"
|
|
647
vendor/golang.org/x/crypto/ssh/handshake.go
generated
vendored
647
vendor/golang.org/x/crypto/ssh/handshake.go
generated
vendored
@ -1,647 +0,0 @@
|
|||||||
// Copyright 2013 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package ssh
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/rand"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"log"
|
|
||||||
"net"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
// debugHandshake, if set, prints messages sent and received. Key
|
|
||||||
// exchange messages are printed as if DH were used, so the debug
|
|
||||||
// messages are wrong when using ECDH.
|
|
||||||
const debugHandshake = false
|
|
||||||
|
|
||||||
// chanSize sets the amount of buffering SSH connections. This is
|
|
||||||
// primarily for testing: setting chanSize=0 uncovers deadlocks more
|
|
||||||
// quickly.
|
|
||||||
const chanSize = 16
|
|
||||||
|
|
||||||
// keyingTransport is a packet based transport that supports key
|
|
||||||
// changes. It need not be thread-safe. It should pass through
|
|
||||||
// msgNewKeys in both directions.
|
|
||||||
type keyingTransport interface {
|
|
||||||
packetConn
|
|
||||||
|
|
||||||
// prepareKeyChange sets up a key change. The key change for a
|
|
||||||
// direction will be effected if a msgNewKeys message is sent
|
|
||||||
// or received.
|
|
||||||
prepareKeyChange(*algorithms, *kexResult) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// handshakeTransport implements rekeying on top of a keyingTransport
|
|
||||||
// and offers a thread-safe writePacket() interface.
|
|
||||||
type handshakeTransport struct {
|
|
||||||
conn keyingTransport
|
|
||||||
config *Config
|
|
||||||
|
|
||||||
serverVersion []byte
|
|
||||||
clientVersion []byte
|
|
||||||
|
|
||||||
// hostKeys is non-empty if we are the server. In that case,
|
|
||||||
// it contains all host keys that can be used to sign the
|
|
||||||
// connection.
|
|
||||||
hostKeys []Signer
|
|
||||||
|
|
||||||
// hostKeyAlgorithms is non-empty if we are the client. In that case,
|
|
||||||
// we accept these key types from the server as host key.
|
|
||||||
hostKeyAlgorithms []string
|
|
||||||
|
|
||||||
// On read error, incoming is closed, and readError is set.
|
|
||||||
incoming chan []byte
|
|
||||||
readError error
|
|
||||||
|
|
||||||
mu sync.Mutex
|
|
||||||
writeError error
|
|
||||||
sentInitPacket []byte
|
|
||||||
sentInitMsg *kexInitMsg
|
|
||||||
pendingPackets [][]byte // Used when a key exchange is in progress.
|
|
||||||
|
|
||||||
// If the read loop wants to schedule a kex, it pings this
|
|
||||||
// channel, and the write loop will send out a kex
|
|
||||||
// message.
|
|
||||||
requestKex chan struct{}
|
|
||||||
|
|
||||||
// If the other side requests or confirms a kex, its kexInit
|
|
||||||
// packet is sent here for the write loop to find it.
|
|
||||||
startKex chan *pendingKex
|
|
||||||
|
|
||||||
// data for host key checking
|
|
||||||
hostKeyCallback HostKeyCallback
|
|
||||||
dialAddress string
|
|
||||||
remoteAddr net.Addr
|
|
||||||
|
|
||||||
// bannerCallback is non-empty if we are the client and it has been set in
|
|
||||||
// ClientConfig. In that case it is called during the user authentication
|
|
||||||
// dance to handle a custom server's message.
|
|
||||||
bannerCallback BannerCallback
|
|
||||||
|
|
||||||
// Algorithms agreed in the last key exchange.
|
|
||||||
algorithms *algorithms
|
|
||||||
|
|
||||||
readPacketsLeft uint32
|
|
||||||
readBytesLeft int64
|
|
||||||
|
|
||||||
writePacketsLeft uint32
|
|
||||||
writeBytesLeft int64
|
|
||||||
|
|
||||||
// The session ID or nil if first kex did not complete yet.
|
|
||||||
sessionID []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
type pendingKex struct {
|
|
||||||
otherInit []byte
|
|
||||||
done chan error
|
|
||||||
}
|
|
||||||
|
|
||||||
func newHandshakeTransport(conn keyingTransport, config *Config, clientVersion, serverVersion []byte) *handshakeTransport {
|
|
||||||
t := &handshakeTransport{
|
|
||||||
conn: conn,
|
|
||||||
serverVersion: serverVersion,
|
|
||||||
clientVersion: clientVersion,
|
|
||||||
incoming: make(chan []byte, chanSize),
|
|
||||||
requestKex: make(chan struct{}, 1),
|
|
||||||
startKex: make(chan *pendingKex, 1),
|
|
||||||
|
|
||||||
config: config,
|
|
||||||
}
|
|
||||||
t.resetReadThresholds()
|
|
||||||
t.resetWriteThresholds()
|
|
||||||
|
|
||||||
// We always start with a mandatory key exchange.
|
|
||||||
t.requestKex <- struct{}{}
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
func newClientTransport(conn keyingTransport, clientVersion, serverVersion []byte, config *ClientConfig, dialAddr string, addr net.Addr) *handshakeTransport {
|
|
||||||
t := newHandshakeTransport(conn, &config.Config, clientVersion, serverVersion)
|
|
||||||
t.dialAddress = dialAddr
|
|
||||||
t.remoteAddr = addr
|
|
||||||
t.hostKeyCallback = config.HostKeyCallback
|
|
||||||
t.bannerCallback = config.BannerCallback
|
|
||||||
if config.HostKeyAlgorithms != nil {
|
|
||||||
t.hostKeyAlgorithms = config.HostKeyAlgorithms
|
|
||||||
} else {
|
|
||||||
t.hostKeyAlgorithms = supportedHostKeyAlgos
|
|
||||||
}
|
|
||||||
go t.readLoop()
|
|
||||||
go t.kexLoop()
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
func newServerTransport(conn keyingTransport, clientVersion, serverVersion []byte, config *ServerConfig) *handshakeTransport {
|
|
||||||
t := newHandshakeTransport(conn, &config.Config, clientVersion, serverVersion)
|
|
||||||
t.hostKeys = config.hostKeys
|
|
||||||
go t.readLoop()
|
|
||||||
go t.kexLoop()
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *handshakeTransport) getSessionID() []byte {
|
|
||||||
return t.sessionID
|
|
||||||
}
|
|
||||||
|
|
||||||
// waitSession waits for the session to be established. This should be
|
|
||||||
// the first thing to call after instantiating handshakeTransport.
|
|
||||||
func (t *handshakeTransport) waitSession() error {
|
|
||||||
p, err := t.readPacket()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if p[0] != msgNewKeys {
|
|
||||||
return fmt.Errorf("ssh: first packet should be msgNewKeys")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *handshakeTransport) id() string {
|
|
||||||
if len(t.hostKeys) > 0 {
|
|
||||||
return "server"
|
|
||||||
}
|
|
||||||
return "client"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *handshakeTransport) printPacket(p []byte, write bool) {
|
|
||||||
action := "got"
|
|
||||||
if write {
|
|
||||||
action = "sent"
|
|
||||||
}
|
|
||||||
|
|
||||||
if p[0] == msgChannelData || p[0] == msgChannelExtendedData {
|
|
||||||
log.Printf("%s %s data (packet %d bytes)", t.id(), action, len(p))
|
|
||||||
} else {
|
|
||||||
msg, err := decode(p)
|
|
||||||
log.Printf("%s %s %T %v (%v)", t.id(), action, msg, msg, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *handshakeTransport) readPacket() ([]byte, error) {
|
|
||||||
p, ok := <-t.incoming
|
|
||||||
if !ok {
|
|
||||||
return nil, t.readError
|
|
||||||
}
|
|
||||||
return p, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *handshakeTransport) readLoop() {
|
|
||||||
first := true
|
|
||||||
for {
|
|
||||||
p, err := t.readOnePacket(first)
|
|
||||||
first = false
|
|
||||||
if err != nil {
|
|
||||||
t.readError = err
|
|
||||||
close(t.incoming)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if p[0] == msgIgnore || p[0] == msgDebug {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
t.incoming <- p
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stop writers too.
|
|
||||||
t.recordWriteError(t.readError)
|
|
||||||
|
|
||||||
// Unblock the writer should it wait for this.
|
|
||||||
close(t.startKex)
|
|
||||||
|
|
||||||
// Don't close t.requestKex; it's also written to from writePacket.
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *handshakeTransport) pushPacket(p []byte) error {
|
|
||||||
if debugHandshake {
|
|
||||||
t.printPacket(p, true)
|
|
||||||
}
|
|
||||||
return t.conn.writePacket(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *handshakeTransport) getWriteError() error {
|
|
||||||
t.mu.Lock()
|
|
||||||
defer t.mu.Unlock()
|
|
||||||
return t.writeError
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *handshakeTransport) recordWriteError(err error) {
|
|
||||||
t.mu.Lock()
|
|
||||||
defer t.mu.Unlock()
|
|
||||||
if t.writeError == nil && err != nil {
|
|
||||||
t.writeError = err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *handshakeTransport) requestKeyExchange() {
|
|
||||||
select {
|
|
||||||
case t.requestKex <- struct{}{}:
|
|
||||||
default:
|
|
||||||
// something already requested a kex, so do nothing.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *handshakeTransport) resetWriteThresholds() {
|
|
||||||
t.writePacketsLeft = packetRekeyThreshold
|
|
||||||
if t.config.RekeyThreshold > 0 {
|
|
||||||
t.writeBytesLeft = int64(t.config.RekeyThreshold)
|
|
||||||
} else if t.algorithms != nil {
|
|
||||||
t.writeBytesLeft = t.algorithms.w.rekeyBytes()
|
|
||||||
} else {
|
|
||||||
t.writeBytesLeft = 1 << 30
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *handshakeTransport) kexLoop() {
|
|
||||||
|
|
||||||
write:
|
|
||||||
for t.getWriteError() == nil {
|
|
||||||
var request *pendingKex
|
|
||||||
var sent bool
|
|
||||||
|
|
||||||
for request == nil || !sent {
|
|
||||||
var ok bool
|
|
||||||
select {
|
|
||||||
case request, ok = <-t.startKex:
|
|
||||||
if !ok {
|
|
||||||
break write
|
|
||||||
}
|
|
||||||
case <-t.requestKex:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
if !sent {
|
|
||||||
if err := t.sendKexInit(); err != nil {
|
|
||||||
t.recordWriteError(err)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
sent = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := t.getWriteError(); err != nil {
|
|
||||||
if request != nil {
|
|
||||||
request.done <- err
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
// We're not servicing t.requestKex, but that is OK:
|
|
||||||
// we never block on sending to t.requestKex.
|
|
||||||
|
|
||||||
// We're not servicing t.startKex, but the remote end
|
|
||||||
// has just sent us a kexInitMsg, so it can't send
|
|
||||||
// another key change request, until we close the done
|
|
||||||
// channel on the pendingKex request.
|
|
||||||
|
|
||||||
err := t.enterKeyExchange(request.otherInit)
|
|
||||||
|
|
||||||
t.mu.Lock()
|
|
||||||
t.writeError = err
|
|
||||||
t.sentInitPacket = nil
|
|
||||||
t.sentInitMsg = nil
|
|
||||||
|
|
||||||
t.resetWriteThresholds()
|
|
||||||
|
|
||||||
// we have completed the key exchange. Since the
|
|
||||||
// reader is still blocked, it is safe to clear out
|
|
||||||
// the requestKex channel. This avoids the situation
|
|
||||||
// where: 1) we consumed our own request for the
|
|
||||||
// initial kex, and 2) the kex from the remote side
|
|
||||||
// caused another send on the requestKex channel,
|
|
||||||
clear:
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-t.requestKex:
|
|
||||||
//
|
|
||||||
default:
|
|
||||||
break clear
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
request.done <- t.writeError
|
|
||||||
|
|
||||||
// kex finished. Push packets that we received while
|
|
||||||
// the kex was in progress. Don't look at t.startKex
|
|
||||||
// and don't increment writtenSinceKex: if we trigger
|
|
||||||
// another kex while we are still busy with the last
|
|
||||||
// one, things will become very confusing.
|
|
||||||
for _, p := range t.pendingPackets {
|
|
||||||
t.writeError = t.pushPacket(p)
|
|
||||||
if t.writeError != nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
t.pendingPackets = t.pendingPackets[:0]
|
|
||||||
t.mu.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
// drain startKex channel. We don't service t.requestKex
|
|
||||||
// because nobody does blocking sends there.
|
|
||||||
go func() {
|
|
||||||
for init := range t.startKex {
|
|
||||||
init.done <- t.writeError
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
// Unblock reader.
|
|
||||||
t.conn.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
// The protocol uses uint32 for packet counters, so we can't let them
|
|
||||||
// reach 1<<32. We will actually read and write more packets than
|
|
||||||
// this, though: the other side may send more packets, and after we
|
|
||||||
// hit this limit on writing we will send a few more packets for the
|
|
||||||
// key exchange itself.
|
|
||||||
const packetRekeyThreshold = (1 << 31)
|
|
||||||
|
|
||||||
func (t *handshakeTransport) resetReadThresholds() {
|
|
||||||
t.readPacketsLeft = packetRekeyThreshold
|
|
||||||
if t.config.RekeyThreshold > 0 {
|
|
||||||
t.readBytesLeft = int64(t.config.RekeyThreshold)
|
|
||||||
} else if t.algorithms != nil {
|
|
||||||
t.readBytesLeft = t.algorithms.r.rekeyBytes()
|
|
||||||
} else {
|
|
||||||
t.readBytesLeft = 1 << 30
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *handshakeTransport) readOnePacket(first bool) ([]byte, error) {
|
|
||||||
p, err := t.conn.readPacket()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if t.readPacketsLeft > 0 {
|
|
||||||
t.readPacketsLeft--
|
|
||||||
} else {
|
|
||||||
t.requestKeyExchange()
|
|
||||||
}
|
|
||||||
|
|
||||||
if t.readBytesLeft > 0 {
|
|
||||||
t.readBytesLeft -= int64(len(p))
|
|
||||||
} else {
|
|
||||||
t.requestKeyExchange()
|
|
||||||
}
|
|
||||||
|
|
||||||
if debugHandshake {
|
|
||||||
t.printPacket(p, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
if first && p[0] != msgKexInit {
|
|
||||||
return nil, fmt.Errorf("ssh: first packet should be msgKexInit")
|
|
||||||
}
|
|
||||||
|
|
||||||
if p[0] != msgKexInit {
|
|
||||||
return p, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
firstKex := t.sessionID == nil
|
|
||||||
|
|
||||||
kex := pendingKex{
|
|
||||||
done: make(chan error, 1),
|
|
||||||
otherInit: p,
|
|
||||||
}
|
|
||||||
t.startKex <- &kex
|
|
||||||
err = <-kex.done
|
|
||||||
|
|
||||||
if debugHandshake {
|
|
||||||
log.Printf("%s exited key exchange (first %v), err %v", t.id(), firstKex, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
t.resetReadThresholds()
|
|
||||||
|
|
||||||
// By default, a key exchange is hidden from higher layers by
|
|
||||||
// translating it into msgIgnore.
|
|
||||||
successPacket := []byte{msgIgnore}
|
|
||||||
if firstKex {
|
|
||||||
// sendKexInit() for the first kex waits for
|
|
||||||
// msgNewKeys so the authentication process is
|
|
||||||
// guaranteed to happen over an encrypted transport.
|
|
||||||
successPacket = []byte{msgNewKeys}
|
|
||||||
}
|
|
||||||
|
|
||||||
return successPacket, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// sendKexInit sends a key change message.
|
|
||||||
func (t *handshakeTransport) sendKexInit() error {
|
|
||||||
t.mu.Lock()
|
|
||||||
defer t.mu.Unlock()
|
|
||||||
if t.sentInitMsg != nil {
|
|
||||||
// kexInits may be sent either in response to the other side,
|
|
||||||
// or because our side wants to initiate a key change, so we
|
|
||||||
// may have already sent a kexInit. In that case, don't send a
|
|
||||||
// second kexInit.
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
msg := &kexInitMsg{
|
|
||||||
KexAlgos: t.config.KeyExchanges,
|
|
||||||
CiphersClientServer: t.config.Ciphers,
|
|
||||||
CiphersServerClient: t.config.Ciphers,
|
|
||||||
MACsClientServer: t.config.MACs,
|
|
||||||
MACsServerClient: t.config.MACs,
|
|
||||||
CompressionClientServer: supportedCompressions,
|
|
||||||
CompressionServerClient: supportedCompressions,
|
|
||||||
}
|
|
||||||
io.ReadFull(rand.Reader, msg.Cookie[:])
|
|
||||||
|
|
||||||
if len(t.hostKeys) > 0 {
|
|
||||||
for _, k := range t.hostKeys {
|
|
||||||
msg.ServerHostKeyAlgos = append(
|
|
||||||
msg.ServerHostKeyAlgos, k.PublicKey().Type())
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
msg.ServerHostKeyAlgos = t.hostKeyAlgorithms
|
|
||||||
}
|
|
||||||
packet := Marshal(msg)
|
|
||||||
|
|
||||||
// writePacket destroys the contents, so save a copy.
|
|
||||||
packetCopy := make([]byte, len(packet))
|
|
||||||
copy(packetCopy, packet)
|
|
||||||
|
|
||||||
if err := t.pushPacket(packetCopy); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
t.sentInitMsg = msg
|
|
||||||
t.sentInitPacket = packet
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *handshakeTransport) writePacket(p []byte) error {
|
|
||||||
switch p[0] {
|
|
||||||
case msgKexInit:
|
|
||||||
return errors.New("ssh: only handshakeTransport can send kexInit")
|
|
||||||
case msgNewKeys:
|
|
||||||
return errors.New("ssh: only handshakeTransport can send newKeys")
|
|
||||||
}
|
|
||||||
|
|
||||||
t.mu.Lock()
|
|
||||||
defer t.mu.Unlock()
|
|
||||||
if t.writeError != nil {
|
|
||||||
return t.writeError
|
|
||||||
}
|
|
||||||
|
|
||||||
if t.sentInitMsg != nil {
|
|
||||||
// Copy the packet so the writer can reuse the buffer.
|
|
||||||
cp := make([]byte, len(p))
|
|
||||||
copy(cp, p)
|
|
||||||
t.pendingPackets = append(t.pendingPackets, cp)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if t.writeBytesLeft > 0 {
|
|
||||||
t.writeBytesLeft -= int64(len(p))
|
|
||||||
} else {
|
|
||||||
t.requestKeyExchange()
|
|
||||||
}
|
|
||||||
|
|
||||||
if t.writePacketsLeft > 0 {
|
|
||||||
t.writePacketsLeft--
|
|
||||||
} else {
|
|
||||||
t.requestKeyExchange()
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := t.pushPacket(p); err != nil {
|
|
||||||
t.writeError = err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *handshakeTransport) Close() error {
|
|
||||||
return t.conn.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error {
|
|
||||||
if debugHandshake {
|
|
||||||
log.Printf("%s entered key exchange", t.id())
|
|
||||||
}
|
|
||||||
|
|
||||||
otherInit := &kexInitMsg{}
|
|
||||||
if err := Unmarshal(otherInitPacket, otherInit); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
magics := handshakeMagics{
|
|
||||||
clientVersion: t.clientVersion,
|
|
||||||
serverVersion: t.serverVersion,
|
|
||||||
clientKexInit: otherInitPacket,
|
|
||||||
serverKexInit: t.sentInitPacket,
|
|
||||||
}
|
|
||||||
|
|
||||||
clientInit := otherInit
|
|
||||||
serverInit := t.sentInitMsg
|
|
||||||
isClient := len(t.hostKeys) == 0
|
|
||||||
if isClient {
|
|
||||||
clientInit, serverInit = serverInit, clientInit
|
|
||||||
|
|
||||||
magics.clientKexInit = t.sentInitPacket
|
|
||||||
magics.serverKexInit = otherInitPacket
|
|
||||||
}
|
|
||||||
|
|
||||||
var err error
|
|
||||||
t.algorithms, err = findAgreedAlgorithms(isClient, clientInit, serverInit)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// We don't send FirstKexFollows, but we handle receiving it.
|
|
||||||
//
|
|
||||||
// RFC 4253 section 7 defines the kex and the agreement method for
|
|
||||||
// first_kex_packet_follows. It states that the guessed packet
|
|
||||||
// should be ignored if the "kex algorithm and/or the host
|
|
||||||
// key algorithm is guessed wrong (server and client have
|
|
||||||
// different preferred algorithm), or if any of the other
|
|
||||||
// algorithms cannot be agreed upon". The other algorithms have
|
|
||||||
// already been checked above so the kex algorithm and host key
|
|
||||||
// algorithm are checked here.
|
|
||||||
if otherInit.FirstKexFollows && (clientInit.KexAlgos[0] != serverInit.KexAlgos[0] || clientInit.ServerHostKeyAlgos[0] != serverInit.ServerHostKeyAlgos[0]) {
|
|
||||||
// other side sent a kex message for the wrong algorithm,
|
|
||||||
// which we have to ignore.
|
|
||||||
if _, err := t.conn.readPacket(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
kex, ok := kexAlgoMap[t.algorithms.kex]
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("ssh: unexpected key exchange algorithm %v", t.algorithms.kex)
|
|
||||||
}
|
|
||||||
|
|
||||||
var result *kexResult
|
|
||||||
if len(t.hostKeys) > 0 {
|
|
||||||
result, err = t.server(kex, t.algorithms, &magics)
|
|
||||||
} else {
|
|
||||||
result, err = t.client(kex, t.algorithms, &magics)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if t.sessionID == nil {
|
|
||||||
t.sessionID = result.H
|
|
||||||
}
|
|
||||||
result.SessionID = t.sessionID
|
|
||||||
|
|
||||||
if err := t.conn.prepareKeyChange(t.algorithms, result); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err = t.conn.writePacket([]byte{msgNewKeys}); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if packet, err := t.conn.readPacket(); err != nil {
|
|
||||||
return err
|
|
||||||
} else if packet[0] != msgNewKeys {
|
|
||||||
return unexpectedMessageError(msgNewKeys, packet[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *handshakeTransport) server(kex kexAlgorithm, algs *algorithms, magics *handshakeMagics) (*kexResult, error) {
|
|
||||||
var hostKey Signer
|
|
||||||
for _, k := range t.hostKeys {
|
|
||||||
if algs.hostKey == k.PublicKey().Type() {
|
|
||||||
hostKey = k
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
r, err := kex.Server(t.conn, t.config.Rand, magics, hostKey)
|
|
||||||
return r, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *handshakeTransport) client(kex kexAlgorithm, algs *algorithms, magics *handshakeMagics) (*kexResult, error) {
|
|
||||||
result, err := kex.Client(t.conn, t.config.Rand, magics)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
hostKey, err := ParsePublicKey(result.HostKey)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := verifyHostKeySignature(hostKey, result); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = t.hostKeyCallback(t.dialAddress, t.remoteAddr, hostKey)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return result, nil
|
|
||||||
}
|
|
789
vendor/golang.org/x/crypto/ssh/kex.go
generated
vendored
789
vendor/golang.org/x/crypto/ssh/kex.go
generated
vendored
@ -1,789 +0,0 @@
|
|||||||
// Copyright 2013 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package ssh
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto"
|
|
||||||
"crypto/ecdsa"
|
|
||||||
"crypto/elliptic"
|
|
||||||
"crypto/rand"
|
|
||||||
"crypto/subtle"
|
|
||||||
"encoding/binary"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"math/big"
|
|
||||||
|
|
||||||
"golang.org/x/crypto/curve25519"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
kexAlgoDH1SHA1 = "diffie-hellman-group1-sha1"
|
|
||||||
kexAlgoDH14SHA1 = "diffie-hellman-group14-sha1"
|
|
||||||
kexAlgoECDH256 = "ecdh-sha2-nistp256"
|
|
||||||
kexAlgoECDH384 = "ecdh-sha2-nistp384"
|
|
||||||
kexAlgoECDH521 = "ecdh-sha2-nistp521"
|
|
||||||
kexAlgoCurve25519SHA256 = "curve25519-sha256@libssh.org"
|
|
||||||
|
|
||||||
// For the following kex only the client half contains a production
|
|
||||||
// ready implementation. The server half only consists of a minimal
|
|
||||||
// implementation to satisfy the automated tests.
|
|
||||||
kexAlgoDHGEXSHA1 = "diffie-hellman-group-exchange-sha1"
|
|
||||||
kexAlgoDHGEXSHA256 = "diffie-hellman-group-exchange-sha256"
|
|
||||||
)
|
|
||||||
|
|
||||||
// kexResult captures the outcome of a key exchange.
|
|
||||||
type kexResult struct {
|
|
||||||
// Session hash. See also RFC 4253, section 8.
|
|
||||||
H []byte
|
|
||||||
|
|
||||||
// Shared secret. See also RFC 4253, section 8.
|
|
||||||
K []byte
|
|
||||||
|
|
||||||
// Host key as hashed into H.
|
|
||||||
HostKey []byte
|
|
||||||
|
|
||||||
// Signature of H.
|
|
||||||
Signature []byte
|
|
||||||
|
|
||||||
// A cryptographic hash function that matches the security
|
|
||||||
// level of the key exchange algorithm. It is used for
|
|
||||||
// calculating H, and for deriving keys from H and K.
|
|
||||||
Hash crypto.Hash
|
|
||||||
|
|
||||||
// The session ID, which is the first H computed. This is used
|
|
||||||
// to derive key material inside the transport.
|
|
||||||
SessionID []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
// handshakeMagics contains data that is always included in the
|
|
||||||
// session hash.
|
|
||||||
type handshakeMagics struct {
|
|
||||||
clientVersion, serverVersion []byte
|
|
||||||
clientKexInit, serverKexInit []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *handshakeMagics) write(w io.Writer) {
|
|
||||||
writeString(w, m.clientVersion)
|
|
||||||
writeString(w, m.serverVersion)
|
|
||||||
writeString(w, m.clientKexInit)
|
|
||||||
writeString(w, m.serverKexInit)
|
|
||||||
}
|
|
||||||
|
|
||||||
// kexAlgorithm abstracts different key exchange algorithms.
|
|
||||||
type kexAlgorithm interface {
|
|
||||||
// Server runs server-side key agreement, signing the result
|
|
||||||
// with a hostkey.
|
|
||||||
Server(p packetConn, rand io.Reader, magics *handshakeMagics, s Signer) (*kexResult, error)
|
|
||||||
|
|
||||||
// Client runs the client-side key agreement. Caller is
|
|
||||||
// responsible for verifying the host key signature.
|
|
||||||
Client(p packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// dhGroup is a multiplicative group suitable for implementing Diffie-Hellman key agreement.
|
|
||||||
type dhGroup struct {
|
|
||||||
g, p, pMinus1 *big.Int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (group *dhGroup) diffieHellman(theirPublic, myPrivate *big.Int) (*big.Int, error) {
|
|
||||||
if theirPublic.Cmp(bigOne) <= 0 || theirPublic.Cmp(group.pMinus1) >= 0 {
|
|
||||||
return nil, errors.New("ssh: DH parameter out of bounds")
|
|
||||||
}
|
|
||||||
return new(big.Int).Exp(theirPublic, myPrivate, group.p), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (group *dhGroup) Client(c packetConn, randSource io.Reader, magics *handshakeMagics) (*kexResult, error) {
|
|
||||||
hashFunc := crypto.SHA1
|
|
||||||
|
|
||||||
var x *big.Int
|
|
||||||
for {
|
|
||||||
var err error
|
|
||||||
if x, err = rand.Int(randSource, group.pMinus1); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if x.Sign() > 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
X := new(big.Int).Exp(group.g, x, group.p)
|
|
||||||
kexDHInit := kexDHInitMsg{
|
|
||||||
X: X,
|
|
||||||
}
|
|
||||||
if err := c.writePacket(Marshal(&kexDHInit)); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
packet, err := c.readPacket()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var kexDHReply kexDHReplyMsg
|
|
||||||
if err = Unmarshal(packet, &kexDHReply); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
ki, err := group.diffieHellman(kexDHReply.Y, x)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
h := hashFunc.New()
|
|
||||||
magics.write(h)
|
|
||||||
writeString(h, kexDHReply.HostKey)
|
|
||||||
writeInt(h, X)
|
|
||||||
writeInt(h, kexDHReply.Y)
|
|
||||||
K := make([]byte, intLength(ki))
|
|
||||||
marshalInt(K, ki)
|
|
||||||
h.Write(K)
|
|
||||||
|
|
||||||
return &kexResult{
|
|
||||||
H: h.Sum(nil),
|
|
||||||
K: K,
|
|
||||||
HostKey: kexDHReply.HostKey,
|
|
||||||
Signature: kexDHReply.Signature,
|
|
||||||
Hash: crypto.SHA1,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (group *dhGroup) Server(c packetConn, randSource io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) {
|
|
||||||
hashFunc := crypto.SHA1
|
|
||||||
packet, err := c.readPacket()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var kexDHInit kexDHInitMsg
|
|
||||||
if err = Unmarshal(packet, &kexDHInit); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var y *big.Int
|
|
||||||
for {
|
|
||||||
if y, err = rand.Int(randSource, group.pMinus1); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if y.Sign() > 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Y := new(big.Int).Exp(group.g, y, group.p)
|
|
||||||
ki, err := group.diffieHellman(kexDHInit.X, y)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
hostKeyBytes := priv.PublicKey().Marshal()
|
|
||||||
|
|
||||||
h := hashFunc.New()
|
|
||||||
magics.write(h)
|
|
||||||
writeString(h, hostKeyBytes)
|
|
||||||
writeInt(h, kexDHInit.X)
|
|
||||||
writeInt(h, Y)
|
|
||||||
|
|
||||||
K := make([]byte, intLength(ki))
|
|
||||||
marshalInt(K, ki)
|
|
||||||
h.Write(K)
|
|
||||||
|
|
||||||
H := h.Sum(nil)
|
|
||||||
|
|
||||||
// H is already a hash, but the hostkey signing will apply its
|
|
||||||
// own key-specific hash algorithm.
|
|
||||||
sig, err := signAndMarshal(priv, randSource, H)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
kexDHReply := kexDHReplyMsg{
|
|
||||||
HostKey: hostKeyBytes,
|
|
||||||
Y: Y,
|
|
||||||
Signature: sig,
|
|
||||||
}
|
|
||||||
packet = Marshal(&kexDHReply)
|
|
||||||
|
|
||||||
err = c.writePacket(packet)
|
|
||||||
return &kexResult{
|
|
||||||
H: H,
|
|
||||||
K: K,
|
|
||||||
HostKey: hostKeyBytes,
|
|
||||||
Signature: sig,
|
|
||||||
Hash: crypto.SHA1,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ecdh performs Elliptic Curve Diffie-Hellman key exchange as
|
|
||||||
// described in RFC 5656, section 4.
|
|
||||||
type ecdh struct {
|
|
||||||
curve elliptic.Curve
|
|
||||||
}
|
|
||||||
|
|
||||||
func (kex *ecdh) Client(c packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) {
|
|
||||||
ephKey, err := ecdsa.GenerateKey(kex.curve, rand)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
kexInit := kexECDHInitMsg{
|
|
||||||
ClientPubKey: elliptic.Marshal(kex.curve, ephKey.PublicKey.X, ephKey.PublicKey.Y),
|
|
||||||
}
|
|
||||||
|
|
||||||
serialized := Marshal(&kexInit)
|
|
||||||
if err := c.writePacket(serialized); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
packet, err := c.readPacket()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var reply kexECDHReplyMsg
|
|
||||||
if err = Unmarshal(packet, &reply); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
x, y, err := unmarshalECKey(kex.curve, reply.EphemeralPubKey)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// generate shared secret
|
|
||||||
secret, _ := kex.curve.ScalarMult(x, y, ephKey.D.Bytes())
|
|
||||||
|
|
||||||
h := ecHash(kex.curve).New()
|
|
||||||
magics.write(h)
|
|
||||||
writeString(h, reply.HostKey)
|
|
||||||
writeString(h, kexInit.ClientPubKey)
|
|
||||||
writeString(h, reply.EphemeralPubKey)
|
|
||||||
K := make([]byte, intLength(secret))
|
|
||||||
marshalInt(K, secret)
|
|
||||||
h.Write(K)
|
|
||||||
|
|
||||||
return &kexResult{
|
|
||||||
H: h.Sum(nil),
|
|
||||||
K: K,
|
|
||||||
HostKey: reply.HostKey,
|
|
||||||
Signature: reply.Signature,
|
|
||||||
Hash: ecHash(kex.curve),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// unmarshalECKey parses and checks an EC key.
|
|
||||||
func unmarshalECKey(curve elliptic.Curve, pubkey []byte) (x, y *big.Int, err error) {
|
|
||||||
x, y = elliptic.Unmarshal(curve, pubkey)
|
|
||||||
if x == nil {
|
|
||||||
return nil, nil, errors.New("ssh: elliptic.Unmarshal failure")
|
|
||||||
}
|
|
||||||
if !validateECPublicKey(curve, x, y) {
|
|
||||||
return nil, nil, errors.New("ssh: public key not on curve")
|
|
||||||
}
|
|
||||||
return x, y, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// validateECPublicKey checks that the point is a valid public key for
|
|
||||||
// the given curve. See [SEC1], 3.2.2
|
|
||||||
func validateECPublicKey(curve elliptic.Curve, x, y *big.Int) bool {
|
|
||||||
if x.Sign() == 0 && y.Sign() == 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if x.Cmp(curve.Params().P) >= 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if y.Cmp(curve.Params().P) >= 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if !curve.IsOnCurve(x, y) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// We don't check if N * PubKey == 0, since
|
|
||||||
//
|
|
||||||
// - the NIST curves have cofactor = 1, so this is implicit.
|
|
||||||
// (We don't foresee an implementation that supports non NIST
|
|
||||||
// curves)
|
|
||||||
//
|
|
||||||
// - for ephemeral keys, we don't need to worry about small
|
|
||||||
// subgroup attacks.
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (kex *ecdh) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) {
|
|
||||||
packet, err := c.readPacket()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var kexECDHInit kexECDHInitMsg
|
|
||||||
if err = Unmarshal(packet, &kexECDHInit); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
clientX, clientY, err := unmarshalECKey(kex.curve, kexECDHInit.ClientPubKey)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// We could cache this key across multiple users/multiple
|
|
||||||
// connection attempts, but the benefit is small. OpenSSH
|
|
||||||
// generates a new key for each incoming connection.
|
|
||||||
ephKey, err := ecdsa.GenerateKey(kex.curve, rand)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
hostKeyBytes := priv.PublicKey().Marshal()
|
|
||||||
|
|
||||||
serializedEphKey := elliptic.Marshal(kex.curve, ephKey.PublicKey.X, ephKey.PublicKey.Y)
|
|
||||||
|
|
||||||
// generate shared secret
|
|
||||||
secret, _ := kex.curve.ScalarMult(clientX, clientY, ephKey.D.Bytes())
|
|
||||||
|
|
||||||
h := ecHash(kex.curve).New()
|
|
||||||
magics.write(h)
|
|
||||||
writeString(h, hostKeyBytes)
|
|
||||||
writeString(h, kexECDHInit.ClientPubKey)
|
|
||||||
writeString(h, serializedEphKey)
|
|
||||||
|
|
||||||
K := make([]byte, intLength(secret))
|
|
||||||
marshalInt(K, secret)
|
|
||||||
h.Write(K)
|
|
||||||
|
|
||||||
H := h.Sum(nil)
|
|
||||||
|
|
||||||
// H is already a hash, but the hostkey signing will apply its
|
|
||||||
// own key-specific hash algorithm.
|
|
||||||
sig, err := signAndMarshal(priv, rand, H)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
reply := kexECDHReplyMsg{
|
|
||||||
EphemeralPubKey: serializedEphKey,
|
|
||||||
HostKey: hostKeyBytes,
|
|
||||||
Signature: sig,
|
|
||||||
}
|
|
||||||
|
|
||||||
serialized := Marshal(&reply)
|
|
||||||
if err := c.writePacket(serialized); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &kexResult{
|
|
||||||
H: H,
|
|
||||||
K: K,
|
|
||||||
HostKey: reply.HostKey,
|
|
||||||
Signature: sig,
|
|
||||||
Hash: ecHash(kex.curve),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var kexAlgoMap = map[string]kexAlgorithm{}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
// This is the group called diffie-hellman-group1-sha1 in RFC
|
|
||||||
// 4253 and Oakley Group 2 in RFC 2409.
|
|
||||||
p, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF", 16)
|
|
||||||
kexAlgoMap[kexAlgoDH1SHA1] = &dhGroup{
|
|
||||||
g: new(big.Int).SetInt64(2),
|
|
||||||
p: p,
|
|
||||||
pMinus1: new(big.Int).Sub(p, bigOne),
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is the group called diffie-hellman-group14-sha1 in RFC
|
|
||||||
// 4253 and Oakley Group 14 in RFC 3526.
|
|
||||||
p, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", 16)
|
|
||||||
|
|
||||||
kexAlgoMap[kexAlgoDH14SHA1] = &dhGroup{
|
|
||||||
g: new(big.Int).SetInt64(2),
|
|
||||||
p: p,
|
|
||||||
pMinus1: new(big.Int).Sub(p, bigOne),
|
|
||||||
}
|
|
||||||
|
|
||||||
kexAlgoMap[kexAlgoECDH521] = &ecdh{elliptic.P521()}
|
|
||||||
kexAlgoMap[kexAlgoECDH384] = &ecdh{elliptic.P384()}
|
|
||||||
kexAlgoMap[kexAlgoECDH256] = &ecdh{elliptic.P256()}
|
|
||||||
kexAlgoMap[kexAlgoCurve25519SHA256] = &curve25519sha256{}
|
|
||||||
kexAlgoMap[kexAlgoDHGEXSHA1] = &dhGEXSHA{hashFunc: crypto.SHA1}
|
|
||||||
kexAlgoMap[kexAlgoDHGEXSHA256] = &dhGEXSHA{hashFunc: crypto.SHA256}
|
|
||||||
}
|
|
||||||
|
|
||||||
// curve25519sha256 implements the curve25519-sha256@libssh.org key
|
|
||||||
// agreement protocol, as described in
|
|
||||||
// https://git.libssh.org/projects/libssh.git/tree/doc/curve25519-sha256@libssh.org.txt
|
|
||||||
type curve25519sha256 struct{}
|
|
||||||
|
|
||||||
type curve25519KeyPair struct {
|
|
||||||
priv [32]byte
|
|
||||||
pub [32]byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func (kp *curve25519KeyPair) generate(rand io.Reader) error {
|
|
||||||
if _, err := io.ReadFull(rand, kp.priv[:]); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
curve25519.ScalarBaseMult(&kp.pub, &kp.priv)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// curve25519Zeros is just an array of 32 zero bytes so that we have something
|
|
||||||
// convenient to compare against in order to reject curve25519 points with the
|
|
||||||
// wrong order.
|
|
||||||
var curve25519Zeros [32]byte
|
|
||||||
|
|
||||||
func (kex *curve25519sha256) Client(c packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) {
|
|
||||||
var kp curve25519KeyPair
|
|
||||||
if err := kp.generate(rand); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := c.writePacket(Marshal(&kexECDHInitMsg{kp.pub[:]})); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
packet, err := c.readPacket()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var reply kexECDHReplyMsg
|
|
||||||
if err = Unmarshal(packet, &reply); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if len(reply.EphemeralPubKey) != 32 {
|
|
||||||
return nil, errors.New("ssh: peer's curve25519 public value has wrong length")
|
|
||||||
}
|
|
||||||
|
|
||||||
var servPub, secret [32]byte
|
|
||||||
copy(servPub[:], reply.EphemeralPubKey)
|
|
||||||
curve25519.ScalarMult(&secret, &kp.priv, &servPub)
|
|
||||||
if subtle.ConstantTimeCompare(secret[:], curve25519Zeros[:]) == 1 {
|
|
||||||
return nil, errors.New("ssh: peer's curve25519 public value has wrong order")
|
|
||||||
}
|
|
||||||
|
|
||||||
h := crypto.SHA256.New()
|
|
||||||
magics.write(h)
|
|
||||||
writeString(h, reply.HostKey)
|
|
||||||
writeString(h, kp.pub[:])
|
|
||||||
writeString(h, reply.EphemeralPubKey)
|
|
||||||
|
|
||||||
ki := new(big.Int).SetBytes(secret[:])
|
|
||||||
K := make([]byte, intLength(ki))
|
|
||||||
marshalInt(K, ki)
|
|
||||||
h.Write(K)
|
|
||||||
|
|
||||||
return &kexResult{
|
|
||||||
H: h.Sum(nil),
|
|
||||||
K: K,
|
|
||||||
HostKey: reply.HostKey,
|
|
||||||
Signature: reply.Signature,
|
|
||||||
Hash: crypto.SHA256,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (kex *curve25519sha256) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) {
|
|
||||||
packet, err := c.readPacket()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var kexInit kexECDHInitMsg
|
|
||||||
if err = Unmarshal(packet, &kexInit); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(kexInit.ClientPubKey) != 32 {
|
|
||||||
return nil, errors.New("ssh: peer's curve25519 public value has wrong length")
|
|
||||||
}
|
|
||||||
|
|
||||||
var kp curve25519KeyPair
|
|
||||||
if err := kp.generate(rand); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var clientPub, secret [32]byte
|
|
||||||
copy(clientPub[:], kexInit.ClientPubKey)
|
|
||||||
curve25519.ScalarMult(&secret, &kp.priv, &clientPub)
|
|
||||||
if subtle.ConstantTimeCompare(secret[:], curve25519Zeros[:]) == 1 {
|
|
||||||
return nil, errors.New("ssh: peer's curve25519 public value has wrong order")
|
|
||||||
}
|
|
||||||
|
|
||||||
hostKeyBytes := priv.PublicKey().Marshal()
|
|
||||||
|
|
||||||
h := crypto.SHA256.New()
|
|
||||||
magics.write(h)
|
|
||||||
writeString(h, hostKeyBytes)
|
|
||||||
writeString(h, kexInit.ClientPubKey)
|
|
||||||
writeString(h, kp.pub[:])
|
|
||||||
|
|
||||||
ki := new(big.Int).SetBytes(secret[:])
|
|
||||||
K := make([]byte, intLength(ki))
|
|
||||||
marshalInt(K, ki)
|
|
||||||
h.Write(K)
|
|
||||||
|
|
||||||
H := h.Sum(nil)
|
|
||||||
|
|
||||||
sig, err := signAndMarshal(priv, rand, H)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
reply := kexECDHReplyMsg{
|
|
||||||
EphemeralPubKey: kp.pub[:],
|
|
||||||
HostKey: hostKeyBytes,
|
|
||||||
Signature: sig,
|
|
||||||
}
|
|
||||||
if err := c.writePacket(Marshal(&reply)); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &kexResult{
|
|
||||||
H: H,
|
|
||||||
K: K,
|
|
||||||
HostKey: hostKeyBytes,
|
|
||||||
Signature: sig,
|
|
||||||
Hash: crypto.SHA256,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// dhGEXSHA implements the diffie-hellman-group-exchange-sha1 and
|
|
||||||
// diffie-hellman-group-exchange-sha256 key agreement protocols,
|
|
||||||
// as described in RFC 4419
|
|
||||||
type dhGEXSHA struct {
|
|
||||||
g, p *big.Int
|
|
||||||
hashFunc crypto.Hash
|
|
||||||
}
|
|
||||||
|
|
||||||
const numMRTests = 64
|
|
||||||
|
|
||||||
const (
|
|
||||||
dhGroupExchangeMinimumBits = 2048
|
|
||||||
dhGroupExchangePreferredBits = 2048
|
|
||||||
dhGroupExchangeMaximumBits = 8192
|
|
||||||
)
|
|
||||||
|
|
||||||
func (gex *dhGEXSHA) diffieHellman(theirPublic, myPrivate *big.Int) (*big.Int, error) {
|
|
||||||
if theirPublic.Sign() <= 0 || theirPublic.Cmp(gex.p) >= 0 {
|
|
||||||
return nil, fmt.Errorf("ssh: DH parameter out of bounds")
|
|
||||||
}
|
|
||||||
return new(big.Int).Exp(theirPublic, myPrivate, gex.p), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gex *dhGEXSHA) Client(c packetConn, randSource io.Reader, magics *handshakeMagics) (*kexResult, error) {
|
|
||||||
// Send GexRequest
|
|
||||||
kexDHGexRequest := kexDHGexRequestMsg{
|
|
||||||
MinBits: dhGroupExchangeMinimumBits,
|
|
||||||
PreferedBits: dhGroupExchangePreferredBits,
|
|
||||||
MaxBits: dhGroupExchangeMaximumBits,
|
|
||||||
}
|
|
||||||
if err := c.writePacket(Marshal(&kexDHGexRequest)); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Receive GexGroup
|
|
||||||
packet, err := c.readPacket()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var kexDHGexGroup kexDHGexGroupMsg
|
|
||||||
if err = Unmarshal(packet, &kexDHGexGroup); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// reject if p's bit length < dhGroupExchangeMinimumBits or > dhGroupExchangeMaximumBits
|
|
||||||
if kexDHGexGroup.P.BitLen() < dhGroupExchangeMinimumBits || kexDHGexGroup.P.BitLen() > dhGroupExchangeMaximumBits {
|
|
||||||
return nil, fmt.Errorf("ssh: server-generated gex p is out of range (%d bits)", kexDHGexGroup.P.BitLen())
|
|
||||||
}
|
|
||||||
|
|
||||||
gex.p = kexDHGexGroup.P
|
|
||||||
gex.g = kexDHGexGroup.G
|
|
||||||
|
|
||||||
// Check if p is safe by verifing that p and (p-1)/2 are primes
|
|
||||||
one := big.NewInt(1)
|
|
||||||
var pHalf = &big.Int{}
|
|
||||||
pHalf.Rsh(gex.p, 1)
|
|
||||||
if !gex.p.ProbablyPrime(numMRTests) || !pHalf.ProbablyPrime(numMRTests) {
|
|
||||||
return nil, fmt.Errorf("ssh: server provided gex p is not safe")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if g is safe by verifing that g > 1 and g < p - 1
|
|
||||||
var pMinusOne = &big.Int{}
|
|
||||||
pMinusOne.Sub(gex.p, one)
|
|
||||||
if gex.g.Cmp(one) != 1 && gex.g.Cmp(pMinusOne) != -1 {
|
|
||||||
return nil, fmt.Errorf("ssh: server provided gex g is not safe")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send GexInit
|
|
||||||
x, err := rand.Int(randSource, pHalf)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
X := new(big.Int).Exp(gex.g, x, gex.p)
|
|
||||||
kexDHGexInit := kexDHGexInitMsg{
|
|
||||||
X: X,
|
|
||||||
}
|
|
||||||
if err := c.writePacket(Marshal(&kexDHGexInit)); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Receive GexReply
|
|
||||||
packet, err = c.readPacket()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var kexDHGexReply kexDHGexReplyMsg
|
|
||||||
if err = Unmarshal(packet, &kexDHGexReply); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
kInt, err := gex.diffieHellman(kexDHGexReply.Y, x)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if k is safe by verifing that k > 1 and k < p - 1
|
|
||||||
if kInt.Cmp(one) != 1 && kInt.Cmp(pMinusOne) != -1 {
|
|
||||||
return nil, fmt.Errorf("ssh: derived k is not safe")
|
|
||||||
}
|
|
||||||
|
|
||||||
h := gex.hashFunc.New()
|
|
||||||
magics.write(h)
|
|
||||||
writeString(h, kexDHGexReply.HostKey)
|
|
||||||
binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMinimumBits))
|
|
||||||
binary.Write(h, binary.BigEndian, uint32(dhGroupExchangePreferredBits))
|
|
||||||
binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMaximumBits))
|
|
||||||
writeInt(h, gex.p)
|
|
||||||
writeInt(h, gex.g)
|
|
||||||
writeInt(h, X)
|
|
||||||
writeInt(h, kexDHGexReply.Y)
|
|
||||||
K := make([]byte, intLength(kInt))
|
|
||||||
marshalInt(K, kInt)
|
|
||||||
h.Write(K)
|
|
||||||
|
|
||||||
return &kexResult{
|
|
||||||
H: h.Sum(nil),
|
|
||||||
K: K,
|
|
||||||
HostKey: kexDHGexReply.HostKey,
|
|
||||||
Signature: kexDHGexReply.Signature,
|
|
||||||
Hash: gex.hashFunc,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Server half implementation of the Diffie Hellman Key Exchange with SHA1 and SHA256.
|
|
||||||
//
|
|
||||||
// This is a minimal implementation to satisfy the automated tests.
|
|
||||||
func (gex *dhGEXSHA) Server(c packetConn, randSource io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) {
|
|
||||||
// Receive GexRequest
|
|
||||||
packet, err := c.readPacket()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var kexDHGexRequest kexDHGexRequestMsg
|
|
||||||
if err = Unmarshal(packet, &kexDHGexRequest); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// smoosh the user's preferred size into our own limits
|
|
||||||
if kexDHGexRequest.PreferedBits > dhGroupExchangeMaximumBits {
|
|
||||||
kexDHGexRequest.PreferedBits = dhGroupExchangeMaximumBits
|
|
||||||
}
|
|
||||||
if kexDHGexRequest.PreferedBits < dhGroupExchangeMinimumBits {
|
|
||||||
kexDHGexRequest.PreferedBits = dhGroupExchangeMinimumBits
|
|
||||||
}
|
|
||||||
// fix min/max if they're inconsistent. technically, we could just pout
|
|
||||||
// and hang up, but there's no harm in giving them the benefit of the
|
|
||||||
// doubt and just picking a bitsize for them.
|
|
||||||
if kexDHGexRequest.MinBits > kexDHGexRequest.PreferedBits {
|
|
||||||
kexDHGexRequest.MinBits = kexDHGexRequest.PreferedBits
|
|
||||||
}
|
|
||||||
if kexDHGexRequest.MaxBits < kexDHGexRequest.PreferedBits {
|
|
||||||
kexDHGexRequest.MaxBits = kexDHGexRequest.PreferedBits
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send GexGroup
|
|
||||||
// This is the group called diffie-hellman-group14-sha1 in RFC
|
|
||||||
// 4253 and Oakley Group 14 in RFC 3526.
|
|
||||||
p, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", 16)
|
|
||||||
gex.p = p
|
|
||||||
gex.g = big.NewInt(2)
|
|
||||||
|
|
||||||
kexDHGexGroup := kexDHGexGroupMsg{
|
|
||||||
P: gex.p,
|
|
||||||
G: gex.g,
|
|
||||||
}
|
|
||||||
if err := c.writePacket(Marshal(&kexDHGexGroup)); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Receive GexInit
|
|
||||||
packet, err = c.readPacket()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var kexDHGexInit kexDHGexInitMsg
|
|
||||||
if err = Unmarshal(packet, &kexDHGexInit); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var pHalf = &big.Int{}
|
|
||||||
pHalf.Rsh(gex.p, 1)
|
|
||||||
|
|
||||||
y, err := rand.Int(randSource, pHalf)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
Y := new(big.Int).Exp(gex.g, y, gex.p)
|
|
||||||
kInt, err := gex.diffieHellman(kexDHGexInit.X, y)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
hostKeyBytes := priv.PublicKey().Marshal()
|
|
||||||
|
|
||||||
h := gex.hashFunc.New()
|
|
||||||
magics.write(h)
|
|
||||||
writeString(h, hostKeyBytes)
|
|
||||||
binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMinimumBits))
|
|
||||||
binary.Write(h, binary.BigEndian, uint32(dhGroupExchangePreferredBits))
|
|
||||||
binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMaximumBits))
|
|
||||||
writeInt(h, gex.p)
|
|
||||||
writeInt(h, gex.g)
|
|
||||||
writeInt(h, kexDHGexInit.X)
|
|
||||||
writeInt(h, Y)
|
|
||||||
|
|
||||||
K := make([]byte, intLength(kInt))
|
|
||||||
marshalInt(K, kInt)
|
|
||||||
h.Write(K)
|
|
||||||
|
|
||||||
H := h.Sum(nil)
|
|
||||||
|
|
||||||
// H is already a hash, but the hostkey signing will apply its
|
|
||||||
// own key-specific hash algorithm.
|
|
||||||
sig, err := signAndMarshal(priv, randSource, H)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
kexDHGexReply := kexDHGexReplyMsg{
|
|
||||||
HostKey: hostKeyBytes,
|
|
||||||
Y: Y,
|
|
||||||
Signature: sig,
|
|
||||||
}
|
|
||||||
packet = Marshal(&kexDHGexReply)
|
|
||||||
|
|
||||||
err = c.writePacket(packet)
|
|
||||||
|
|
||||||
return &kexResult{
|
|
||||||
H: H,
|
|
||||||
K: K,
|
|
||||||
HostKey: hostKeyBytes,
|
|
||||||
Signature: sig,
|
|
||||||
Hash: gex.hashFunc,
|
|
||||||
}, err
|
|
||||||
}
|
|
1100
vendor/golang.org/x/crypto/ssh/keys.go
generated
vendored
1100
vendor/golang.org/x/crypto/ssh/keys.go
generated
vendored
File diff suppressed because it is too large
Load Diff
61
vendor/golang.org/x/crypto/ssh/mac.go
generated
vendored
61
vendor/golang.org/x/crypto/ssh/mac.go
generated
vendored
@ -1,61 +0,0 @@
|
|||||||
// 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 ssh
|
|
||||||
|
|
||||||
// Message authentication support
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/hmac"
|
|
||||||
"crypto/sha1"
|
|
||||||
"crypto/sha256"
|
|
||||||
"hash"
|
|
||||||
)
|
|
||||||
|
|
||||||
type macMode struct {
|
|
||||||
keySize int
|
|
||||||
etm bool
|
|
||||||
new func(key []byte) hash.Hash
|
|
||||||
}
|
|
||||||
|
|
||||||
// truncatingMAC wraps around a hash.Hash and truncates the output digest to
|
|
||||||
// a given size.
|
|
||||||
type truncatingMAC struct {
|
|
||||||
length int
|
|
||||||
hmac hash.Hash
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t truncatingMAC) Write(data []byte) (int, error) {
|
|
||||||
return t.hmac.Write(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t truncatingMAC) Sum(in []byte) []byte {
|
|
||||||
out := t.hmac.Sum(in)
|
|
||||||
return out[:len(in)+t.length]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t truncatingMAC) Reset() {
|
|
||||||
t.hmac.Reset()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t truncatingMAC) Size() int {
|
|
||||||
return t.length
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t truncatingMAC) BlockSize() int { return t.hmac.BlockSize() }
|
|
||||||
|
|
||||||
var macModes = map[string]*macMode{
|
|
||||||
"hmac-sha2-256-etm@openssh.com": {32, true, func(key []byte) hash.Hash {
|
|
||||||
return hmac.New(sha256.New, key)
|
|
||||||
}},
|
|
||||||
"hmac-sha2-256": {32, false, func(key []byte) hash.Hash {
|
|
||||||
return hmac.New(sha256.New, key)
|
|
||||||
}},
|
|
||||||
"hmac-sha1": {20, false, func(key []byte) hash.Hash {
|
|
||||||
return hmac.New(sha1.New, key)
|
|
||||||
}},
|
|
||||||
"hmac-sha1-96": {20, false, func(key []byte) hash.Hash {
|
|
||||||
return truncatingMAC{12, hmac.New(sha1.New, key)}
|
|
||||||
}},
|
|
||||||
}
|
|
866
vendor/golang.org/x/crypto/ssh/messages.go
generated
vendored
866
vendor/golang.org/x/crypto/ssh/messages.go
generated
vendored
@ -1,866 +0,0 @@
|
|||||||
// 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 ssh
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/binary"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"math/big"
|
|
||||||
"reflect"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// These are SSH message type numbers. They are scattered around several
|
|
||||||
// documents but many were taken from [SSH-PARAMETERS].
|
|
||||||
const (
|
|
||||||
msgIgnore = 2
|
|
||||||
msgUnimplemented = 3
|
|
||||||
msgDebug = 4
|
|
||||||
msgNewKeys = 21
|
|
||||||
)
|
|
||||||
|
|
||||||
// SSH messages:
|
|
||||||
//
|
|
||||||
// These structures mirror the wire format of the corresponding SSH messages.
|
|
||||||
// They are marshaled using reflection with the marshal and unmarshal functions
|
|
||||||
// in this file. The only wrinkle is that a final member of type []byte with a
|
|
||||||
// ssh tag of "rest" receives the remainder of a packet when unmarshaling.
|
|
||||||
|
|
||||||
// See RFC 4253, section 11.1.
|
|
||||||
const msgDisconnect = 1
|
|
||||||
|
|
||||||
// disconnectMsg is the message that signals a disconnect. It is also
|
|
||||||
// the error type returned from mux.Wait()
|
|
||||||
type disconnectMsg struct {
|
|
||||||
Reason uint32 `sshtype:"1"`
|
|
||||||
Message string
|
|
||||||
Language string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *disconnectMsg) Error() string {
|
|
||||||
return fmt.Sprintf("ssh: disconnect, reason %d: %s", d.Reason, d.Message)
|
|
||||||
}
|
|
||||||
|
|
||||||
// See RFC 4253, section 7.1.
|
|
||||||
const msgKexInit = 20
|
|
||||||
|
|
||||||
type kexInitMsg struct {
|
|
||||||
Cookie [16]byte `sshtype:"20"`
|
|
||||||
KexAlgos []string
|
|
||||||
ServerHostKeyAlgos []string
|
|
||||||
CiphersClientServer []string
|
|
||||||
CiphersServerClient []string
|
|
||||||
MACsClientServer []string
|
|
||||||
MACsServerClient []string
|
|
||||||
CompressionClientServer []string
|
|
||||||
CompressionServerClient []string
|
|
||||||
LanguagesClientServer []string
|
|
||||||
LanguagesServerClient []string
|
|
||||||
FirstKexFollows bool
|
|
||||||
Reserved uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
// See RFC 4253, section 8.
|
|
||||||
|
|
||||||
// Diffie-Helman
|
|
||||||
const msgKexDHInit = 30
|
|
||||||
|
|
||||||
type kexDHInitMsg struct {
|
|
||||||
X *big.Int `sshtype:"30"`
|
|
||||||
}
|
|
||||||
|
|
||||||
const msgKexECDHInit = 30
|
|
||||||
|
|
||||||
type kexECDHInitMsg struct {
|
|
||||||
ClientPubKey []byte `sshtype:"30"`
|
|
||||||
}
|
|
||||||
|
|
||||||
const msgKexECDHReply = 31
|
|
||||||
|
|
||||||
type kexECDHReplyMsg struct {
|
|
||||||
HostKey []byte `sshtype:"31"`
|
|
||||||
EphemeralPubKey []byte
|
|
||||||
Signature []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
const msgKexDHReply = 31
|
|
||||||
|
|
||||||
type kexDHReplyMsg struct {
|
|
||||||
HostKey []byte `sshtype:"31"`
|
|
||||||
Y *big.Int
|
|
||||||
Signature []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
// See RFC 4419, section 5.
|
|
||||||
const msgKexDHGexGroup = 31
|
|
||||||
|
|
||||||
type kexDHGexGroupMsg struct {
|
|
||||||
P *big.Int `sshtype:"31"`
|
|
||||||
G *big.Int
|
|
||||||
}
|
|
||||||
|
|
||||||
const msgKexDHGexInit = 32
|
|
||||||
|
|
||||||
type kexDHGexInitMsg struct {
|
|
||||||
X *big.Int `sshtype:"32"`
|
|
||||||
}
|
|
||||||
|
|
||||||
const msgKexDHGexReply = 33
|
|
||||||
|
|
||||||
type kexDHGexReplyMsg struct {
|
|
||||||
HostKey []byte `sshtype:"33"`
|
|
||||||
Y *big.Int
|
|
||||||
Signature []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
const msgKexDHGexRequest = 34
|
|
||||||
|
|
||||||
type kexDHGexRequestMsg struct {
|
|
||||||
MinBits uint32 `sshtype:"34"`
|
|
||||||
PreferedBits uint32
|
|
||||||
MaxBits uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
// See RFC 4253, section 10.
|
|
||||||
const msgServiceRequest = 5
|
|
||||||
|
|
||||||
type serviceRequestMsg struct {
|
|
||||||
Service string `sshtype:"5"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// See RFC 4253, section 10.
|
|
||||||
const msgServiceAccept = 6
|
|
||||||
|
|
||||||
type serviceAcceptMsg struct {
|
|
||||||
Service string `sshtype:"6"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// See RFC 4252, section 5.
|
|
||||||
const msgUserAuthRequest = 50
|
|
||||||
|
|
||||||
type userAuthRequestMsg struct {
|
|
||||||
User string `sshtype:"50"`
|
|
||||||
Service string
|
|
||||||
Method string
|
|
||||||
Payload []byte `ssh:"rest"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used for debug printouts of packets.
|
|
||||||
type userAuthSuccessMsg struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
// See RFC 4252, section 5.1
|
|
||||||
const msgUserAuthFailure = 51
|
|
||||||
|
|
||||||
type userAuthFailureMsg struct {
|
|
||||||
Methods []string `sshtype:"51"`
|
|
||||||
PartialSuccess bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// See RFC 4252, section 5.1
|
|
||||||
const msgUserAuthSuccess = 52
|
|
||||||
|
|
||||||
// See RFC 4252, section 5.4
|
|
||||||
const msgUserAuthBanner = 53
|
|
||||||
|
|
||||||
type userAuthBannerMsg struct {
|
|
||||||
Message string `sshtype:"53"`
|
|
||||||
// unused, but required to allow message parsing
|
|
||||||
Language string
|
|
||||||
}
|
|
||||||
|
|
||||||
// See RFC 4256, section 3.2
|
|
||||||
const msgUserAuthInfoRequest = 60
|
|
||||||
const msgUserAuthInfoResponse = 61
|
|
||||||
|
|
||||||
type userAuthInfoRequestMsg struct {
|
|
||||||
User string `sshtype:"60"`
|
|
||||||
Instruction string
|
|
||||||
DeprecatedLanguage string
|
|
||||||
NumPrompts uint32
|
|
||||||
Prompts []byte `ssh:"rest"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// See RFC 4254, section 5.1.
|
|
||||||
const msgChannelOpen = 90
|
|
||||||
|
|
||||||
type channelOpenMsg struct {
|
|
||||||
ChanType string `sshtype:"90"`
|
|
||||||
PeersID uint32
|
|
||||||
PeersWindow uint32
|
|
||||||
MaxPacketSize uint32
|
|
||||||
TypeSpecificData []byte `ssh:"rest"`
|
|
||||||
}
|
|
||||||
|
|
||||||
const msgChannelExtendedData = 95
|
|
||||||
const msgChannelData = 94
|
|
||||||
|
|
||||||
// Used for debug print outs of packets.
|
|
||||||
type channelDataMsg struct {
|
|
||||||
PeersID uint32 `sshtype:"94"`
|
|
||||||
Length uint32
|
|
||||||
Rest []byte `ssh:"rest"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// See RFC 4254, section 5.1.
|
|
||||||
const msgChannelOpenConfirm = 91
|
|
||||||
|
|
||||||
type channelOpenConfirmMsg struct {
|
|
||||||
PeersID uint32 `sshtype:"91"`
|
|
||||||
MyID uint32
|
|
||||||
MyWindow uint32
|
|
||||||
MaxPacketSize uint32
|
|
||||||
TypeSpecificData []byte `ssh:"rest"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// See RFC 4254, section 5.1.
|
|
||||||
const msgChannelOpenFailure = 92
|
|
||||||
|
|
||||||
type channelOpenFailureMsg struct {
|
|
||||||
PeersID uint32 `sshtype:"92"`
|
|
||||||
Reason RejectionReason
|
|
||||||
Message string
|
|
||||||
Language string
|
|
||||||
}
|
|
||||||
|
|
||||||
const msgChannelRequest = 98
|
|
||||||
|
|
||||||
type channelRequestMsg struct {
|
|
||||||
PeersID uint32 `sshtype:"98"`
|
|
||||||
Request string
|
|
||||||
WantReply bool
|
|
||||||
RequestSpecificData []byte `ssh:"rest"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// See RFC 4254, section 5.4.
|
|
||||||
const msgChannelSuccess = 99
|
|
||||||
|
|
||||||
type channelRequestSuccessMsg struct {
|
|
||||||
PeersID uint32 `sshtype:"99"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// See RFC 4254, section 5.4.
|
|
||||||
const msgChannelFailure = 100
|
|
||||||
|
|
||||||
type channelRequestFailureMsg struct {
|
|
||||||
PeersID uint32 `sshtype:"100"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// See RFC 4254, section 5.3
|
|
||||||
const msgChannelClose = 97
|
|
||||||
|
|
||||||
type channelCloseMsg struct {
|
|
||||||
PeersID uint32 `sshtype:"97"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// See RFC 4254, section 5.3
|
|
||||||
const msgChannelEOF = 96
|
|
||||||
|
|
||||||
type channelEOFMsg struct {
|
|
||||||
PeersID uint32 `sshtype:"96"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// See RFC 4254, section 4
|
|
||||||
const msgGlobalRequest = 80
|
|
||||||
|
|
||||||
type globalRequestMsg struct {
|
|
||||||
Type string `sshtype:"80"`
|
|
||||||
WantReply bool
|
|
||||||
Data []byte `ssh:"rest"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// See RFC 4254, section 4
|
|
||||||
const msgRequestSuccess = 81
|
|
||||||
|
|
||||||
type globalRequestSuccessMsg struct {
|
|
||||||
Data []byte `ssh:"rest" sshtype:"81"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// See RFC 4254, section 4
|
|
||||||
const msgRequestFailure = 82
|
|
||||||
|
|
||||||
type globalRequestFailureMsg struct {
|
|
||||||
Data []byte `ssh:"rest" sshtype:"82"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// See RFC 4254, section 5.2
|
|
||||||
const msgChannelWindowAdjust = 93
|
|
||||||
|
|
||||||
type windowAdjustMsg struct {
|
|
||||||
PeersID uint32 `sshtype:"93"`
|
|
||||||
AdditionalBytes uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
// See RFC 4252, section 7
|
|
||||||
const msgUserAuthPubKeyOk = 60
|
|
||||||
|
|
||||||
type userAuthPubKeyOkMsg struct {
|
|
||||||
Algo string `sshtype:"60"`
|
|
||||||
PubKey []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
// See RFC 4462, section 3
|
|
||||||
const msgUserAuthGSSAPIResponse = 60
|
|
||||||
|
|
||||||
type userAuthGSSAPIResponse struct {
|
|
||||||
SupportMech []byte `sshtype:"60"`
|
|
||||||
}
|
|
||||||
|
|
||||||
const msgUserAuthGSSAPIToken = 61
|
|
||||||
|
|
||||||
type userAuthGSSAPIToken struct {
|
|
||||||
Token []byte `sshtype:"61"`
|
|
||||||
}
|
|
||||||
|
|
||||||
const msgUserAuthGSSAPIMIC = 66
|
|
||||||
|
|
||||||
type userAuthGSSAPIMIC struct {
|
|
||||||
MIC []byte `sshtype:"66"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// See RFC 4462, section 3.9
|
|
||||||
const msgUserAuthGSSAPIErrTok = 64
|
|
||||||
|
|
||||||
type userAuthGSSAPIErrTok struct {
|
|
||||||
ErrorToken []byte `sshtype:"64"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// See RFC 4462, section 3.8
|
|
||||||
const msgUserAuthGSSAPIError = 65
|
|
||||||
|
|
||||||
type userAuthGSSAPIError struct {
|
|
||||||
MajorStatus uint32 `sshtype:"65"`
|
|
||||||
MinorStatus uint32
|
|
||||||
Message string
|
|
||||||
LanguageTag string
|
|
||||||
}
|
|
||||||
|
|
||||||
// typeTags returns the possible type bytes for the given reflect.Type, which
|
|
||||||
// should be a struct. The possible values are separated by a '|' character.
|
|
||||||
func typeTags(structType reflect.Type) (tags []byte) {
|
|
||||||
tagStr := structType.Field(0).Tag.Get("sshtype")
|
|
||||||
|
|
||||||
for _, tag := range strings.Split(tagStr, "|") {
|
|
||||||
i, err := strconv.Atoi(tag)
|
|
||||||
if err == nil {
|
|
||||||
tags = append(tags, byte(i))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return tags
|
|
||||||
}
|
|
||||||
|
|
||||||
func fieldError(t reflect.Type, field int, problem string) error {
|
|
||||||
if problem != "" {
|
|
||||||
problem = ": " + problem
|
|
||||||
}
|
|
||||||
return fmt.Errorf("ssh: unmarshal error for field %s of type %s%s", t.Field(field).Name, t.Name(), problem)
|
|
||||||
}
|
|
||||||
|
|
||||||
var errShortRead = errors.New("ssh: short read")
|
|
||||||
|
|
||||||
// Unmarshal parses data in SSH wire format into a structure. The out
|
|
||||||
// argument should be a pointer to struct. If the first member of the
|
|
||||||
// struct has the "sshtype" tag set to a '|'-separated set of numbers
|
|
||||||
// in decimal, the packet must start with one of those numbers. In
|
|
||||||
// case of error, Unmarshal returns a ParseError or
|
|
||||||
// UnexpectedMessageError.
|
|
||||||
func Unmarshal(data []byte, out interface{}) error {
|
|
||||||
v := reflect.ValueOf(out).Elem()
|
|
||||||
structType := v.Type()
|
|
||||||
expectedTypes := typeTags(structType)
|
|
||||||
|
|
||||||
var expectedType byte
|
|
||||||
if len(expectedTypes) > 0 {
|
|
||||||
expectedType = expectedTypes[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(data) == 0 {
|
|
||||||
return parseError(expectedType)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(expectedTypes) > 0 {
|
|
||||||
goodType := false
|
|
||||||
for _, e := range expectedTypes {
|
|
||||||
if e > 0 && data[0] == e {
|
|
||||||
goodType = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !goodType {
|
|
||||||
return fmt.Errorf("ssh: unexpected message type %d (expected one of %v)", data[0], expectedTypes)
|
|
||||||
}
|
|
||||||
data = data[1:]
|
|
||||||
}
|
|
||||||
|
|
||||||
var ok bool
|
|
||||||
for i := 0; i < v.NumField(); i++ {
|
|
||||||
field := v.Field(i)
|
|
||||||
t := field.Type()
|
|
||||||
switch t.Kind() {
|
|
||||||
case reflect.Bool:
|
|
||||||
if len(data) < 1 {
|
|
||||||
return errShortRead
|
|
||||||
}
|
|
||||||
field.SetBool(data[0] != 0)
|
|
||||||
data = data[1:]
|
|
||||||
case reflect.Array:
|
|
||||||
if t.Elem().Kind() != reflect.Uint8 {
|
|
||||||
return fieldError(structType, i, "array of unsupported type")
|
|
||||||
}
|
|
||||||
if len(data) < t.Len() {
|
|
||||||
return errShortRead
|
|
||||||
}
|
|
||||||
for j, n := 0, t.Len(); j < n; j++ {
|
|
||||||
field.Index(j).Set(reflect.ValueOf(data[j]))
|
|
||||||
}
|
|
||||||
data = data[t.Len():]
|
|
||||||
case reflect.Uint64:
|
|
||||||
var u64 uint64
|
|
||||||
if u64, data, ok = parseUint64(data); !ok {
|
|
||||||
return errShortRead
|
|
||||||
}
|
|
||||||
field.SetUint(u64)
|
|
||||||
case reflect.Uint32:
|
|
||||||
var u32 uint32
|
|
||||||
if u32, data, ok = parseUint32(data); !ok {
|
|
||||||
return errShortRead
|
|
||||||
}
|
|
||||||
field.SetUint(uint64(u32))
|
|
||||||
case reflect.Uint8:
|
|
||||||
if len(data) < 1 {
|
|
||||||
return errShortRead
|
|
||||||
}
|
|
||||||
field.SetUint(uint64(data[0]))
|
|
||||||
data = data[1:]
|
|
||||||
case reflect.String:
|
|
||||||
var s []byte
|
|
||||||
if s, data, ok = parseString(data); !ok {
|
|
||||||
return fieldError(structType, i, "")
|
|
||||||
}
|
|
||||||
field.SetString(string(s))
|
|
||||||
case reflect.Slice:
|
|
||||||
switch t.Elem().Kind() {
|
|
||||||
case reflect.Uint8:
|
|
||||||
if structType.Field(i).Tag.Get("ssh") == "rest" {
|
|
||||||
field.Set(reflect.ValueOf(data))
|
|
||||||
data = nil
|
|
||||||
} else {
|
|
||||||
var s []byte
|
|
||||||
if s, data, ok = parseString(data); !ok {
|
|
||||||
return errShortRead
|
|
||||||
}
|
|
||||||
field.Set(reflect.ValueOf(s))
|
|
||||||
}
|
|
||||||
case reflect.String:
|
|
||||||
var nl []string
|
|
||||||
if nl, data, ok = parseNameList(data); !ok {
|
|
||||||
return errShortRead
|
|
||||||
}
|
|
||||||
field.Set(reflect.ValueOf(nl))
|
|
||||||
default:
|
|
||||||
return fieldError(structType, i, "slice of unsupported type")
|
|
||||||
}
|
|
||||||
case reflect.Ptr:
|
|
||||||
if t == bigIntType {
|
|
||||||
var n *big.Int
|
|
||||||
if n, data, ok = parseInt(data); !ok {
|
|
||||||
return errShortRead
|
|
||||||
}
|
|
||||||
field.Set(reflect.ValueOf(n))
|
|
||||||
} else {
|
|
||||||
return fieldError(structType, i, "pointer to unsupported type")
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return fieldError(structType, i, fmt.Sprintf("unsupported type: %v", t))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(data) != 0 {
|
|
||||||
return parseError(expectedType)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Marshal serializes the message in msg to SSH wire format. The msg
|
|
||||||
// argument should be a struct or pointer to struct. If the first
|
|
||||||
// member has the "sshtype" tag set to a number in decimal, that
|
|
||||||
// number is prepended to the result. If the last of member has the
|
|
||||||
// "ssh" tag set to "rest", its contents are appended to the output.
|
|
||||||
func Marshal(msg interface{}) []byte {
|
|
||||||
out := make([]byte, 0, 64)
|
|
||||||
return marshalStruct(out, msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
func marshalStruct(out []byte, msg interface{}) []byte {
|
|
||||||
v := reflect.Indirect(reflect.ValueOf(msg))
|
|
||||||
msgTypes := typeTags(v.Type())
|
|
||||||
if len(msgTypes) > 0 {
|
|
||||||
out = append(out, msgTypes[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, n := 0, v.NumField(); i < n; i++ {
|
|
||||||
field := v.Field(i)
|
|
||||||
switch t := field.Type(); t.Kind() {
|
|
||||||
case reflect.Bool:
|
|
||||||
var v uint8
|
|
||||||
if field.Bool() {
|
|
||||||
v = 1
|
|
||||||
}
|
|
||||||
out = append(out, v)
|
|
||||||
case reflect.Array:
|
|
||||||
if t.Elem().Kind() != reflect.Uint8 {
|
|
||||||
panic(fmt.Sprintf("array of non-uint8 in field %d: %T", i, field.Interface()))
|
|
||||||
}
|
|
||||||
for j, l := 0, t.Len(); j < l; j++ {
|
|
||||||
out = append(out, uint8(field.Index(j).Uint()))
|
|
||||||
}
|
|
||||||
case reflect.Uint32:
|
|
||||||
out = appendU32(out, uint32(field.Uint()))
|
|
||||||
case reflect.Uint64:
|
|
||||||
out = appendU64(out, uint64(field.Uint()))
|
|
||||||
case reflect.Uint8:
|
|
||||||
out = append(out, uint8(field.Uint()))
|
|
||||||
case reflect.String:
|
|
||||||
s := field.String()
|
|
||||||
out = appendInt(out, len(s))
|
|
||||||
out = append(out, s...)
|
|
||||||
case reflect.Slice:
|
|
||||||
switch t.Elem().Kind() {
|
|
||||||
case reflect.Uint8:
|
|
||||||
if v.Type().Field(i).Tag.Get("ssh") != "rest" {
|
|
||||||
out = appendInt(out, field.Len())
|
|
||||||
}
|
|
||||||
out = append(out, field.Bytes()...)
|
|
||||||
case reflect.String:
|
|
||||||
offset := len(out)
|
|
||||||
out = appendU32(out, 0)
|
|
||||||
if n := field.Len(); n > 0 {
|
|
||||||
for j := 0; j < n; j++ {
|
|
||||||
f := field.Index(j)
|
|
||||||
if j != 0 {
|
|
||||||
out = append(out, ',')
|
|
||||||
}
|
|
||||||
out = append(out, f.String()...)
|
|
||||||
}
|
|
||||||
// overwrite length value
|
|
||||||
binary.BigEndian.PutUint32(out[offset:], uint32(len(out)-offset-4))
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
panic(fmt.Sprintf("slice of unknown type in field %d: %T", i, field.Interface()))
|
|
||||||
}
|
|
||||||
case reflect.Ptr:
|
|
||||||
if t == bigIntType {
|
|
||||||
var n *big.Int
|
|
||||||
nValue := reflect.ValueOf(&n)
|
|
||||||
nValue.Elem().Set(field)
|
|
||||||
needed := intLength(n)
|
|
||||||
oldLength := len(out)
|
|
||||||
|
|
||||||
if cap(out)-len(out) < needed {
|
|
||||||
newOut := make([]byte, len(out), 2*(len(out)+needed))
|
|
||||||
copy(newOut, out)
|
|
||||||
out = newOut
|
|
||||||
}
|
|
||||||
out = out[:oldLength+needed]
|
|
||||||
marshalInt(out[oldLength:], n)
|
|
||||||
} else {
|
|
||||||
panic(fmt.Sprintf("pointer to unknown type in field %d: %T", i, field.Interface()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
var bigOne = big.NewInt(1)
|
|
||||||
|
|
||||||
func parseString(in []byte) (out, rest []byte, ok bool) {
|
|
||||||
if len(in) < 4 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
length := binary.BigEndian.Uint32(in)
|
|
||||||
in = in[4:]
|
|
||||||
if uint32(len(in)) < length {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
out = in[:length]
|
|
||||||
rest = in[length:]
|
|
||||||
ok = true
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
comma = []byte{','}
|
|
||||||
emptyNameList = []string{}
|
|
||||||
)
|
|
||||||
|
|
||||||
func parseNameList(in []byte) (out []string, rest []byte, ok bool) {
|
|
||||||
contents, rest, ok := parseString(in)
|
|
||||||
if !ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if len(contents) == 0 {
|
|
||||||
out = emptyNameList
|
|
||||||
return
|
|
||||||
}
|
|
||||||
parts := bytes.Split(contents, comma)
|
|
||||||
out = make([]string, len(parts))
|
|
||||||
for i, part := range parts {
|
|
||||||
out[i] = string(part)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseInt(in []byte) (out *big.Int, rest []byte, ok bool) {
|
|
||||||
contents, rest, ok := parseString(in)
|
|
||||||
if !ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
out = new(big.Int)
|
|
||||||
|
|
||||||
if len(contents) > 0 && contents[0]&0x80 == 0x80 {
|
|
||||||
// This is a negative number
|
|
||||||
notBytes := make([]byte, len(contents))
|
|
||||||
for i := range notBytes {
|
|
||||||
notBytes[i] = ^contents[i]
|
|
||||||
}
|
|
||||||
out.SetBytes(notBytes)
|
|
||||||
out.Add(out, bigOne)
|
|
||||||
out.Neg(out)
|
|
||||||
} else {
|
|
||||||
// Positive number
|
|
||||||
out.SetBytes(contents)
|
|
||||||
}
|
|
||||||
ok = true
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseUint32(in []byte) (uint32, []byte, bool) {
|
|
||||||
if len(in) < 4 {
|
|
||||||
return 0, nil, false
|
|
||||||
}
|
|
||||||
return binary.BigEndian.Uint32(in), in[4:], true
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseUint64(in []byte) (uint64, []byte, bool) {
|
|
||||||
if len(in) < 8 {
|
|
||||||
return 0, nil, false
|
|
||||||
}
|
|
||||||
return binary.BigEndian.Uint64(in), in[8:], true
|
|
||||||
}
|
|
||||||
|
|
||||||
func intLength(n *big.Int) int {
|
|
||||||
length := 4 /* length bytes */
|
|
||||||
if n.Sign() < 0 {
|
|
||||||
nMinus1 := new(big.Int).Neg(n)
|
|
||||||
nMinus1.Sub(nMinus1, bigOne)
|
|
||||||
bitLen := nMinus1.BitLen()
|
|
||||||
if bitLen%8 == 0 {
|
|
||||||
// The number will need 0xff padding
|
|
||||||
length++
|
|
||||||
}
|
|
||||||
length += (bitLen + 7) / 8
|
|
||||||
} else if n.Sign() == 0 {
|
|
||||||
// A zero is the zero length string
|
|
||||||
} else {
|
|
||||||
bitLen := n.BitLen()
|
|
||||||
if bitLen%8 == 0 {
|
|
||||||
// The number will need 0x00 padding
|
|
||||||
length++
|
|
||||||
}
|
|
||||||
length += (bitLen + 7) / 8
|
|
||||||
}
|
|
||||||
|
|
||||||
return length
|
|
||||||
}
|
|
||||||
|
|
||||||
func marshalUint32(to []byte, n uint32) []byte {
|
|
||||||
binary.BigEndian.PutUint32(to, n)
|
|
||||||
return to[4:]
|
|
||||||
}
|
|
||||||
|
|
||||||
func marshalUint64(to []byte, n uint64) []byte {
|
|
||||||
binary.BigEndian.PutUint64(to, n)
|
|
||||||
return to[8:]
|
|
||||||
}
|
|
||||||
|
|
||||||
func marshalInt(to []byte, n *big.Int) []byte {
|
|
||||||
lengthBytes := to
|
|
||||||
to = to[4:]
|
|
||||||
length := 0
|
|
||||||
|
|
||||||
if n.Sign() < 0 {
|
|
||||||
// A negative number has to be converted to two's-complement
|
|
||||||
// form. So we'll subtract 1 and invert. If the
|
|
||||||
// most-significant-bit isn't set then we'll need to pad the
|
|
||||||
// beginning with 0xff in order to keep the number negative.
|
|
||||||
nMinus1 := new(big.Int).Neg(n)
|
|
||||||
nMinus1.Sub(nMinus1, bigOne)
|
|
||||||
bytes := nMinus1.Bytes()
|
|
||||||
for i := range bytes {
|
|
||||||
bytes[i] ^= 0xff
|
|
||||||
}
|
|
||||||
if len(bytes) == 0 || bytes[0]&0x80 == 0 {
|
|
||||||
to[0] = 0xff
|
|
||||||
to = to[1:]
|
|
||||||
length++
|
|
||||||
}
|
|
||||||
nBytes := copy(to, bytes)
|
|
||||||
to = to[nBytes:]
|
|
||||||
length += nBytes
|
|
||||||
} else if n.Sign() == 0 {
|
|
||||||
// A zero is the zero length string
|
|
||||||
} else {
|
|
||||||
bytes := n.Bytes()
|
|
||||||
if len(bytes) > 0 && bytes[0]&0x80 != 0 {
|
|
||||||
// We'll have to pad this with a 0x00 in order to
|
|
||||||
// stop it looking like a negative number.
|
|
||||||
to[0] = 0
|
|
||||||
to = to[1:]
|
|
||||||
length++
|
|
||||||
}
|
|
||||||
nBytes := copy(to, bytes)
|
|
||||||
to = to[nBytes:]
|
|
||||||
length += nBytes
|
|
||||||
}
|
|
||||||
|
|
||||||
lengthBytes[0] = byte(length >> 24)
|
|
||||||
lengthBytes[1] = byte(length >> 16)
|
|
||||||
lengthBytes[2] = byte(length >> 8)
|
|
||||||
lengthBytes[3] = byte(length)
|
|
||||||
return to
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeInt(w io.Writer, n *big.Int) {
|
|
||||||
length := intLength(n)
|
|
||||||
buf := make([]byte, length)
|
|
||||||
marshalInt(buf, n)
|
|
||||||
w.Write(buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeString(w io.Writer, s []byte) {
|
|
||||||
var lengthBytes [4]byte
|
|
||||||
lengthBytes[0] = byte(len(s) >> 24)
|
|
||||||
lengthBytes[1] = byte(len(s) >> 16)
|
|
||||||
lengthBytes[2] = byte(len(s) >> 8)
|
|
||||||
lengthBytes[3] = byte(len(s))
|
|
||||||
w.Write(lengthBytes[:])
|
|
||||||
w.Write(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func stringLength(n int) int {
|
|
||||||
return 4 + n
|
|
||||||
}
|
|
||||||
|
|
||||||
func marshalString(to []byte, s []byte) []byte {
|
|
||||||
to[0] = byte(len(s) >> 24)
|
|
||||||
to[1] = byte(len(s) >> 16)
|
|
||||||
to[2] = byte(len(s) >> 8)
|
|
||||||
to[3] = byte(len(s))
|
|
||||||
to = to[4:]
|
|
||||||
copy(to, s)
|
|
||||||
return to[len(s):]
|
|
||||||
}
|
|
||||||
|
|
||||||
var bigIntType = reflect.TypeOf((*big.Int)(nil))
|
|
||||||
|
|
||||||
// Decode a packet into its corresponding message.
|
|
||||||
func decode(packet []byte) (interface{}, error) {
|
|
||||||
var msg interface{}
|
|
||||||
switch packet[0] {
|
|
||||||
case msgDisconnect:
|
|
||||||
msg = new(disconnectMsg)
|
|
||||||
case msgServiceRequest:
|
|
||||||
msg = new(serviceRequestMsg)
|
|
||||||
case msgServiceAccept:
|
|
||||||
msg = new(serviceAcceptMsg)
|
|
||||||
case msgKexInit:
|
|
||||||
msg = new(kexInitMsg)
|
|
||||||
case msgKexDHInit:
|
|
||||||
msg = new(kexDHInitMsg)
|
|
||||||
case msgKexDHReply:
|
|
||||||
msg = new(kexDHReplyMsg)
|
|
||||||
case msgUserAuthRequest:
|
|
||||||
msg = new(userAuthRequestMsg)
|
|
||||||
case msgUserAuthSuccess:
|
|
||||||
return new(userAuthSuccessMsg), nil
|
|
||||||
case msgUserAuthFailure:
|
|
||||||
msg = new(userAuthFailureMsg)
|
|
||||||
case msgUserAuthPubKeyOk:
|
|
||||||
msg = new(userAuthPubKeyOkMsg)
|
|
||||||
case msgGlobalRequest:
|
|
||||||
msg = new(globalRequestMsg)
|
|
||||||
case msgRequestSuccess:
|
|
||||||
msg = new(globalRequestSuccessMsg)
|
|
||||||
case msgRequestFailure:
|
|
||||||
msg = new(globalRequestFailureMsg)
|
|
||||||
case msgChannelOpen:
|
|
||||||
msg = new(channelOpenMsg)
|
|
||||||
case msgChannelData:
|
|
||||||
msg = new(channelDataMsg)
|
|
||||||
case msgChannelOpenConfirm:
|
|
||||||
msg = new(channelOpenConfirmMsg)
|
|
||||||
case msgChannelOpenFailure:
|
|
||||||
msg = new(channelOpenFailureMsg)
|
|
||||||
case msgChannelWindowAdjust:
|
|
||||||
msg = new(windowAdjustMsg)
|
|
||||||
case msgChannelEOF:
|
|
||||||
msg = new(channelEOFMsg)
|
|
||||||
case msgChannelClose:
|
|
||||||
msg = new(channelCloseMsg)
|
|
||||||
case msgChannelRequest:
|
|
||||||
msg = new(channelRequestMsg)
|
|
||||||
case msgChannelSuccess:
|
|
||||||
msg = new(channelRequestSuccessMsg)
|
|
||||||
case msgChannelFailure:
|
|
||||||
msg = new(channelRequestFailureMsg)
|
|
||||||
case msgUserAuthGSSAPIToken:
|
|
||||||
msg = new(userAuthGSSAPIToken)
|
|
||||||
case msgUserAuthGSSAPIMIC:
|
|
||||||
msg = new(userAuthGSSAPIMIC)
|
|
||||||
case msgUserAuthGSSAPIErrTok:
|
|
||||||
msg = new(userAuthGSSAPIErrTok)
|
|
||||||
case msgUserAuthGSSAPIError:
|
|
||||||
msg = new(userAuthGSSAPIError)
|
|
||||||
default:
|
|
||||||
return nil, unexpectedMessageError(0, packet[0])
|
|
||||||
}
|
|
||||||
if err := Unmarshal(packet, msg); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return msg, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var packetTypeNames = map[byte]string{
|
|
||||||
msgDisconnect: "disconnectMsg",
|
|
||||||
msgServiceRequest: "serviceRequestMsg",
|
|
||||||
msgServiceAccept: "serviceAcceptMsg",
|
|
||||||
msgKexInit: "kexInitMsg",
|
|
||||||
msgKexDHInit: "kexDHInitMsg",
|
|
||||||
msgKexDHReply: "kexDHReplyMsg",
|
|
||||||
msgUserAuthRequest: "userAuthRequestMsg",
|
|
||||||
msgUserAuthSuccess: "userAuthSuccessMsg",
|
|
||||||
msgUserAuthFailure: "userAuthFailureMsg",
|
|
||||||
msgUserAuthPubKeyOk: "userAuthPubKeyOkMsg",
|
|
||||||
msgGlobalRequest: "globalRequestMsg",
|
|
||||||
msgRequestSuccess: "globalRequestSuccessMsg",
|
|
||||||
msgRequestFailure: "globalRequestFailureMsg",
|
|
||||||
msgChannelOpen: "channelOpenMsg",
|
|
||||||
msgChannelData: "channelDataMsg",
|
|
||||||
msgChannelOpenConfirm: "channelOpenConfirmMsg",
|
|
||||||
msgChannelOpenFailure: "channelOpenFailureMsg",
|
|
||||||
msgChannelWindowAdjust: "windowAdjustMsg",
|
|
||||||
msgChannelEOF: "channelEOFMsg",
|
|
||||||
msgChannelClose: "channelCloseMsg",
|
|
||||||
msgChannelRequest: "channelRequestMsg",
|
|
||||||
msgChannelSuccess: "channelRequestSuccessMsg",
|
|
||||||
msgChannelFailure: "channelRequestFailureMsg",
|
|
||||||
}
|
|
330
vendor/golang.org/x/crypto/ssh/mux.go
generated
vendored
330
vendor/golang.org/x/crypto/ssh/mux.go
generated
vendored
@ -1,330 +0,0 @@
|
|||||||
// Copyright 2013 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package ssh
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/binary"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"log"
|
|
||||||
"sync"
|
|
||||||
"sync/atomic"
|
|
||||||
)
|
|
||||||
|
|
||||||
// debugMux, if set, causes messages in the connection protocol to be
|
|
||||||
// logged.
|
|
||||||
const debugMux = false
|
|
||||||
|
|
||||||
// chanList is a thread safe channel list.
|
|
||||||
type chanList struct {
|
|
||||||
// protects concurrent access to chans
|
|
||||||
sync.Mutex
|
|
||||||
|
|
||||||
// chans are indexed by the local id of the channel, which the
|
|
||||||
// other side should send in the PeersId field.
|
|
||||||
chans []*channel
|
|
||||||
|
|
||||||
// This is a debugging aid: it offsets all IDs by this
|
|
||||||
// amount. This helps distinguish otherwise identical
|
|
||||||
// server/client muxes
|
|
||||||
offset uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assigns a channel ID to the given channel.
|
|
||||||
func (c *chanList) add(ch *channel) uint32 {
|
|
||||||
c.Lock()
|
|
||||||
defer c.Unlock()
|
|
||||||
for i := range c.chans {
|
|
||||||
if c.chans[i] == nil {
|
|
||||||
c.chans[i] = ch
|
|
||||||
return uint32(i) + c.offset
|
|
||||||
}
|
|
||||||
}
|
|
||||||
c.chans = append(c.chans, ch)
|
|
||||||
return uint32(len(c.chans)-1) + c.offset
|
|
||||||
}
|
|
||||||
|
|
||||||
// getChan returns the channel for the given ID.
|
|
||||||
func (c *chanList) getChan(id uint32) *channel {
|
|
||||||
id -= c.offset
|
|
||||||
|
|
||||||
c.Lock()
|
|
||||||
defer c.Unlock()
|
|
||||||
if id < uint32(len(c.chans)) {
|
|
||||||
return c.chans[id]
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *chanList) remove(id uint32) {
|
|
||||||
id -= c.offset
|
|
||||||
c.Lock()
|
|
||||||
if id < uint32(len(c.chans)) {
|
|
||||||
c.chans[id] = nil
|
|
||||||
}
|
|
||||||
c.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
// dropAll forgets all channels it knows, returning them in a slice.
|
|
||||||
func (c *chanList) dropAll() []*channel {
|
|
||||||
c.Lock()
|
|
||||||
defer c.Unlock()
|
|
||||||
var r []*channel
|
|
||||||
|
|
||||||
for _, ch := range c.chans {
|
|
||||||
if ch == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
r = append(r, ch)
|
|
||||||
}
|
|
||||||
c.chans = nil
|
|
||||||
return r
|
|
||||||
}
|
|
||||||
|
|
||||||
// mux represents the state for the SSH connection protocol, which
|
|
||||||
// multiplexes many channels onto a single packet transport.
|
|
||||||
type mux struct {
|
|
||||||
conn packetConn
|
|
||||||
chanList chanList
|
|
||||||
|
|
||||||
incomingChannels chan NewChannel
|
|
||||||
|
|
||||||
globalSentMu sync.Mutex
|
|
||||||
globalResponses chan interface{}
|
|
||||||
incomingRequests chan *Request
|
|
||||||
|
|
||||||
errCond *sync.Cond
|
|
||||||
err error
|
|
||||||
}
|
|
||||||
|
|
||||||
// When debugging, each new chanList instantiation has a different
|
|
||||||
// offset.
|
|
||||||
var globalOff uint32
|
|
||||||
|
|
||||||
func (m *mux) Wait() error {
|
|
||||||
m.errCond.L.Lock()
|
|
||||||
defer m.errCond.L.Unlock()
|
|
||||||
for m.err == nil {
|
|
||||||
m.errCond.Wait()
|
|
||||||
}
|
|
||||||
return m.err
|
|
||||||
}
|
|
||||||
|
|
||||||
// newMux returns a mux that runs over the given connection.
|
|
||||||
func newMux(p packetConn) *mux {
|
|
||||||
m := &mux{
|
|
||||||
conn: p,
|
|
||||||
incomingChannels: make(chan NewChannel, chanSize),
|
|
||||||
globalResponses: make(chan interface{}, 1),
|
|
||||||
incomingRequests: make(chan *Request, chanSize),
|
|
||||||
errCond: newCond(),
|
|
||||||
}
|
|
||||||
if debugMux {
|
|
||||||
m.chanList.offset = atomic.AddUint32(&globalOff, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
go m.loop()
|
|
||||||
return m
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *mux) sendMessage(msg interface{}) error {
|
|
||||||
p := Marshal(msg)
|
|
||||||
if debugMux {
|
|
||||||
log.Printf("send global(%d): %#v", m.chanList.offset, msg)
|
|
||||||
}
|
|
||||||
return m.conn.writePacket(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *mux) SendRequest(name string, wantReply bool, payload []byte) (bool, []byte, error) {
|
|
||||||
if wantReply {
|
|
||||||
m.globalSentMu.Lock()
|
|
||||||
defer m.globalSentMu.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := m.sendMessage(globalRequestMsg{
|
|
||||||
Type: name,
|
|
||||||
WantReply: wantReply,
|
|
||||||
Data: payload,
|
|
||||||
}); err != nil {
|
|
||||||
return false, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !wantReply {
|
|
||||||
return false, nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
msg, ok := <-m.globalResponses
|
|
||||||
if !ok {
|
|
||||||
return false, nil, io.EOF
|
|
||||||
}
|
|
||||||
switch msg := msg.(type) {
|
|
||||||
case *globalRequestFailureMsg:
|
|
||||||
return false, msg.Data, nil
|
|
||||||
case *globalRequestSuccessMsg:
|
|
||||||
return true, msg.Data, nil
|
|
||||||
default:
|
|
||||||
return false, nil, fmt.Errorf("ssh: unexpected response to request: %#v", msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ackRequest must be called after processing a global request that
|
|
||||||
// has WantReply set.
|
|
||||||
func (m *mux) ackRequest(ok bool, data []byte) error {
|
|
||||||
if ok {
|
|
||||||
return m.sendMessage(globalRequestSuccessMsg{Data: data})
|
|
||||||
}
|
|
||||||
return m.sendMessage(globalRequestFailureMsg{Data: data})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *mux) Close() error {
|
|
||||||
return m.conn.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
// loop runs the connection machine. It will process packets until an
|
|
||||||
// error is encountered. To synchronize on loop exit, use mux.Wait.
|
|
||||||
func (m *mux) loop() {
|
|
||||||
var err error
|
|
||||||
for err == nil {
|
|
||||||
err = m.onePacket()
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, ch := range m.chanList.dropAll() {
|
|
||||||
ch.close()
|
|
||||||
}
|
|
||||||
|
|
||||||
close(m.incomingChannels)
|
|
||||||
close(m.incomingRequests)
|
|
||||||
close(m.globalResponses)
|
|
||||||
|
|
||||||
m.conn.Close()
|
|
||||||
|
|
||||||
m.errCond.L.Lock()
|
|
||||||
m.err = err
|
|
||||||
m.errCond.Broadcast()
|
|
||||||
m.errCond.L.Unlock()
|
|
||||||
|
|
||||||
if debugMux {
|
|
||||||
log.Println("loop exit", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// onePacket reads and processes one packet.
|
|
||||||
func (m *mux) onePacket() error {
|
|
||||||
packet, err := m.conn.readPacket()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if debugMux {
|
|
||||||
if packet[0] == msgChannelData || packet[0] == msgChannelExtendedData {
|
|
||||||
log.Printf("decoding(%d): data packet - %d bytes", m.chanList.offset, len(packet))
|
|
||||||
} else {
|
|
||||||
p, _ := decode(packet)
|
|
||||||
log.Printf("decoding(%d): %d %#v - %d bytes", m.chanList.offset, packet[0], p, len(packet))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch packet[0] {
|
|
||||||
case msgChannelOpen:
|
|
||||||
return m.handleChannelOpen(packet)
|
|
||||||
case msgGlobalRequest, msgRequestSuccess, msgRequestFailure:
|
|
||||||
return m.handleGlobalPacket(packet)
|
|
||||||
}
|
|
||||||
|
|
||||||
// assume a channel packet.
|
|
||||||
if len(packet) < 5 {
|
|
||||||
return parseError(packet[0])
|
|
||||||
}
|
|
||||||
id := binary.BigEndian.Uint32(packet[1:])
|
|
||||||
ch := m.chanList.getChan(id)
|
|
||||||
if ch == nil {
|
|
||||||
return fmt.Errorf("ssh: invalid channel %d", id)
|
|
||||||
}
|
|
||||||
|
|
||||||
return ch.handlePacket(packet)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *mux) handleGlobalPacket(packet []byte) error {
|
|
||||||
msg, err := decode(packet)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
switch msg := msg.(type) {
|
|
||||||
case *globalRequestMsg:
|
|
||||||
m.incomingRequests <- &Request{
|
|
||||||
Type: msg.Type,
|
|
||||||
WantReply: msg.WantReply,
|
|
||||||
Payload: msg.Data,
|
|
||||||
mux: m,
|
|
||||||
}
|
|
||||||
case *globalRequestSuccessMsg, *globalRequestFailureMsg:
|
|
||||||
m.globalResponses <- msg
|
|
||||||
default:
|
|
||||||
panic(fmt.Sprintf("not a global message %#v", msg))
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// handleChannelOpen schedules a channel to be Accept()ed.
|
|
||||||
func (m *mux) handleChannelOpen(packet []byte) error {
|
|
||||||
var msg channelOpenMsg
|
|
||||||
if err := Unmarshal(packet, &msg); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if msg.MaxPacketSize < minPacketLength || msg.MaxPacketSize > 1<<31 {
|
|
||||||
failMsg := channelOpenFailureMsg{
|
|
||||||
PeersID: msg.PeersID,
|
|
||||||
Reason: ConnectionFailed,
|
|
||||||
Message: "invalid request",
|
|
||||||
Language: "en_US.UTF-8",
|
|
||||||
}
|
|
||||||
return m.sendMessage(failMsg)
|
|
||||||
}
|
|
||||||
|
|
||||||
c := m.newChannel(msg.ChanType, channelInbound, msg.TypeSpecificData)
|
|
||||||
c.remoteId = msg.PeersID
|
|
||||||
c.maxRemotePayload = msg.MaxPacketSize
|
|
||||||
c.remoteWin.add(msg.PeersWindow)
|
|
||||||
m.incomingChannels <- c
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *mux) OpenChannel(chanType string, extra []byte) (Channel, <-chan *Request, error) {
|
|
||||||
ch, err := m.openChannel(chanType, extra)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return ch, ch.incomingRequests, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *mux) openChannel(chanType string, extra []byte) (*channel, error) {
|
|
||||||
ch := m.newChannel(chanType, channelOutbound, extra)
|
|
||||||
|
|
||||||
ch.maxIncomingPayload = channelMaxPacket
|
|
||||||
|
|
||||||
open := channelOpenMsg{
|
|
||||||
ChanType: chanType,
|
|
||||||
PeersWindow: ch.myWindow,
|
|
||||||
MaxPacketSize: ch.maxIncomingPayload,
|
|
||||||
TypeSpecificData: extra,
|
|
||||||
PeersID: ch.localId,
|
|
||||||
}
|
|
||||||
if err := m.sendMessage(open); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
switch msg := (<-ch.msg).(type) {
|
|
||||||
case *channelOpenConfirmMsg:
|
|
||||||
return ch, nil
|
|
||||||
case *channelOpenFailureMsg:
|
|
||||||
return nil, &OpenChannelError{msg.Reason, msg.Message}
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("ssh: unexpected packet in response to channel open: %T", msg)
|
|
||||||
}
|
|
||||||
}
|
|
716
vendor/golang.org/x/crypto/ssh/server.go
generated
vendored
716
vendor/golang.org/x/crypto/ssh/server.go
generated
vendored
@ -1,716 +0,0 @@
|
|||||||
// 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 ssh
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"net"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// The Permissions type holds fine-grained permissions that are
|
|
||||||
// specific to a user or a specific authentication method for a user.
|
|
||||||
// The Permissions value for a successful authentication attempt is
|
|
||||||
// available in ServerConn, so it can be used to pass information from
|
|
||||||
// the user-authentication phase to the application layer.
|
|
||||||
type Permissions struct {
|
|
||||||
// CriticalOptions indicate restrictions to the default
|
|
||||||
// permissions, and are typically used in conjunction with
|
|
||||||
// user certificates. The standard for SSH certificates
|
|
||||||
// defines "force-command" (only allow the given command to
|
|
||||||
// execute) and "source-address" (only allow connections from
|
|
||||||
// the given address). The SSH package currently only enforces
|
|
||||||
// the "source-address" critical option. It is up to server
|
|
||||||
// implementations to enforce other critical options, such as
|
|
||||||
// "force-command", by checking them after the SSH handshake
|
|
||||||
// is successful. In general, SSH servers should reject
|
|
||||||
// connections that specify critical options that are unknown
|
|
||||||
// or not supported.
|
|
||||||
CriticalOptions map[string]string
|
|
||||||
|
|
||||||
// Extensions are extra functionality that the server may
|
|
||||||
// offer on authenticated connections. Lack of support for an
|
|
||||||
// extension does not preclude authenticating a user. Common
|
|
||||||
// extensions are "permit-agent-forwarding",
|
|
||||||
// "permit-X11-forwarding". The Go SSH library currently does
|
|
||||||
// not act on any extension, and it is up to server
|
|
||||||
// implementations to honor them. Extensions can be used to
|
|
||||||
// pass data from the authentication callbacks to the server
|
|
||||||
// application layer.
|
|
||||||
Extensions map[string]string
|
|
||||||
}
|
|
||||||
|
|
||||||
type GSSAPIWithMICConfig struct {
|
|
||||||
// AllowLogin, must be set, is called when gssapi-with-mic
|
|
||||||
// authentication is selected (RFC 4462 section 3). The srcName is from the
|
|
||||||
// results of the GSS-API authentication. The format is username@DOMAIN.
|
|
||||||
// GSSAPI just guarantees to the server who the user is, but not if they can log in, and with what permissions.
|
|
||||||
// This callback is called after the user identity is established with GSSAPI to decide if the user can login with
|
|
||||||
// which permissions. If the user is allowed to login, it should return a nil error.
|
|
||||||
AllowLogin func(conn ConnMetadata, srcName string) (*Permissions, error)
|
|
||||||
|
|
||||||
// Server must be set. It's the implementation
|
|
||||||
// of the GSSAPIServer interface. See GSSAPIServer interface for details.
|
|
||||||
Server GSSAPIServer
|
|
||||||
}
|
|
||||||
|
|
||||||
// ServerConfig holds server specific configuration data.
|
|
||||||
type ServerConfig struct {
|
|
||||||
// Config contains configuration shared between client and server.
|
|
||||||
Config
|
|
||||||
|
|
||||||
hostKeys []Signer
|
|
||||||
|
|
||||||
// NoClientAuth is true if clients are allowed to connect without
|
|
||||||
// authenticating.
|
|
||||||
NoClientAuth bool
|
|
||||||
|
|
||||||
// MaxAuthTries specifies the maximum number of authentication attempts
|
|
||||||
// permitted per connection. If set to a negative number, the number of
|
|
||||||
// attempts are unlimited. If set to zero, the number of attempts are limited
|
|
||||||
// to 6.
|
|
||||||
MaxAuthTries int
|
|
||||||
|
|
||||||
// PasswordCallback, if non-nil, is called when a user
|
|
||||||
// attempts to authenticate using a password.
|
|
||||||
PasswordCallback func(conn ConnMetadata, password []byte) (*Permissions, error)
|
|
||||||
|
|
||||||
// PublicKeyCallback, if non-nil, is called when a client
|
|
||||||
// offers a public key for authentication. It must return a nil error
|
|
||||||
// if the given public key can be used to authenticate the
|
|
||||||
// given user. For example, see CertChecker.Authenticate. A
|
|
||||||
// call to this function does not guarantee that the key
|
|
||||||
// offered is in fact used to authenticate. To record any data
|
|
||||||
// depending on the public key, store it inside a
|
|
||||||
// Permissions.Extensions entry.
|
|
||||||
PublicKeyCallback func(conn ConnMetadata, key PublicKey) (*Permissions, error)
|
|
||||||
|
|
||||||
// KeyboardInteractiveCallback, if non-nil, is called when
|
|
||||||
// keyboard-interactive authentication is selected (RFC
|
|
||||||
// 4256). The client object's Challenge function should be
|
|
||||||
// used to query the user. The callback may offer multiple
|
|
||||||
// Challenge rounds. To avoid information leaks, the client
|
|
||||||
// should be presented a challenge even if the user is
|
|
||||||
// unknown.
|
|
||||||
KeyboardInteractiveCallback func(conn ConnMetadata, client KeyboardInteractiveChallenge) (*Permissions, error)
|
|
||||||
|
|
||||||
// AuthLogCallback, if non-nil, is called to log all authentication
|
|
||||||
// attempts.
|
|
||||||
AuthLogCallback func(conn ConnMetadata, method string, err error)
|
|
||||||
|
|
||||||
// ServerVersion is the version identification string to announce in
|
|
||||||
// the public handshake.
|
|
||||||
// If empty, a reasonable default is used.
|
|
||||||
// Note that RFC 4253 section 4.2 requires that this string start with
|
|
||||||
// "SSH-2.0-".
|
|
||||||
ServerVersion string
|
|
||||||
|
|
||||||
// BannerCallback, if present, is called and the return string is sent to
|
|
||||||
// the client after key exchange completed but before authentication.
|
|
||||||
BannerCallback func(conn ConnMetadata) string
|
|
||||||
|
|
||||||
// GSSAPIWithMICConfig includes gssapi server and callback, which if both non-nil, is used
|
|
||||||
// when gssapi-with-mic authentication is selected (RFC 4462 section 3).
|
|
||||||
GSSAPIWithMICConfig *GSSAPIWithMICConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddHostKey adds a private key as a host key. If an existing host
|
|
||||||
// key exists with the same algorithm, it is overwritten. Each server
|
|
||||||
// config must have at least one host key.
|
|
||||||
func (s *ServerConfig) AddHostKey(key Signer) {
|
|
||||||
for i, k := range s.hostKeys {
|
|
||||||
if k.PublicKey().Type() == key.PublicKey().Type() {
|
|
||||||
s.hostKeys[i] = key
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
s.hostKeys = append(s.hostKeys, key)
|
|
||||||
}
|
|
||||||
|
|
||||||
// cachedPubKey contains the results of querying whether a public key is
|
|
||||||
// acceptable for a user.
|
|
||||||
type cachedPubKey struct {
|
|
||||||
user string
|
|
||||||
pubKeyData []byte
|
|
||||||
result error
|
|
||||||
perms *Permissions
|
|
||||||
}
|
|
||||||
|
|
||||||
const maxCachedPubKeys = 16
|
|
||||||
|
|
||||||
// pubKeyCache caches tests for public keys. Since SSH clients
|
|
||||||
// will query whether a public key is acceptable before attempting to
|
|
||||||
// authenticate with it, we end up with duplicate queries for public
|
|
||||||
// key validity. The cache only applies to a single ServerConn.
|
|
||||||
type pubKeyCache struct {
|
|
||||||
keys []cachedPubKey
|
|
||||||
}
|
|
||||||
|
|
||||||
// get returns the result for a given user/algo/key tuple.
|
|
||||||
func (c *pubKeyCache) get(user string, pubKeyData []byte) (cachedPubKey, bool) {
|
|
||||||
for _, k := range c.keys {
|
|
||||||
if k.user == user && bytes.Equal(k.pubKeyData, pubKeyData) {
|
|
||||||
return k, true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return cachedPubKey{}, false
|
|
||||||
}
|
|
||||||
|
|
||||||
// add adds the given tuple to the cache.
|
|
||||||
func (c *pubKeyCache) add(candidate cachedPubKey) {
|
|
||||||
if len(c.keys) < maxCachedPubKeys {
|
|
||||||
c.keys = append(c.keys, candidate)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ServerConn is an authenticated SSH connection, as seen from the
|
|
||||||
// server
|
|
||||||
type ServerConn struct {
|
|
||||||
Conn
|
|
||||||
|
|
||||||
// If the succeeding authentication callback returned a
|
|
||||||
// non-nil Permissions pointer, it is stored here.
|
|
||||||
Permissions *Permissions
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewServerConn starts a new SSH server with c as the underlying
|
|
||||||
// transport. It starts with a handshake and, if the handshake is
|
|
||||||
// unsuccessful, it closes the connection and returns an error. The
|
|
||||||
// Request and NewChannel channels must be serviced, or the connection
|
|
||||||
// will hang.
|
|
||||||
//
|
|
||||||
// The returned error may be of type *ServerAuthError for
|
|
||||||
// authentication errors.
|
|
||||||
func NewServerConn(c net.Conn, config *ServerConfig) (*ServerConn, <-chan NewChannel, <-chan *Request, error) {
|
|
||||||
fullConf := *config
|
|
||||||
fullConf.SetDefaults()
|
|
||||||
if fullConf.MaxAuthTries == 0 {
|
|
||||||
fullConf.MaxAuthTries = 6
|
|
||||||
}
|
|
||||||
// Check if the config contains any unsupported key exchanges
|
|
||||||
for _, kex := range fullConf.KeyExchanges {
|
|
||||||
if _, ok := serverForbiddenKexAlgos[kex]; ok {
|
|
||||||
return nil, nil, nil, fmt.Errorf("ssh: unsupported key exchange %s for server", kex)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
s := &connection{
|
|
||||||
sshConn: sshConn{conn: c},
|
|
||||||
}
|
|
||||||
perms, err := s.serverHandshake(&fullConf)
|
|
||||||
if err != nil {
|
|
||||||
c.Close()
|
|
||||||
return nil, nil, nil, err
|
|
||||||
}
|
|
||||||
return &ServerConn{s, perms}, s.mux.incomingChannels, s.mux.incomingRequests, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// signAndMarshal signs the data with the appropriate algorithm,
|
|
||||||
// and serializes the result in SSH wire format.
|
|
||||||
func signAndMarshal(k Signer, rand io.Reader, data []byte) ([]byte, error) {
|
|
||||||
sig, err := k.Sign(rand, data)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return Marshal(sig), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// handshake performs key exchange and user authentication.
|
|
||||||
func (s *connection) serverHandshake(config *ServerConfig) (*Permissions, error) {
|
|
||||||
if len(config.hostKeys) == 0 {
|
|
||||||
return nil, errors.New("ssh: server has no host keys")
|
|
||||||
}
|
|
||||||
|
|
||||||
if !config.NoClientAuth && config.PasswordCallback == nil && config.PublicKeyCallback == nil &&
|
|
||||||
config.KeyboardInteractiveCallback == nil && (config.GSSAPIWithMICConfig == nil ||
|
|
||||||
config.GSSAPIWithMICConfig.AllowLogin == nil || config.GSSAPIWithMICConfig.Server == nil) {
|
|
||||||
return nil, errors.New("ssh: no authentication methods configured but NoClientAuth is also false")
|
|
||||||
}
|
|
||||||
|
|
||||||
if config.ServerVersion != "" {
|
|
||||||
s.serverVersion = []byte(config.ServerVersion)
|
|
||||||
} else {
|
|
||||||
s.serverVersion = []byte(packageVersion)
|
|
||||||
}
|
|
||||||
var err error
|
|
||||||
s.clientVersion, err = exchangeVersions(s.sshConn.conn, s.serverVersion)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
tr := newTransport(s.sshConn.conn, config.Rand, false /* not client */)
|
|
||||||
s.transport = newServerTransport(tr, s.clientVersion, s.serverVersion, config)
|
|
||||||
|
|
||||||
if err := s.transport.waitSession(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// We just did the key change, so the session ID is established.
|
|
||||||
s.sessionID = s.transport.getSessionID()
|
|
||||||
|
|
||||||
var packet []byte
|
|
||||||
if packet, err = s.transport.readPacket(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var serviceRequest serviceRequestMsg
|
|
||||||
if err = Unmarshal(packet, &serviceRequest); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if serviceRequest.Service != serviceUserAuth {
|
|
||||||
return nil, errors.New("ssh: requested service '" + serviceRequest.Service + "' before authenticating")
|
|
||||||
}
|
|
||||||
serviceAccept := serviceAcceptMsg{
|
|
||||||
Service: serviceUserAuth,
|
|
||||||
}
|
|
||||||
if err := s.transport.writePacket(Marshal(&serviceAccept)); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
perms, err := s.serverAuthenticate(config)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
s.mux = newMux(s.transport)
|
|
||||||
return perms, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func isAcceptableAlgo(algo string) bool {
|
|
||||||
switch algo {
|
|
||||||
case KeyAlgoRSA, KeyAlgoDSA, KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521, KeyAlgoED25519,
|
|
||||||
CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, CertAlgoECDSA384v01, CertAlgoECDSA521v01, CertAlgoED25519v01:
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkSourceAddress(addr net.Addr, sourceAddrs string) error {
|
|
||||||
if addr == nil {
|
|
||||||
return errors.New("ssh: no address known for client, but source-address match required")
|
|
||||||
}
|
|
||||||
|
|
||||||
tcpAddr, ok := addr.(*net.TCPAddr)
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("ssh: remote address %v is not an TCP address when checking source-address match", addr)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, sourceAddr := range strings.Split(sourceAddrs, ",") {
|
|
||||||
if allowedIP := net.ParseIP(sourceAddr); allowedIP != nil {
|
|
||||||
if allowedIP.Equal(tcpAddr.IP) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_, ipNet, err := net.ParseCIDR(sourceAddr)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("ssh: error parsing source-address restriction %q: %v", sourceAddr, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if ipNet.Contains(tcpAddr.IP) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Errorf("ssh: remote address %v is not allowed because of source-address restriction", addr)
|
|
||||||
}
|
|
||||||
|
|
||||||
func gssExchangeToken(gssapiConfig *GSSAPIWithMICConfig, firstToken []byte, s *connection,
|
|
||||||
sessionID []byte, userAuthReq userAuthRequestMsg) (authErr error, perms *Permissions, err error) {
|
|
||||||
gssAPIServer := gssapiConfig.Server
|
|
||||||
defer gssAPIServer.DeleteSecContext()
|
|
||||||
var srcName string
|
|
||||||
for {
|
|
||||||
var (
|
|
||||||
outToken []byte
|
|
||||||
needContinue bool
|
|
||||||
)
|
|
||||||
outToken, srcName, needContinue, err = gssAPIServer.AcceptSecContext(firstToken)
|
|
||||||
if err != nil {
|
|
||||||
return err, nil, nil
|
|
||||||
}
|
|
||||||
if len(outToken) != 0 {
|
|
||||||
if err := s.transport.writePacket(Marshal(&userAuthGSSAPIToken{
|
|
||||||
Token: outToken,
|
|
||||||
})); err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !needContinue {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
packet, err := s.transport.readPacket()
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
userAuthGSSAPITokenReq := &userAuthGSSAPIToken{}
|
|
||||||
if err := Unmarshal(packet, userAuthGSSAPITokenReq); err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
packet, err := s.transport.readPacket()
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
userAuthGSSAPIMICReq := &userAuthGSSAPIMIC{}
|
|
||||||
if err := Unmarshal(packet, userAuthGSSAPIMICReq); err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
mic := buildMIC(string(sessionID), userAuthReq.User, userAuthReq.Service, userAuthReq.Method)
|
|
||||||
if err := gssAPIServer.VerifyMIC(mic, userAuthGSSAPIMICReq.MIC); err != nil {
|
|
||||||
return err, nil, nil
|
|
||||||
}
|
|
||||||
perms, authErr = gssapiConfig.AllowLogin(s, srcName)
|
|
||||||
return authErr, perms, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ServerAuthError represents server authentication errors and is
|
|
||||||
// sometimes returned by NewServerConn. It appends any authentication
|
|
||||||
// errors that may occur, and is returned if all of the authentication
|
|
||||||
// methods provided by the user failed to authenticate.
|
|
||||||
type ServerAuthError struct {
|
|
||||||
// Errors contains authentication errors returned by the authentication
|
|
||||||
// callback methods. The first entry is typically ErrNoAuth.
|
|
||||||
Errors []error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l ServerAuthError) Error() string {
|
|
||||||
var errs []string
|
|
||||||
for _, err := range l.Errors {
|
|
||||||
errs = append(errs, err.Error())
|
|
||||||
}
|
|
||||||
return "[" + strings.Join(errs, ", ") + "]"
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrNoAuth is the error value returned if no
|
|
||||||
// authentication method has been passed yet. This happens as a normal
|
|
||||||
// part of the authentication loop, since the client first tries
|
|
||||||
// 'none' authentication to discover available methods.
|
|
||||||
// It is returned in ServerAuthError.Errors from NewServerConn.
|
|
||||||
var ErrNoAuth = errors.New("ssh: no auth passed yet")
|
|
||||||
|
|
||||||
func (s *connection) serverAuthenticate(config *ServerConfig) (*Permissions, error) {
|
|
||||||
sessionID := s.transport.getSessionID()
|
|
||||||
var cache pubKeyCache
|
|
||||||
var perms *Permissions
|
|
||||||
|
|
||||||
authFailures := 0
|
|
||||||
var authErrs []error
|
|
||||||
var displayedBanner bool
|
|
||||||
|
|
||||||
userAuthLoop:
|
|
||||||
for {
|
|
||||||
if authFailures >= config.MaxAuthTries && config.MaxAuthTries > 0 {
|
|
||||||
discMsg := &disconnectMsg{
|
|
||||||
Reason: 2,
|
|
||||||
Message: "too many authentication failures",
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := s.transport.writePacket(Marshal(discMsg)); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, discMsg
|
|
||||||
}
|
|
||||||
|
|
||||||
var userAuthReq userAuthRequestMsg
|
|
||||||
if packet, err := s.transport.readPacket(); err != nil {
|
|
||||||
if err == io.EOF {
|
|
||||||
return nil, &ServerAuthError{Errors: authErrs}
|
|
||||||
}
|
|
||||||
return nil, err
|
|
||||||
} else if err = Unmarshal(packet, &userAuthReq); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if userAuthReq.Service != serviceSSH {
|
|
||||||
return nil, errors.New("ssh: client attempted to negotiate for unknown service: " + userAuthReq.Service)
|
|
||||||
}
|
|
||||||
|
|
||||||
s.user = userAuthReq.User
|
|
||||||
|
|
||||||
if !displayedBanner && config.BannerCallback != nil {
|
|
||||||
displayedBanner = true
|
|
||||||
msg := config.BannerCallback(s)
|
|
||||||
if msg != "" {
|
|
||||||
bannerMsg := &userAuthBannerMsg{
|
|
||||||
Message: msg,
|
|
||||||
}
|
|
||||||
if err := s.transport.writePacket(Marshal(bannerMsg)); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
perms = nil
|
|
||||||
authErr := ErrNoAuth
|
|
||||||
|
|
||||||
switch userAuthReq.Method {
|
|
||||||
case "none":
|
|
||||||
if config.NoClientAuth {
|
|
||||||
authErr = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// allow initial attempt of 'none' without penalty
|
|
||||||
if authFailures == 0 {
|
|
||||||
authFailures--
|
|
||||||
}
|
|
||||||
case "password":
|
|
||||||
if config.PasswordCallback == nil {
|
|
||||||
authErr = errors.New("ssh: password auth not configured")
|
|
||||||
break
|
|
||||||
}
|
|
||||||
payload := userAuthReq.Payload
|
|
||||||
if len(payload) < 1 || payload[0] != 0 {
|
|
||||||
return nil, parseError(msgUserAuthRequest)
|
|
||||||
}
|
|
||||||
payload = payload[1:]
|
|
||||||
password, payload, ok := parseString(payload)
|
|
||||||
if !ok || len(payload) > 0 {
|
|
||||||
return nil, parseError(msgUserAuthRequest)
|
|
||||||
}
|
|
||||||
|
|
||||||
perms, authErr = config.PasswordCallback(s, password)
|
|
||||||
case "keyboard-interactive":
|
|
||||||
if config.KeyboardInteractiveCallback == nil {
|
|
||||||
authErr = errors.New("ssh: keyboard-interactive auth not configured")
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
prompter := &sshClientKeyboardInteractive{s}
|
|
||||||
perms, authErr = config.KeyboardInteractiveCallback(s, prompter.Challenge)
|
|
||||||
case "publickey":
|
|
||||||
if config.PublicKeyCallback == nil {
|
|
||||||
authErr = errors.New("ssh: publickey auth not configured")
|
|
||||||
break
|
|
||||||
}
|
|
||||||
payload := userAuthReq.Payload
|
|
||||||
if len(payload) < 1 {
|
|
||||||
return nil, parseError(msgUserAuthRequest)
|
|
||||||
}
|
|
||||||
isQuery := payload[0] == 0
|
|
||||||
payload = payload[1:]
|
|
||||||
algoBytes, payload, ok := parseString(payload)
|
|
||||||
if !ok {
|
|
||||||
return nil, parseError(msgUserAuthRequest)
|
|
||||||
}
|
|
||||||
algo := string(algoBytes)
|
|
||||||
if !isAcceptableAlgo(algo) {
|
|
||||||
authErr = fmt.Errorf("ssh: algorithm %q not accepted", algo)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
pubKeyData, payload, ok := parseString(payload)
|
|
||||||
if !ok {
|
|
||||||
return nil, parseError(msgUserAuthRequest)
|
|
||||||
}
|
|
||||||
|
|
||||||
pubKey, err := ParsePublicKey(pubKeyData)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
candidate, ok := cache.get(s.user, pubKeyData)
|
|
||||||
if !ok {
|
|
||||||
candidate.user = s.user
|
|
||||||
candidate.pubKeyData = pubKeyData
|
|
||||||
candidate.perms, candidate.result = config.PublicKeyCallback(s, pubKey)
|
|
||||||
if candidate.result == nil && candidate.perms != nil && candidate.perms.CriticalOptions != nil && candidate.perms.CriticalOptions[sourceAddressCriticalOption] != "" {
|
|
||||||
candidate.result = checkSourceAddress(
|
|
||||||
s.RemoteAddr(),
|
|
||||||
candidate.perms.CriticalOptions[sourceAddressCriticalOption])
|
|
||||||
}
|
|
||||||
cache.add(candidate)
|
|
||||||
}
|
|
||||||
|
|
||||||
if isQuery {
|
|
||||||
// The client can query if the given public key
|
|
||||||
// would be okay.
|
|
||||||
|
|
||||||
if len(payload) > 0 {
|
|
||||||
return nil, parseError(msgUserAuthRequest)
|
|
||||||
}
|
|
||||||
|
|
||||||
if candidate.result == nil {
|
|
||||||
okMsg := userAuthPubKeyOkMsg{
|
|
||||||
Algo: algo,
|
|
||||||
PubKey: pubKeyData,
|
|
||||||
}
|
|
||||||
if err = s.transport.writePacket(Marshal(&okMsg)); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
continue userAuthLoop
|
|
||||||
}
|
|
||||||
authErr = candidate.result
|
|
||||||
} else {
|
|
||||||
sig, payload, ok := parseSignature(payload)
|
|
||||||
if !ok || len(payload) > 0 {
|
|
||||||
return nil, parseError(msgUserAuthRequest)
|
|
||||||
}
|
|
||||||
// Ensure the public key algo and signature algo
|
|
||||||
// are supported. Compare the private key
|
|
||||||
// algorithm name that corresponds to algo with
|
|
||||||
// sig.Format. This is usually the same, but
|
|
||||||
// for certs, the names differ.
|
|
||||||
if !isAcceptableAlgo(sig.Format) {
|
|
||||||
authErr = fmt.Errorf("ssh: algorithm %q not accepted", sig.Format)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
signedData := buildDataSignedForAuth(sessionID, userAuthReq, algoBytes, pubKeyData)
|
|
||||||
|
|
||||||
if err := pubKey.Verify(signedData, sig); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
authErr = candidate.result
|
|
||||||
perms = candidate.perms
|
|
||||||
}
|
|
||||||
case "gssapi-with-mic":
|
|
||||||
gssapiConfig := config.GSSAPIWithMICConfig
|
|
||||||
userAuthRequestGSSAPI, err := parseGSSAPIPayload(userAuthReq.Payload)
|
|
||||||
if err != nil {
|
|
||||||
return nil, parseError(msgUserAuthRequest)
|
|
||||||
}
|
|
||||||
// OpenSSH supports Kerberos V5 mechanism only for GSS-API authentication.
|
|
||||||
if userAuthRequestGSSAPI.N == 0 {
|
|
||||||
authErr = fmt.Errorf("ssh: Mechanism negotiation is not supported")
|
|
||||||
break
|
|
||||||
}
|
|
||||||
var i uint32
|
|
||||||
present := false
|
|
||||||
for i = 0; i < userAuthRequestGSSAPI.N; i++ {
|
|
||||||
if userAuthRequestGSSAPI.OIDS[i].Equal(krb5Mesh) {
|
|
||||||
present = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !present {
|
|
||||||
authErr = fmt.Errorf("ssh: GSSAPI authentication must use the Kerberos V5 mechanism")
|
|
||||||
break
|
|
||||||
}
|
|
||||||
// Initial server response, see RFC 4462 section 3.3.
|
|
||||||
if err := s.transport.writePacket(Marshal(&userAuthGSSAPIResponse{
|
|
||||||
SupportMech: krb5OID,
|
|
||||||
})); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// Exchange token, see RFC 4462 section 3.4.
|
|
||||||
packet, err := s.transport.readPacket()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
userAuthGSSAPITokenReq := &userAuthGSSAPIToken{}
|
|
||||||
if err := Unmarshal(packet, userAuthGSSAPITokenReq); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
authErr, perms, err = gssExchangeToken(gssapiConfig, userAuthGSSAPITokenReq.Token, s, sessionID,
|
|
||||||
userAuthReq)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
authErr = fmt.Errorf("ssh: unknown method %q", userAuthReq.Method)
|
|
||||||
}
|
|
||||||
|
|
||||||
authErrs = append(authErrs, authErr)
|
|
||||||
|
|
||||||
if config.AuthLogCallback != nil {
|
|
||||||
config.AuthLogCallback(s, userAuthReq.Method, authErr)
|
|
||||||
}
|
|
||||||
|
|
||||||
if authErr == nil {
|
|
||||||
break userAuthLoop
|
|
||||||
}
|
|
||||||
|
|
||||||
authFailures++
|
|
||||||
|
|
||||||
var failureMsg userAuthFailureMsg
|
|
||||||
if config.PasswordCallback != nil {
|
|
||||||
failureMsg.Methods = append(failureMsg.Methods, "password")
|
|
||||||
}
|
|
||||||
if config.PublicKeyCallback != nil {
|
|
||||||
failureMsg.Methods = append(failureMsg.Methods, "publickey")
|
|
||||||
}
|
|
||||||
if config.KeyboardInteractiveCallback != nil {
|
|
||||||
failureMsg.Methods = append(failureMsg.Methods, "keyboard-interactive")
|
|
||||||
}
|
|
||||||
if config.GSSAPIWithMICConfig != nil && config.GSSAPIWithMICConfig.Server != nil &&
|
|
||||||
config.GSSAPIWithMICConfig.AllowLogin != nil {
|
|
||||||
failureMsg.Methods = append(failureMsg.Methods, "gssapi-with-mic")
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(failureMsg.Methods) == 0 {
|
|
||||||
return nil, errors.New("ssh: no authentication methods configured but NoClientAuth is also false")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := s.transport.writePacket(Marshal(&failureMsg)); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := s.transport.writePacket([]byte{msgUserAuthSuccess}); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return perms, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// sshClientKeyboardInteractive implements a ClientKeyboardInteractive by
|
|
||||||
// asking the client on the other side of a ServerConn.
|
|
||||||
type sshClientKeyboardInteractive struct {
|
|
||||||
*connection
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *sshClientKeyboardInteractive) Challenge(user, instruction string, questions []string, echos []bool) (answers []string, err error) {
|
|
||||||
if len(questions) != len(echos) {
|
|
||||||
return nil, errors.New("ssh: echos and questions must have equal length")
|
|
||||||
}
|
|
||||||
|
|
||||||
var prompts []byte
|
|
||||||
for i := range questions {
|
|
||||||
prompts = appendString(prompts, questions[i])
|
|
||||||
prompts = appendBool(prompts, echos[i])
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := c.transport.writePacket(Marshal(&userAuthInfoRequestMsg{
|
|
||||||
Instruction: instruction,
|
|
||||||
NumPrompts: uint32(len(questions)),
|
|
||||||
Prompts: prompts,
|
|
||||||
})); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
packet, err := c.transport.readPacket()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if packet[0] != msgUserAuthInfoResponse {
|
|
||||||
return nil, unexpectedMessageError(msgUserAuthInfoResponse, packet[0])
|
|
||||||
}
|
|
||||||
packet = packet[1:]
|
|
||||||
|
|
||||||
n, packet, ok := parseUint32(packet)
|
|
||||||
if !ok || int(n) != len(questions) {
|
|
||||||
return nil, parseError(msgUserAuthInfoResponse)
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := uint32(0); i < n; i++ {
|
|
||||||
ans, rest, ok := parseString(packet)
|
|
||||||
if !ok {
|
|
||||||
return nil, parseError(msgUserAuthInfoResponse)
|
|
||||||
}
|
|
||||||
|
|
||||||
answers = append(answers, string(ans))
|
|
||||||
packet = rest
|
|
||||||
}
|
|
||||||
if len(packet) != 0 {
|
|
||||||
return nil, errors.New("ssh: junk at end of message")
|
|
||||||
}
|
|
||||||
|
|
||||||
return answers, nil
|
|
||||||
}
|
|
647
vendor/golang.org/x/crypto/ssh/session.go
generated
vendored
647
vendor/golang.org/x/crypto/ssh/session.go
generated
vendored
@ -1,647 +0,0 @@
|
|||||||
// 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 ssh
|
|
||||||
|
|
||||||
// Session implements an interactive session described in
|
|
||||||
// "RFC 4254, section 6".
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/binary"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Signal string
|
|
||||||
|
|
||||||
// POSIX signals as listed in RFC 4254 Section 6.10.
|
|
||||||
const (
|
|
||||||
SIGABRT Signal = "ABRT"
|
|
||||||
SIGALRM Signal = "ALRM"
|
|
||||||
SIGFPE Signal = "FPE"
|
|
||||||
SIGHUP Signal = "HUP"
|
|
||||||
SIGILL Signal = "ILL"
|
|
||||||
SIGINT Signal = "INT"
|
|
||||||
SIGKILL Signal = "KILL"
|
|
||||||
SIGPIPE Signal = "PIPE"
|
|
||||||
SIGQUIT Signal = "QUIT"
|
|
||||||
SIGSEGV Signal = "SEGV"
|
|
||||||
SIGTERM Signal = "TERM"
|
|
||||||
SIGUSR1 Signal = "USR1"
|
|
||||||
SIGUSR2 Signal = "USR2"
|
|
||||||
)
|
|
||||||
|
|
||||||
var signals = map[Signal]int{
|
|
||||||
SIGABRT: 6,
|
|
||||||
SIGALRM: 14,
|
|
||||||
SIGFPE: 8,
|
|
||||||
SIGHUP: 1,
|
|
||||||
SIGILL: 4,
|
|
||||||
SIGINT: 2,
|
|
||||||
SIGKILL: 9,
|
|
||||||
SIGPIPE: 13,
|
|
||||||
SIGQUIT: 3,
|
|
||||||
SIGSEGV: 11,
|
|
||||||
SIGTERM: 15,
|
|
||||||
}
|
|
||||||
|
|
||||||
type TerminalModes map[uint8]uint32
|
|
||||||
|
|
||||||
// POSIX terminal mode flags as listed in RFC 4254 Section 8.
|
|
||||||
const (
|
|
||||||
tty_OP_END = 0
|
|
||||||
VINTR = 1
|
|
||||||
VQUIT = 2
|
|
||||||
VERASE = 3
|
|
||||||
VKILL = 4
|
|
||||||
VEOF = 5
|
|
||||||
VEOL = 6
|
|
||||||
VEOL2 = 7
|
|
||||||
VSTART = 8
|
|
||||||
VSTOP = 9
|
|
||||||
VSUSP = 10
|
|
||||||
VDSUSP = 11
|
|
||||||
VREPRINT = 12
|
|
||||||
VWERASE = 13
|
|
||||||
VLNEXT = 14
|
|
||||||
VFLUSH = 15
|
|
||||||
VSWTCH = 16
|
|
||||||
VSTATUS = 17
|
|
||||||
VDISCARD = 18
|
|
||||||
IGNPAR = 30
|
|
||||||
PARMRK = 31
|
|
||||||
INPCK = 32
|
|
||||||
ISTRIP = 33
|
|
||||||
INLCR = 34
|
|
||||||
IGNCR = 35
|
|
||||||
ICRNL = 36
|
|
||||||
IUCLC = 37
|
|
||||||
IXON = 38
|
|
||||||
IXANY = 39
|
|
||||||
IXOFF = 40
|
|
||||||
IMAXBEL = 41
|
|
||||||
ISIG = 50
|
|
||||||
ICANON = 51
|
|
||||||
XCASE = 52
|
|
||||||
ECHO = 53
|
|
||||||
ECHOE = 54
|
|
||||||
ECHOK = 55
|
|
||||||
ECHONL = 56
|
|
||||||
NOFLSH = 57
|
|
||||||
TOSTOP = 58
|
|
||||||
IEXTEN = 59
|
|
||||||
ECHOCTL = 60
|
|
||||||
ECHOKE = 61
|
|
||||||
PENDIN = 62
|
|
||||||
OPOST = 70
|
|
||||||
OLCUC = 71
|
|
||||||
ONLCR = 72
|
|
||||||
OCRNL = 73
|
|
||||||
ONOCR = 74
|
|
||||||
ONLRET = 75
|
|
||||||
CS7 = 90
|
|
||||||
CS8 = 91
|
|
||||||
PARENB = 92
|
|
||||||
PARODD = 93
|
|
||||||
TTY_OP_ISPEED = 128
|
|
||||||
TTY_OP_OSPEED = 129
|
|
||||||
)
|
|
||||||
|
|
||||||
// A Session represents a connection to a remote command or shell.
|
|
||||||
type Session struct {
|
|
||||||
// Stdin specifies the remote process's standard input.
|
|
||||||
// If Stdin is nil, the remote process reads from an empty
|
|
||||||
// bytes.Buffer.
|
|
||||||
Stdin io.Reader
|
|
||||||
|
|
||||||
// Stdout and Stderr specify the remote process's standard
|
|
||||||
// output and error.
|
|
||||||
//
|
|
||||||
// If either is nil, Run connects the corresponding file
|
|
||||||
// descriptor to an instance of ioutil.Discard. There is a
|
|
||||||
// fixed amount of buffering that is shared for the two streams.
|
|
||||||
// If either blocks it may eventually cause the remote
|
|
||||||
// command to block.
|
|
||||||
Stdout io.Writer
|
|
||||||
Stderr io.Writer
|
|
||||||
|
|
||||||
ch Channel // the channel backing this session
|
|
||||||
started bool // true once Start, Run or Shell is invoked.
|
|
||||||
copyFuncs []func() error
|
|
||||||
errors chan error // one send per copyFunc
|
|
||||||
|
|
||||||
// true if pipe method is active
|
|
||||||
stdinpipe, stdoutpipe, stderrpipe bool
|
|
||||||
|
|
||||||
// stdinPipeWriter is non-nil if StdinPipe has not been called
|
|
||||||
// and Stdin was specified by the user; it is the write end of
|
|
||||||
// a pipe connecting Session.Stdin to the stdin channel.
|
|
||||||
stdinPipeWriter io.WriteCloser
|
|
||||||
|
|
||||||
exitStatus chan error
|
|
||||||
}
|
|
||||||
|
|
||||||
// SendRequest sends an out-of-band channel request on the SSH channel
|
|
||||||
// underlying the session.
|
|
||||||
func (s *Session) SendRequest(name string, wantReply bool, payload []byte) (bool, error) {
|
|
||||||
return s.ch.SendRequest(name, wantReply, payload)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Session) Close() error {
|
|
||||||
return s.ch.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
// RFC 4254 Section 6.4.
|
|
||||||
type setenvRequest struct {
|
|
||||||
Name string
|
|
||||||
Value string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setenv sets an environment variable that will be applied to any
|
|
||||||
// command executed by Shell or Run.
|
|
||||||
func (s *Session) Setenv(name, value string) error {
|
|
||||||
msg := setenvRequest{
|
|
||||||
Name: name,
|
|
||||||
Value: value,
|
|
||||||
}
|
|
||||||
ok, err := s.ch.SendRequest("env", true, Marshal(&msg))
|
|
||||||
if err == nil && !ok {
|
|
||||||
err = errors.New("ssh: setenv failed")
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// RFC 4254 Section 6.2.
|
|
||||||
type ptyRequestMsg struct {
|
|
||||||
Term string
|
|
||||||
Columns uint32
|
|
||||||
Rows uint32
|
|
||||||
Width uint32
|
|
||||||
Height uint32
|
|
||||||
Modelist string
|
|
||||||
}
|
|
||||||
|
|
||||||
// RequestPty requests the association of a pty with the session on the remote host.
|
|
||||||
func (s *Session) RequestPty(term string, h, w int, termmodes TerminalModes) error {
|
|
||||||
var tm []byte
|
|
||||||
for k, v := range termmodes {
|
|
||||||
kv := struct {
|
|
||||||
Key byte
|
|
||||||
Val uint32
|
|
||||||
}{k, v}
|
|
||||||
|
|
||||||
tm = append(tm, Marshal(&kv)...)
|
|
||||||
}
|
|
||||||
tm = append(tm, tty_OP_END)
|
|
||||||
req := ptyRequestMsg{
|
|
||||||
Term: term,
|
|
||||||
Columns: uint32(w),
|
|
||||||
Rows: uint32(h),
|
|
||||||
Width: uint32(w * 8),
|
|
||||||
Height: uint32(h * 8),
|
|
||||||
Modelist: string(tm),
|
|
||||||
}
|
|
||||||
ok, err := s.ch.SendRequest("pty-req", true, Marshal(&req))
|
|
||||||
if err == nil && !ok {
|
|
||||||
err = errors.New("ssh: pty-req failed")
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// RFC 4254 Section 6.5.
|
|
||||||
type subsystemRequestMsg struct {
|
|
||||||
Subsystem string
|
|
||||||
}
|
|
||||||
|
|
||||||
// RequestSubsystem requests the association of a subsystem with the session on the remote host.
|
|
||||||
// A subsystem is a predefined command that runs in the background when the ssh session is initiated
|
|
||||||
func (s *Session) RequestSubsystem(subsystem string) error {
|
|
||||||
msg := subsystemRequestMsg{
|
|
||||||
Subsystem: subsystem,
|
|
||||||
}
|
|
||||||
ok, err := s.ch.SendRequest("subsystem", true, Marshal(&msg))
|
|
||||||
if err == nil && !ok {
|
|
||||||
err = errors.New("ssh: subsystem request failed")
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// RFC 4254 Section 6.7.
|
|
||||||
type ptyWindowChangeMsg struct {
|
|
||||||
Columns uint32
|
|
||||||
Rows uint32
|
|
||||||
Width uint32
|
|
||||||
Height uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
// WindowChange informs the remote host about a terminal window dimension change to h rows and w columns.
|
|
||||||
func (s *Session) WindowChange(h, w int) error {
|
|
||||||
req := ptyWindowChangeMsg{
|
|
||||||
Columns: uint32(w),
|
|
||||||
Rows: uint32(h),
|
|
||||||
Width: uint32(w * 8),
|
|
||||||
Height: uint32(h * 8),
|
|
||||||
}
|
|
||||||
_, err := s.ch.SendRequest("window-change", false, Marshal(&req))
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// RFC 4254 Section 6.9.
|
|
||||||
type signalMsg struct {
|
|
||||||
Signal string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Signal sends the given signal to the remote process.
|
|
||||||
// sig is one of the SIG* constants.
|
|
||||||
func (s *Session) Signal(sig Signal) error {
|
|
||||||
msg := signalMsg{
|
|
||||||
Signal: string(sig),
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err := s.ch.SendRequest("signal", false, Marshal(&msg))
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// RFC 4254 Section 6.5.
|
|
||||||
type execMsg struct {
|
|
||||||
Command string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start runs cmd on the remote host. Typically, the remote
|
|
||||||
// server passes cmd to the shell for interpretation.
|
|
||||||
// A Session only accepts one call to Run, Start or Shell.
|
|
||||||
func (s *Session) Start(cmd string) error {
|
|
||||||
if s.started {
|
|
||||||
return errors.New("ssh: session already started")
|
|
||||||
}
|
|
||||||
req := execMsg{
|
|
||||||
Command: cmd,
|
|
||||||
}
|
|
||||||
|
|
||||||
ok, err := s.ch.SendRequest("exec", true, Marshal(&req))
|
|
||||||
if err == nil && !ok {
|
|
||||||
err = fmt.Errorf("ssh: command %v failed", cmd)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return s.start()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run runs cmd on the remote host. Typically, the remote
|
|
||||||
// server passes cmd to the shell for interpretation.
|
|
||||||
// A Session only accepts one call to Run, Start, Shell, Output,
|
|
||||||
// or CombinedOutput.
|
|
||||||
//
|
|
||||||
// The returned error is nil if the command runs, has no problems
|
|
||||||
// copying stdin, stdout, and stderr, and exits with a zero exit
|
|
||||||
// status.
|
|
||||||
//
|
|
||||||
// If the remote server does not send an exit status, an error of type
|
|
||||||
// *ExitMissingError is returned. If the command completes
|
|
||||||
// unsuccessfully or is interrupted by a signal, the error is of type
|
|
||||||
// *ExitError. Other error types may be returned for I/O problems.
|
|
||||||
func (s *Session) Run(cmd string) error {
|
|
||||||
err := s.Start(cmd)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return s.Wait()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Output runs cmd on the remote host and returns its standard output.
|
|
||||||
func (s *Session) Output(cmd string) ([]byte, error) {
|
|
||||||
if s.Stdout != nil {
|
|
||||||
return nil, errors.New("ssh: Stdout already set")
|
|
||||||
}
|
|
||||||
var b bytes.Buffer
|
|
||||||
s.Stdout = &b
|
|
||||||
err := s.Run(cmd)
|
|
||||||
return b.Bytes(), err
|
|
||||||
}
|
|
||||||
|
|
||||||
type singleWriter struct {
|
|
||||||
b bytes.Buffer
|
|
||||||
mu sync.Mutex
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *singleWriter) Write(p []byte) (int, error) {
|
|
||||||
w.mu.Lock()
|
|
||||||
defer w.mu.Unlock()
|
|
||||||
return w.b.Write(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CombinedOutput runs cmd on the remote host and returns its combined
|
|
||||||
// standard output and standard error.
|
|
||||||
func (s *Session) CombinedOutput(cmd string) ([]byte, error) {
|
|
||||||
if s.Stdout != nil {
|
|
||||||
return nil, errors.New("ssh: Stdout already set")
|
|
||||||
}
|
|
||||||
if s.Stderr != nil {
|
|
||||||
return nil, errors.New("ssh: Stderr already set")
|
|
||||||
}
|
|
||||||
var b singleWriter
|
|
||||||
s.Stdout = &b
|
|
||||||
s.Stderr = &b
|
|
||||||
err := s.Run(cmd)
|
|
||||||
return b.b.Bytes(), err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Shell starts a login shell on the remote host. A Session only
|
|
||||||
// accepts one call to Run, Start, Shell, Output, or CombinedOutput.
|
|
||||||
func (s *Session) Shell() error {
|
|
||||||
if s.started {
|
|
||||||
return errors.New("ssh: session already started")
|
|
||||||
}
|
|
||||||
|
|
||||||
ok, err := s.ch.SendRequest("shell", true, nil)
|
|
||||||
if err == nil && !ok {
|
|
||||||
return errors.New("ssh: could not start shell")
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return s.start()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Session) start() error {
|
|
||||||
s.started = true
|
|
||||||
|
|
||||||
type F func(*Session)
|
|
||||||
for _, setupFd := range []F{(*Session).stdin, (*Session).stdout, (*Session).stderr} {
|
|
||||||
setupFd(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
s.errors = make(chan error, len(s.copyFuncs))
|
|
||||||
for _, fn := range s.copyFuncs {
|
|
||||||
go func(fn func() error) {
|
|
||||||
s.errors <- fn()
|
|
||||||
}(fn)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait waits for the remote command to exit.
|
|
||||||
//
|
|
||||||
// The returned error is nil if the command runs, has no problems
|
|
||||||
// copying stdin, stdout, and stderr, and exits with a zero exit
|
|
||||||
// status.
|
|
||||||
//
|
|
||||||
// If the remote server does not send an exit status, an error of type
|
|
||||||
// *ExitMissingError is returned. If the command completes
|
|
||||||
// unsuccessfully or is interrupted by a signal, the error is of type
|
|
||||||
// *ExitError. Other error types may be returned for I/O problems.
|
|
||||||
func (s *Session) Wait() error {
|
|
||||||
if !s.started {
|
|
||||||
return errors.New("ssh: session not started")
|
|
||||||
}
|
|
||||||
waitErr := <-s.exitStatus
|
|
||||||
|
|
||||||
if s.stdinPipeWriter != nil {
|
|
||||||
s.stdinPipeWriter.Close()
|
|
||||||
}
|
|
||||||
var copyError error
|
|
||||||
for range s.copyFuncs {
|
|
||||||
if err := <-s.errors; err != nil && copyError == nil {
|
|
||||||
copyError = err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if waitErr != nil {
|
|
||||||
return waitErr
|
|
||||||
}
|
|
||||||
return copyError
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Session) wait(reqs <-chan *Request) error {
|
|
||||||
wm := Waitmsg{status: -1}
|
|
||||||
// Wait for msg channel to be closed before returning.
|
|
||||||
for msg := range reqs {
|
|
||||||
switch msg.Type {
|
|
||||||
case "exit-status":
|
|
||||||
wm.status = int(binary.BigEndian.Uint32(msg.Payload))
|
|
||||||
case "exit-signal":
|
|
||||||
var sigval struct {
|
|
||||||
Signal string
|
|
||||||
CoreDumped bool
|
|
||||||
Error string
|
|
||||||
Lang string
|
|
||||||
}
|
|
||||||
if err := Unmarshal(msg.Payload, &sigval); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Must sanitize strings?
|
|
||||||
wm.signal = sigval.Signal
|
|
||||||
wm.msg = sigval.Error
|
|
||||||
wm.lang = sigval.Lang
|
|
||||||
default:
|
|
||||||
// This handles keepalives and matches
|
|
||||||
// OpenSSH's behaviour.
|
|
||||||
if msg.WantReply {
|
|
||||||
msg.Reply(false, nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if wm.status == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if wm.status == -1 {
|
|
||||||
// exit-status was never sent from server
|
|
||||||
if wm.signal == "" {
|
|
||||||
// signal was not sent either. RFC 4254
|
|
||||||
// section 6.10 recommends against this
|
|
||||||
// behavior, but it is allowed, so we let
|
|
||||||
// clients handle it.
|
|
||||||
return &ExitMissingError{}
|
|
||||||
}
|
|
||||||
wm.status = 128
|
|
||||||
if _, ok := signals[Signal(wm.signal)]; ok {
|
|
||||||
wm.status += signals[Signal(wm.signal)]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &ExitError{wm}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExitMissingError is returned if a session is torn down cleanly, but
|
|
||||||
// the server sends no confirmation of the exit status.
|
|
||||||
type ExitMissingError struct{}
|
|
||||||
|
|
||||||
func (e *ExitMissingError) Error() string {
|
|
||||||
return "wait: remote command exited without exit status or exit signal"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Session) stdin() {
|
|
||||||
if s.stdinpipe {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var stdin io.Reader
|
|
||||||
if s.Stdin == nil {
|
|
||||||
stdin = new(bytes.Buffer)
|
|
||||||
} else {
|
|
||||||
r, w := io.Pipe()
|
|
||||||
go func() {
|
|
||||||
_, err := io.Copy(w, s.Stdin)
|
|
||||||
w.CloseWithError(err)
|
|
||||||
}()
|
|
||||||
stdin, s.stdinPipeWriter = r, w
|
|
||||||
}
|
|
||||||
s.copyFuncs = append(s.copyFuncs, func() error {
|
|
||||||
_, err := io.Copy(s.ch, stdin)
|
|
||||||
if err1 := s.ch.CloseWrite(); err == nil && err1 != io.EOF {
|
|
||||||
err = err1
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Session) stdout() {
|
|
||||||
if s.stdoutpipe {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if s.Stdout == nil {
|
|
||||||
s.Stdout = ioutil.Discard
|
|
||||||
}
|
|
||||||
s.copyFuncs = append(s.copyFuncs, func() error {
|
|
||||||
_, err := io.Copy(s.Stdout, s.ch)
|
|
||||||
return err
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Session) stderr() {
|
|
||||||
if s.stderrpipe {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if s.Stderr == nil {
|
|
||||||
s.Stderr = ioutil.Discard
|
|
||||||
}
|
|
||||||
s.copyFuncs = append(s.copyFuncs, func() error {
|
|
||||||
_, err := io.Copy(s.Stderr, s.ch.Stderr())
|
|
||||||
return err
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// sessionStdin reroutes Close to CloseWrite.
|
|
||||||
type sessionStdin struct {
|
|
||||||
io.Writer
|
|
||||||
ch Channel
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *sessionStdin) Close() error {
|
|
||||||
return s.ch.CloseWrite()
|
|
||||||
}
|
|
||||||
|
|
||||||
// StdinPipe returns a pipe that will be connected to the
|
|
||||||
// remote command's standard input when the command starts.
|
|
||||||
func (s *Session) StdinPipe() (io.WriteCloser, error) {
|
|
||||||
if s.Stdin != nil {
|
|
||||||
return nil, errors.New("ssh: Stdin already set")
|
|
||||||
}
|
|
||||||
if s.started {
|
|
||||||
return nil, errors.New("ssh: StdinPipe after process started")
|
|
||||||
}
|
|
||||||
s.stdinpipe = true
|
|
||||||
return &sessionStdin{s.ch, s.ch}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// StdoutPipe returns a pipe that will be connected to the
|
|
||||||
// remote command's standard output when the command starts.
|
|
||||||
// There is a fixed amount of buffering that is shared between
|
|
||||||
// stdout and stderr streams. If the StdoutPipe reader is
|
|
||||||
// not serviced fast enough it may eventually cause the
|
|
||||||
// remote command to block.
|
|
||||||
func (s *Session) StdoutPipe() (io.Reader, error) {
|
|
||||||
if s.Stdout != nil {
|
|
||||||
return nil, errors.New("ssh: Stdout already set")
|
|
||||||
}
|
|
||||||
if s.started {
|
|
||||||
return nil, errors.New("ssh: StdoutPipe after process started")
|
|
||||||
}
|
|
||||||
s.stdoutpipe = true
|
|
||||||
return s.ch, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// StderrPipe returns a pipe that will be connected to the
|
|
||||||
// remote command's standard error when the command starts.
|
|
||||||
// There is a fixed amount of buffering that is shared between
|
|
||||||
// stdout and stderr streams. If the StderrPipe reader is
|
|
||||||
// not serviced fast enough it may eventually cause the
|
|
||||||
// remote command to block.
|
|
||||||
func (s *Session) StderrPipe() (io.Reader, error) {
|
|
||||||
if s.Stderr != nil {
|
|
||||||
return nil, errors.New("ssh: Stderr already set")
|
|
||||||
}
|
|
||||||
if s.started {
|
|
||||||
return nil, errors.New("ssh: StderrPipe after process started")
|
|
||||||
}
|
|
||||||
s.stderrpipe = true
|
|
||||||
return s.ch.Stderr(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// newSession returns a new interactive session on the remote host.
|
|
||||||
func newSession(ch Channel, reqs <-chan *Request) (*Session, error) {
|
|
||||||
s := &Session{
|
|
||||||
ch: ch,
|
|
||||||
}
|
|
||||||
s.exitStatus = make(chan error, 1)
|
|
||||||
go func() {
|
|
||||||
s.exitStatus <- s.wait(reqs)
|
|
||||||
}()
|
|
||||||
|
|
||||||
return s, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// An ExitError reports unsuccessful completion of a remote command.
|
|
||||||
type ExitError struct {
|
|
||||||
Waitmsg
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ExitError) Error() string {
|
|
||||||
return e.Waitmsg.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Waitmsg stores the information about an exited remote command
|
|
||||||
// as reported by Wait.
|
|
||||||
type Waitmsg struct {
|
|
||||||
status int
|
|
||||||
signal string
|
|
||||||
msg string
|
|
||||||
lang string
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExitStatus returns the exit status of the remote command.
|
|
||||||
func (w Waitmsg) ExitStatus() int {
|
|
||||||
return w.status
|
|
||||||
}
|
|
||||||
|
|
||||||
// Signal returns the exit signal of the remote command if
|
|
||||||
// it was terminated violently.
|
|
||||||
func (w Waitmsg) Signal() string {
|
|
||||||
return w.signal
|
|
||||||
}
|
|
||||||
|
|
||||||
// Msg returns the exit message given by the remote command
|
|
||||||
func (w Waitmsg) Msg() string {
|
|
||||||
return w.msg
|
|
||||||
}
|
|
||||||
|
|
||||||
// Lang returns the language tag. See RFC 3066
|
|
||||||
func (w Waitmsg) Lang() string {
|
|
||||||
return w.lang
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w Waitmsg) String() string {
|
|
||||||
str := fmt.Sprintf("Process exited with status %v", w.status)
|
|
||||||
if w.signal != "" {
|
|
||||||
str += fmt.Sprintf(" from signal %v", w.signal)
|
|
||||||
}
|
|
||||||
if w.msg != "" {
|
|
||||||
str += fmt.Sprintf(". Reason was: %v", w.msg)
|
|
||||||
}
|
|
||||||
return str
|
|
||||||
}
|
|
139
vendor/golang.org/x/crypto/ssh/ssh_gss.go
generated
vendored
139
vendor/golang.org/x/crypto/ssh/ssh_gss.go
generated
vendored
@ -1,139 +0,0 @@
|
|||||||
// 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 ssh
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/asn1"
|
|
||||||
"errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
var krb5OID []byte
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
krb5OID, _ = asn1.Marshal(krb5Mesh)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GSSAPIClient provides the API to plug-in GSSAPI authentication for client logins.
|
|
||||||
type GSSAPIClient interface {
|
|
||||||
// InitSecContext initiates the establishment of a security context for GSS-API between the
|
|
||||||
// ssh client and ssh server. Initially the token parameter should be specified as nil.
|
|
||||||
// The routine may return a outputToken which should be transferred to
|
|
||||||
// the ssh server, where the ssh server will present it to
|
|
||||||
// AcceptSecContext. If no token need be sent, InitSecContext will indicate this by setting
|
|
||||||
// needContinue to false. To complete the context
|
|
||||||
// establishment, one or more reply tokens may be required from the ssh
|
|
||||||
// server;if so, InitSecContext will return a needContinue which is true.
|
|
||||||
// In this case, InitSecContext should be called again when the
|
|
||||||
// reply token is received from the ssh server, passing the reply
|
|
||||||
// token to InitSecContext via the token parameters.
|
|
||||||
// See RFC 2743 section 2.2.1 and RFC 4462 section 3.4.
|
|
||||||
InitSecContext(target string, token []byte, isGSSDelegCreds bool) (outputToken []byte, needContinue bool, err error)
|
|
||||||
// GetMIC generates a cryptographic MIC for the SSH2 message, and places
|
|
||||||
// the MIC in a token for transfer to the ssh server.
|
|
||||||
// The contents of the MIC field are obtained by calling GSS_GetMIC()
|
|
||||||
// over the following, using the GSS-API context that was just
|
|
||||||
// established:
|
|
||||||
// string session identifier
|
|
||||||
// byte SSH_MSG_USERAUTH_REQUEST
|
|
||||||
// string user name
|
|
||||||
// string service
|
|
||||||
// string "gssapi-with-mic"
|
|
||||||
// See RFC 2743 section 2.3.1 and RFC 4462 3.5.
|
|
||||||
GetMIC(micFiled []byte) ([]byte, error)
|
|
||||||
// Whenever possible, it should be possible for
|
|
||||||
// DeleteSecContext() calls to be successfully processed even
|
|
||||||
// if other calls cannot succeed, thereby enabling context-related
|
|
||||||
// resources to be released.
|
|
||||||
// In addition to deleting established security contexts,
|
|
||||||
// gss_delete_sec_context must also be able to delete "half-built"
|
|
||||||
// security contexts resulting from an incomplete sequence of
|
|
||||||
// InitSecContext()/AcceptSecContext() calls.
|
|
||||||
// See RFC 2743 section 2.2.3.
|
|
||||||
DeleteSecContext() error
|
|
||||||
}
|
|
||||||
|
|
||||||
// GSSAPIServer provides the API to plug in GSSAPI authentication for server logins.
|
|
||||||
type GSSAPIServer interface {
|
|
||||||
// AcceptSecContext allows a remotely initiated security context between the application
|
|
||||||
// and a remote peer to be established by the ssh client. The routine may return a
|
|
||||||
// outputToken which should be transferred to the ssh client,
|
|
||||||
// where the ssh client will present it to InitSecContext.
|
|
||||||
// If no token need be sent, AcceptSecContext will indicate this
|
|
||||||
// by setting the needContinue to false. To
|
|
||||||
// complete the context establishment, one or more reply tokens may be
|
|
||||||
// required from the ssh client. if so, AcceptSecContext
|
|
||||||
// will return a needContinue which is true, in which case it
|
|
||||||
// should be called again when the reply token is received from the ssh
|
|
||||||
// client, passing the token to AcceptSecContext via the
|
|
||||||
// token parameters.
|
|
||||||
// The srcName return value is the authenticated username.
|
|
||||||
// See RFC 2743 section 2.2.2 and RFC 4462 section 3.4.
|
|
||||||
AcceptSecContext(token []byte) (outputToken []byte, srcName string, needContinue bool, err error)
|
|
||||||
// VerifyMIC verifies that a cryptographic MIC, contained in the token parameter,
|
|
||||||
// fits the supplied message is received from the ssh client.
|
|
||||||
// See RFC 2743 section 2.3.2.
|
|
||||||
VerifyMIC(micField []byte, micToken []byte) error
|
|
||||||
// Whenever possible, it should be possible for
|
|
||||||
// DeleteSecContext() calls to be successfully processed even
|
|
||||||
// if other calls cannot succeed, thereby enabling context-related
|
|
||||||
// resources to be released.
|
|
||||||
// In addition to deleting established security contexts,
|
|
||||||
// gss_delete_sec_context must also be able to delete "half-built"
|
|
||||||
// security contexts resulting from an incomplete sequence of
|
|
||||||
// InitSecContext()/AcceptSecContext() calls.
|
|
||||||
// See RFC 2743 section 2.2.3.
|
|
||||||
DeleteSecContext() error
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
// OpenSSH supports Kerberos V5 mechanism only for GSS-API authentication,
|
|
||||||
// so we also support the krb5 mechanism only.
|
|
||||||
// See RFC 1964 section 1.
|
|
||||||
krb5Mesh = asn1.ObjectIdentifier{1, 2, 840, 113554, 1, 2, 2}
|
|
||||||
)
|
|
||||||
|
|
||||||
// The GSS-API authentication method is initiated when the client sends an SSH_MSG_USERAUTH_REQUEST
|
|
||||||
// See RFC 4462 section 3.2.
|
|
||||||
type userAuthRequestGSSAPI struct {
|
|
||||||
N uint32
|
|
||||||
OIDS []asn1.ObjectIdentifier
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseGSSAPIPayload(payload []byte) (*userAuthRequestGSSAPI, error) {
|
|
||||||
n, rest, ok := parseUint32(payload)
|
|
||||||
if !ok {
|
|
||||||
return nil, errors.New("parse uint32 failed")
|
|
||||||
}
|
|
||||||
s := &userAuthRequestGSSAPI{
|
|
||||||
N: n,
|
|
||||||
OIDS: make([]asn1.ObjectIdentifier, n),
|
|
||||||
}
|
|
||||||
for i := 0; i < int(n); i++ {
|
|
||||||
var (
|
|
||||||
desiredMech []byte
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
desiredMech, rest, ok = parseString(rest)
|
|
||||||
if !ok {
|
|
||||||
return nil, errors.New("parse string failed")
|
|
||||||
}
|
|
||||||
if rest, err = asn1.Unmarshal(desiredMech, &s.OIDS[i]); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return s, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// See RFC 4462 section 3.6.
|
|
||||||
func buildMIC(sessionID string, username string, service string, authMethod string) []byte {
|
|
||||||
out := make([]byte, 0, 0)
|
|
||||||
out = appendString(out, sessionID)
|
|
||||||
out = append(out, msgUserAuthRequest)
|
|
||||||
out = appendString(out, username)
|
|
||||||
out = appendString(out, service)
|
|
||||||
out = appendString(out, authMethod)
|
|
||||||
return out
|
|
||||||
}
|
|
116
vendor/golang.org/x/crypto/ssh/streamlocal.go
generated
vendored
116
vendor/golang.org/x/crypto/ssh/streamlocal.go
generated
vendored
@ -1,116 +0,0 @@
|
|||||||
package ssh
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"io"
|
|
||||||
"net"
|
|
||||||
)
|
|
||||||
|
|
||||||
// streamLocalChannelOpenDirectMsg is a struct used for SSH_MSG_CHANNEL_OPEN message
|
|
||||||
// with "direct-streamlocal@openssh.com" string.
|
|
||||||
//
|
|
||||||
// See openssh-portable/PROTOCOL, section 2.4. connection: Unix domain socket forwarding
|
|
||||||
// https://github.com/openssh/openssh-portable/blob/master/PROTOCOL#L235
|
|
||||||
type streamLocalChannelOpenDirectMsg struct {
|
|
||||||
socketPath string
|
|
||||||
reserved0 string
|
|
||||||
reserved1 uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
// forwardedStreamLocalPayload is a struct used for SSH_MSG_CHANNEL_OPEN message
|
|
||||||
// with "forwarded-streamlocal@openssh.com" string.
|
|
||||||
type forwardedStreamLocalPayload struct {
|
|
||||||
SocketPath string
|
|
||||||
Reserved0 string
|
|
||||||
}
|
|
||||||
|
|
||||||
// streamLocalChannelForwardMsg is a struct used for SSH2_MSG_GLOBAL_REQUEST message
|
|
||||||
// with "streamlocal-forward@openssh.com"/"cancel-streamlocal-forward@openssh.com" string.
|
|
||||||
type streamLocalChannelForwardMsg struct {
|
|
||||||
socketPath string
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListenUnix is similar to ListenTCP but uses a Unix domain socket.
|
|
||||||
func (c *Client) ListenUnix(socketPath string) (net.Listener, error) {
|
|
||||||
c.handleForwardsOnce.Do(c.handleForwards)
|
|
||||||
m := streamLocalChannelForwardMsg{
|
|
||||||
socketPath,
|
|
||||||
}
|
|
||||||
// send message
|
|
||||||
ok, _, err := c.SendRequest("streamlocal-forward@openssh.com", true, Marshal(&m))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if !ok {
|
|
||||||
return nil, errors.New("ssh: streamlocal-forward@openssh.com request denied by peer")
|
|
||||||
}
|
|
||||||
ch := c.forwards.add(&net.UnixAddr{Name: socketPath, Net: "unix"})
|
|
||||||
|
|
||||||
return &unixListener{socketPath, c, ch}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) dialStreamLocal(socketPath string) (Channel, error) {
|
|
||||||
msg := streamLocalChannelOpenDirectMsg{
|
|
||||||
socketPath: socketPath,
|
|
||||||
}
|
|
||||||
ch, in, err := c.OpenChannel("direct-streamlocal@openssh.com", Marshal(&msg))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
go DiscardRequests(in)
|
|
||||||
return ch, err
|
|
||||||
}
|
|
||||||
|
|
||||||
type unixListener struct {
|
|
||||||
socketPath string
|
|
||||||
|
|
||||||
conn *Client
|
|
||||||
in <-chan forward
|
|
||||||
}
|
|
||||||
|
|
||||||
// Accept waits for and returns the next connection to the listener.
|
|
||||||
func (l *unixListener) Accept() (net.Conn, error) {
|
|
||||||
s, ok := <-l.in
|
|
||||||
if !ok {
|
|
||||||
return nil, io.EOF
|
|
||||||
}
|
|
||||||
ch, incoming, err := s.newCh.Accept()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
go DiscardRequests(incoming)
|
|
||||||
|
|
||||||
return &chanConn{
|
|
||||||
Channel: ch,
|
|
||||||
laddr: &net.UnixAddr{
|
|
||||||
Name: l.socketPath,
|
|
||||||
Net: "unix",
|
|
||||||
},
|
|
||||||
raddr: &net.UnixAddr{
|
|
||||||
Name: "@",
|
|
||||||
Net: "unix",
|
|
||||||
},
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close closes the listener.
|
|
||||||
func (l *unixListener) Close() error {
|
|
||||||
// this also closes the listener.
|
|
||||||
l.conn.forwards.remove(&net.UnixAddr{Name: l.socketPath, Net: "unix"})
|
|
||||||
m := streamLocalChannelForwardMsg{
|
|
||||||
l.socketPath,
|
|
||||||
}
|
|
||||||
ok, _, err := l.conn.SendRequest("cancel-streamlocal-forward@openssh.com", true, Marshal(&m))
|
|
||||||
if err == nil && !ok {
|
|
||||||
err = errors.New("ssh: cancel-streamlocal-forward@openssh.com failed")
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Addr returns the listener's network address.
|
|
||||||
func (l *unixListener) Addr() net.Addr {
|
|
||||||
return &net.UnixAddr{
|
|
||||||
Name: l.socketPath,
|
|
||||||
Net: "unix",
|
|
||||||
}
|
|
||||||
}
|
|
474
vendor/golang.org/x/crypto/ssh/tcpip.go
generated
vendored
474
vendor/golang.org/x/crypto/ssh/tcpip.go
generated
vendored
@ -1,474 +0,0 @@
|
|||||||
// 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 ssh
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"math/rand"
|
|
||||||
"net"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Listen requests the remote peer open a listening socket on
|
|
||||||
// addr. Incoming connections will be available by calling Accept on
|
|
||||||
// the returned net.Listener. The listener must be serviced, or the
|
|
||||||
// SSH connection may hang.
|
|
||||||
// N must be "tcp", "tcp4", "tcp6", or "unix".
|
|
||||||
func (c *Client) Listen(n, addr string) (net.Listener, error) {
|
|
||||||
switch n {
|
|
||||||
case "tcp", "tcp4", "tcp6":
|
|
||||||
laddr, err := net.ResolveTCPAddr(n, addr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return c.ListenTCP(laddr)
|
|
||||||
case "unix":
|
|
||||||
return c.ListenUnix(addr)
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("ssh: unsupported protocol: %s", n)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Automatic port allocation is broken with OpenSSH before 6.0. See
|
|
||||||
// also https://bugzilla.mindrot.org/show_bug.cgi?id=2017. In
|
|
||||||
// particular, OpenSSH 5.9 sends a channelOpenMsg with port number 0,
|
|
||||||
// rather than the actual port number. This means you can never open
|
|
||||||
// two different listeners with auto allocated ports. We work around
|
|
||||||
// this by trying explicit ports until we succeed.
|
|
||||||
|
|
||||||
const openSSHPrefix = "OpenSSH_"
|
|
||||||
|
|
||||||
var portRandomizer = rand.New(rand.NewSource(time.Now().UnixNano()))
|
|
||||||
|
|
||||||
// isBrokenOpenSSHVersion returns true if the given version string
|
|
||||||
// specifies a version of OpenSSH that is known to have a bug in port
|
|
||||||
// forwarding.
|
|
||||||
func isBrokenOpenSSHVersion(versionStr string) bool {
|
|
||||||
i := strings.Index(versionStr, openSSHPrefix)
|
|
||||||
if i < 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
i += len(openSSHPrefix)
|
|
||||||
j := i
|
|
||||||
for ; j < len(versionStr); j++ {
|
|
||||||
if versionStr[j] < '0' || versionStr[j] > '9' {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
version, _ := strconv.Atoi(versionStr[i:j])
|
|
||||||
return version < 6
|
|
||||||
}
|
|
||||||
|
|
||||||
// autoPortListenWorkaround simulates automatic port allocation by
|
|
||||||
// trying random ports repeatedly.
|
|
||||||
func (c *Client) autoPortListenWorkaround(laddr *net.TCPAddr) (net.Listener, error) {
|
|
||||||
var sshListener net.Listener
|
|
||||||
var err error
|
|
||||||
const tries = 10
|
|
||||||
for i := 0; i < tries; i++ {
|
|
||||||
addr := *laddr
|
|
||||||
addr.Port = 1024 + portRandomizer.Intn(60000)
|
|
||||||
sshListener, err = c.ListenTCP(&addr)
|
|
||||||
if err == nil {
|
|
||||||
laddr.Port = addr.Port
|
|
||||||
return sshListener, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil, fmt.Errorf("ssh: listen on random port failed after %d tries: %v", tries, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RFC 4254 7.1
|
|
||||||
type channelForwardMsg struct {
|
|
||||||
addr string
|
|
||||||
rport uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
// handleForwards starts goroutines handling forwarded connections.
|
|
||||||
// It's called on first use by (*Client).ListenTCP to not launch
|
|
||||||
// goroutines until needed.
|
|
||||||
func (c *Client) handleForwards() {
|
|
||||||
go c.forwards.handleChannels(c.HandleChannelOpen("forwarded-tcpip"))
|
|
||||||
go c.forwards.handleChannels(c.HandleChannelOpen("forwarded-streamlocal@openssh.com"))
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListenTCP requests the remote peer open a listening socket
|
|
||||||
// on laddr. Incoming connections will be available by calling
|
|
||||||
// Accept on the returned net.Listener.
|
|
||||||
func (c *Client) ListenTCP(laddr *net.TCPAddr) (net.Listener, error) {
|
|
||||||
c.handleForwardsOnce.Do(c.handleForwards)
|
|
||||||
if laddr.Port == 0 && isBrokenOpenSSHVersion(string(c.ServerVersion())) {
|
|
||||||
return c.autoPortListenWorkaround(laddr)
|
|
||||||
}
|
|
||||||
|
|
||||||
m := channelForwardMsg{
|
|
||||||
laddr.IP.String(),
|
|
||||||
uint32(laddr.Port),
|
|
||||||
}
|
|
||||||
// send message
|
|
||||||
ok, resp, err := c.SendRequest("tcpip-forward", true, Marshal(&m))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if !ok {
|
|
||||||
return nil, errors.New("ssh: tcpip-forward request denied by peer")
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the original port was 0, then the remote side will
|
|
||||||
// supply a real port number in the response.
|
|
||||||
if laddr.Port == 0 {
|
|
||||||
var p struct {
|
|
||||||
Port uint32
|
|
||||||
}
|
|
||||||
if err := Unmarshal(resp, &p); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
laddr.Port = int(p.Port)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register this forward, using the port number we obtained.
|
|
||||||
ch := c.forwards.add(laddr)
|
|
||||||
|
|
||||||
return &tcpListener{laddr, c, ch}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// forwardList stores a mapping between remote
|
|
||||||
// forward requests and the tcpListeners.
|
|
||||||
type forwardList struct {
|
|
||||||
sync.Mutex
|
|
||||||
entries []forwardEntry
|
|
||||||
}
|
|
||||||
|
|
||||||
// forwardEntry represents an established mapping of a laddr on a
|
|
||||||
// remote ssh server to a channel connected to a tcpListener.
|
|
||||||
type forwardEntry struct {
|
|
||||||
laddr net.Addr
|
|
||||||
c chan forward
|
|
||||||
}
|
|
||||||
|
|
||||||
// forward represents an incoming forwarded tcpip connection. The
|
|
||||||
// arguments to add/remove/lookup should be address as specified in
|
|
||||||
// the original forward-request.
|
|
||||||
type forward struct {
|
|
||||||
newCh NewChannel // the ssh client channel underlying this forward
|
|
||||||
raddr net.Addr // the raddr of the incoming connection
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *forwardList) add(addr net.Addr) chan forward {
|
|
||||||
l.Lock()
|
|
||||||
defer l.Unlock()
|
|
||||||
f := forwardEntry{
|
|
||||||
laddr: addr,
|
|
||||||
c: make(chan forward, 1),
|
|
||||||
}
|
|
||||||
l.entries = append(l.entries, f)
|
|
||||||
return f.c
|
|
||||||
}
|
|
||||||
|
|
||||||
// See RFC 4254, section 7.2
|
|
||||||
type forwardedTCPPayload struct {
|
|
||||||
Addr string
|
|
||||||
Port uint32
|
|
||||||
OriginAddr string
|
|
||||||
OriginPort uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
// parseTCPAddr parses the originating address from the remote into a *net.TCPAddr.
|
|
||||||
func parseTCPAddr(addr string, port uint32) (*net.TCPAddr, error) {
|
|
||||||
if port == 0 || port > 65535 {
|
|
||||||
return nil, fmt.Errorf("ssh: port number out of range: %d", port)
|
|
||||||
}
|
|
||||||
ip := net.ParseIP(string(addr))
|
|
||||||
if ip == nil {
|
|
||||||
return nil, fmt.Errorf("ssh: cannot parse IP address %q", addr)
|
|
||||||
}
|
|
||||||
return &net.TCPAddr{IP: ip, Port: int(port)}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *forwardList) handleChannels(in <-chan NewChannel) {
|
|
||||||
for ch := range in {
|
|
||||||
var (
|
|
||||||
laddr net.Addr
|
|
||||||
raddr net.Addr
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
switch channelType := ch.ChannelType(); channelType {
|
|
||||||
case "forwarded-tcpip":
|
|
||||||
var payload forwardedTCPPayload
|
|
||||||
if err = Unmarshal(ch.ExtraData(), &payload); err != nil {
|
|
||||||
ch.Reject(ConnectionFailed, "could not parse forwarded-tcpip payload: "+err.Error())
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// RFC 4254 section 7.2 specifies that incoming
|
|
||||||
// addresses should list the address, in string
|
|
||||||
// format. It is implied that this should be an IP
|
|
||||||
// address, as it would be impossible to connect to it
|
|
||||||
// otherwise.
|
|
||||||
laddr, err = parseTCPAddr(payload.Addr, payload.Port)
|
|
||||||
if err != nil {
|
|
||||||
ch.Reject(ConnectionFailed, err.Error())
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
raddr, err = parseTCPAddr(payload.OriginAddr, payload.OriginPort)
|
|
||||||
if err != nil {
|
|
||||||
ch.Reject(ConnectionFailed, err.Error())
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
case "forwarded-streamlocal@openssh.com":
|
|
||||||
var payload forwardedStreamLocalPayload
|
|
||||||
if err = Unmarshal(ch.ExtraData(), &payload); err != nil {
|
|
||||||
ch.Reject(ConnectionFailed, "could not parse forwarded-streamlocal@openssh.com payload: "+err.Error())
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
laddr = &net.UnixAddr{
|
|
||||||
Name: payload.SocketPath,
|
|
||||||
Net: "unix",
|
|
||||||
}
|
|
||||||
raddr = &net.UnixAddr{
|
|
||||||
Name: "@",
|
|
||||||
Net: "unix",
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
panic(fmt.Errorf("ssh: unknown channel type %s", channelType))
|
|
||||||
}
|
|
||||||
if ok := l.forward(laddr, raddr, ch); !ok {
|
|
||||||
// Section 7.2, implementations MUST reject spurious incoming
|
|
||||||
// connections.
|
|
||||||
ch.Reject(Prohibited, "no forward for address")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove removes the forward entry, and the channel feeding its
|
|
||||||
// listener.
|
|
||||||
func (l *forwardList) remove(addr net.Addr) {
|
|
||||||
l.Lock()
|
|
||||||
defer l.Unlock()
|
|
||||||
for i, f := range l.entries {
|
|
||||||
if addr.Network() == f.laddr.Network() && addr.String() == f.laddr.String() {
|
|
||||||
l.entries = append(l.entries[:i], l.entries[i+1:]...)
|
|
||||||
close(f.c)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// closeAll closes and clears all forwards.
|
|
||||||
func (l *forwardList) closeAll() {
|
|
||||||
l.Lock()
|
|
||||||
defer l.Unlock()
|
|
||||||
for _, f := range l.entries {
|
|
||||||
close(f.c)
|
|
||||||
}
|
|
||||||
l.entries = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *forwardList) forward(laddr, raddr net.Addr, ch NewChannel) bool {
|
|
||||||
l.Lock()
|
|
||||||
defer l.Unlock()
|
|
||||||
for _, f := range l.entries {
|
|
||||||
if laddr.Network() == f.laddr.Network() && laddr.String() == f.laddr.String() {
|
|
||||||
f.c <- forward{newCh: ch, raddr: raddr}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
type tcpListener struct {
|
|
||||||
laddr *net.TCPAddr
|
|
||||||
|
|
||||||
conn *Client
|
|
||||||
in <-chan forward
|
|
||||||
}
|
|
||||||
|
|
||||||
// Accept waits for and returns the next connection to the listener.
|
|
||||||
func (l *tcpListener) Accept() (net.Conn, error) {
|
|
||||||
s, ok := <-l.in
|
|
||||||
if !ok {
|
|
||||||
return nil, io.EOF
|
|
||||||
}
|
|
||||||
ch, incoming, err := s.newCh.Accept()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
go DiscardRequests(incoming)
|
|
||||||
|
|
||||||
return &chanConn{
|
|
||||||
Channel: ch,
|
|
||||||
laddr: l.laddr,
|
|
||||||
raddr: s.raddr,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close closes the listener.
|
|
||||||
func (l *tcpListener) Close() error {
|
|
||||||
m := channelForwardMsg{
|
|
||||||
l.laddr.IP.String(),
|
|
||||||
uint32(l.laddr.Port),
|
|
||||||
}
|
|
||||||
|
|
||||||
// this also closes the listener.
|
|
||||||
l.conn.forwards.remove(l.laddr)
|
|
||||||
ok, _, err := l.conn.SendRequest("cancel-tcpip-forward", true, Marshal(&m))
|
|
||||||
if err == nil && !ok {
|
|
||||||
err = errors.New("ssh: cancel-tcpip-forward failed")
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Addr returns the listener's network address.
|
|
||||||
func (l *tcpListener) Addr() net.Addr {
|
|
||||||
return l.laddr
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dial initiates a connection to the addr from the remote host.
|
|
||||||
// The resulting connection has a zero LocalAddr() and RemoteAddr().
|
|
||||||
func (c *Client) Dial(n, addr string) (net.Conn, error) {
|
|
||||||
var ch Channel
|
|
||||||
switch n {
|
|
||||||
case "tcp", "tcp4", "tcp6":
|
|
||||||
// Parse the address into host and numeric port.
|
|
||||||
host, portString, err := net.SplitHostPort(addr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
port, err := strconv.ParseUint(portString, 10, 16)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
ch, err = c.dial(net.IPv4zero.String(), 0, host, int(port))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// Use a zero address for local and remote address.
|
|
||||||
zeroAddr := &net.TCPAddr{
|
|
||||||
IP: net.IPv4zero,
|
|
||||||
Port: 0,
|
|
||||||
}
|
|
||||||
return &chanConn{
|
|
||||||
Channel: ch,
|
|
||||||
laddr: zeroAddr,
|
|
||||||
raddr: zeroAddr,
|
|
||||||
}, nil
|
|
||||||
case "unix":
|
|
||||||
var err error
|
|
||||||
ch, err = c.dialStreamLocal(addr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &chanConn{
|
|
||||||
Channel: ch,
|
|
||||||
laddr: &net.UnixAddr{
|
|
||||||
Name: "@",
|
|
||||||
Net: "unix",
|
|
||||||
},
|
|
||||||
raddr: &net.UnixAddr{
|
|
||||||
Name: addr,
|
|
||||||
Net: "unix",
|
|
||||||
},
|
|
||||||
}, nil
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("ssh: unsupported protocol: %s", n)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// DialTCP connects to the remote address raddr on the network net,
|
|
||||||
// which must be "tcp", "tcp4", or "tcp6". If laddr is not nil, it is used
|
|
||||||
// as the local address for the connection.
|
|
||||||
func (c *Client) DialTCP(n string, laddr, raddr *net.TCPAddr) (net.Conn, error) {
|
|
||||||
if laddr == nil {
|
|
||||||
laddr = &net.TCPAddr{
|
|
||||||
IP: net.IPv4zero,
|
|
||||||
Port: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ch, err := c.dial(laddr.IP.String(), laddr.Port, raddr.IP.String(), raddr.Port)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &chanConn{
|
|
||||||
Channel: ch,
|
|
||||||
laddr: laddr,
|
|
||||||
raddr: raddr,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// RFC 4254 7.2
|
|
||||||
type channelOpenDirectMsg struct {
|
|
||||||
raddr string
|
|
||||||
rport uint32
|
|
||||||
laddr string
|
|
||||||
lport uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) dial(laddr string, lport int, raddr string, rport int) (Channel, error) {
|
|
||||||
msg := channelOpenDirectMsg{
|
|
||||||
raddr: raddr,
|
|
||||||
rport: uint32(rport),
|
|
||||||
laddr: laddr,
|
|
||||||
lport: uint32(lport),
|
|
||||||
}
|
|
||||||
ch, in, err := c.OpenChannel("direct-tcpip", Marshal(&msg))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
go DiscardRequests(in)
|
|
||||||
return ch, err
|
|
||||||
}
|
|
||||||
|
|
||||||
type tcpChan struct {
|
|
||||||
Channel // the backing channel
|
|
||||||
}
|
|
||||||
|
|
||||||
// chanConn fulfills the net.Conn interface without
|
|
||||||
// the tcpChan having to hold laddr or raddr directly.
|
|
||||||
type chanConn struct {
|
|
||||||
Channel
|
|
||||||
laddr, raddr net.Addr
|
|
||||||
}
|
|
||||||
|
|
||||||
// LocalAddr returns the local network address.
|
|
||||||
func (t *chanConn) LocalAddr() net.Addr {
|
|
||||||
return t.laddr
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoteAddr returns the remote network address.
|
|
||||||
func (t *chanConn) RemoteAddr() net.Addr {
|
|
||||||
return t.raddr
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetDeadline sets the read and write deadlines associated
|
|
||||||
// with the connection.
|
|
||||||
func (t *chanConn) SetDeadline(deadline time.Time) error {
|
|
||||||
if err := t.SetReadDeadline(deadline); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return t.SetWriteDeadline(deadline)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetReadDeadline sets the read deadline.
|
|
||||||
// A zero value for t means Read will not time out.
|
|
||||||
// After the deadline, the error from Read will implement net.Error
|
|
||||||
// with Timeout() == true.
|
|
||||||
func (t *chanConn) SetReadDeadline(deadline time.Time) error {
|
|
||||||
// for compatibility with previous version,
|
|
||||||
// the error message contains "tcpChan"
|
|
||||||
return errors.New("ssh: tcpChan: deadline not supported")
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetWriteDeadline exists to satisfy the net.Conn interface
|
|
||||||
// but is not implemented by this type. It always returns an error.
|
|
||||||
func (t *chanConn) SetWriteDeadline(deadline time.Time) error {
|
|
||||||
return errors.New("ssh: tcpChan: deadline not supported")
|
|
||||||
}
|
|
353
vendor/golang.org/x/crypto/ssh/transport.go
generated
vendored
353
vendor/golang.org/x/crypto/ssh/transport.go
generated
vendored
@ -1,353 +0,0 @@
|
|||||||
// 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 ssh
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"bytes"
|
|
||||||
"errors"
|
|
||||||
"io"
|
|
||||||
"log"
|
|
||||||
)
|
|
||||||
|
|
||||||
// debugTransport if set, will print packet types as they go over the
|
|
||||||
// wire. No message decoding is done, to minimize the impact on timing.
|
|
||||||
const debugTransport = false
|
|
||||||
|
|
||||||
const (
|
|
||||||
gcmCipherID = "aes128-gcm@openssh.com"
|
|
||||||
aes128cbcID = "aes128-cbc"
|
|
||||||
tripledescbcID = "3des-cbc"
|
|
||||||
)
|
|
||||||
|
|
||||||
// packetConn represents a transport that implements packet based
|
|
||||||
// operations.
|
|
||||||
type packetConn interface {
|
|
||||||
// Encrypt and send a packet of data to the remote peer.
|
|
||||||
writePacket(packet []byte) error
|
|
||||||
|
|
||||||
// Read a packet from the connection. The read is blocking,
|
|
||||||
// i.e. if error is nil, then the returned byte slice is
|
|
||||||
// always non-empty.
|
|
||||||
readPacket() ([]byte, error)
|
|
||||||
|
|
||||||
// Close closes the write-side of the connection.
|
|
||||||
Close() error
|
|
||||||
}
|
|
||||||
|
|
||||||
// transport is the keyingTransport that implements the SSH packet
|
|
||||||
// protocol.
|
|
||||||
type transport struct {
|
|
||||||
reader connectionState
|
|
||||||
writer connectionState
|
|
||||||
|
|
||||||
bufReader *bufio.Reader
|
|
||||||
bufWriter *bufio.Writer
|
|
||||||
rand io.Reader
|
|
||||||
isClient bool
|
|
||||||
io.Closer
|
|
||||||
}
|
|
||||||
|
|
||||||
// packetCipher represents a combination of SSH encryption/MAC
|
|
||||||
// protocol. A single instance should be used for one direction only.
|
|
||||||
type packetCipher interface {
|
|
||||||
// writeCipherPacket encrypts the packet and writes it to w. The
|
|
||||||
// contents of the packet are generally scrambled.
|
|
||||||
writeCipherPacket(seqnum uint32, w io.Writer, rand io.Reader, packet []byte) error
|
|
||||||
|
|
||||||
// readCipherPacket reads and decrypts a packet of data. The
|
|
||||||
// returned packet may be overwritten by future calls of
|
|
||||||
// readPacket.
|
|
||||||
readCipherPacket(seqnum uint32, r io.Reader) ([]byte, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// connectionState represents one side (read or write) of the
|
|
||||||
// connection. This is necessary because each direction has its own
|
|
||||||
// keys, and can even have its own algorithms
|
|
||||||
type connectionState struct {
|
|
||||||
packetCipher
|
|
||||||
seqNum uint32
|
|
||||||
dir direction
|
|
||||||
pendingKeyChange chan packetCipher
|
|
||||||
}
|
|
||||||
|
|
||||||
// prepareKeyChange sets up key material for a keychange. The key changes in
|
|
||||||
// both directions are triggered by reading and writing a msgNewKey packet
|
|
||||||
// respectively.
|
|
||||||
func (t *transport) prepareKeyChange(algs *algorithms, kexResult *kexResult) error {
|
|
||||||
ciph, err := newPacketCipher(t.reader.dir, algs.r, kexResult)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
t.reader.pendingKeyChange <- ciph
|
|
||||||
|
|
||||||
ciph, err = newPacketCipher(t.writer.dir, algs.w, kexResult)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
t.writer.pendingKeyChange <- ciph
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *transport) printPacket(p []byte, write bool) {
|
|
||||||
if len(p) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
who := "server"
|
|
||||||
if t.isClient {
|
|
||||||
who = "client"
|
|
||||||
}
|
|
||||||
what := "read"
|
|
||||||
if write {
|
|
||||||
what = "write"
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Println(what, who, p[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read and decrypt next packet.
|
|
||||||
func (t *transport) readPacket() (p []byte, err error) {
|
|
||||||
for {
|
|
||||||
p, err = t.reader.readPacket(t.bufReader)
|
|
||||||
if err != nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if len(p) == 0 || (p[0] != msgIgnore && p[0] != msgDebug) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if debugTransport {
|
|
||||||
t.printPacket(p, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
return p, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *connectionState) readPacket(r *bufio.Reader) ([]byte, error) {
|
|
||||||
packet, err := s.packetCipher.readCipherPacket(s.seqNum, r)
|
|
||||||
s.seqNum++
|
|
||||||
if err == nil && len(packet) == 0 {
|
|
||||||
err = errors.New("ssh: zero length packet")
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(packet) > 0 {
|
|
||||||
switch packet[0] {
|
|
||||||
case msgNewKeys:
|
|
||||||
select {
|
|
||||||
case cipher := <-s.pendingKeyChange:
|
|
||||||
s.packetCipher = cipher
|
|
||||||
default:
|
|
||||||
return nil, errors.New("ssh: got bogus newkeys message")
|
|
||||||
}
|
|
||||||
|
|
||||||
case msgDisconnect:
|
|
||||||
// Transform a disconnect message into an
|
|
||||||
// error. Since this is lowest level at which
|
|
||||||
// we interpret message types, doing it here
|
|
||||||
// ensures that we don't have to handle it
|
|
||||||
// elsewhere.
|
|
||||||
var msg disconnectMsg
|
|
||||||
if err := Unmarshal(packet, &msg); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return nil, &msg
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The packet may point to an internal buffer, so copy the
|
|
||||||
// packet out here.
|
|
||||||
fresh := make([]byte, len(packet))
|
|
||||||
copy(fresh, packet)
|
|
||||||
|
|
||||||
return fresh, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *transport) writePacket(packet []byte) error {
|
|
||||||
if debugTransport {
|
|
||||||
t.printPacket(packet, true)
|
|
||||||
}
|
|
||||||
return t.writer.writePacket(t.bufWriter, t.rand, packet)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *connectionState) writePacket(w *bufio.Writer, rand io.Reader, packet []byte) error {
|
|
||||||
changeKeys := len(packet) > 0 && packet[0] == msgNewKeys
|
|
||||||
|
|
||||||
err := s.packetCipher.writeCipherPacket(s.seqNum, w, rand, packet)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err = w.Flush(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
s.seqNum++
|
|
||||||
if changeKeys {
|
|
||||||
select {
|
|
||||||
case cipher := <-s.pendingKeyChange:
|
|
||||||
s.packetCipher = cipher
|
|
||||||
default:
|
|
||||||
panic("ssh: no key material for msgNewKeys")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func newTransport(rwc io.ReadWriteCloser, rand io.Reader, isClient bool) *transport {
|
|
||||||
t := &transport{
|
|
||||||
bufReader: bufio.NewReader(rwc),
|
|
||||||
bufWriter: bufio.NewWriter(rwc),
|
|
||||||
rand: rand,
|
|
||||||
reader: connectionState{
|
|
||||||
packetCipher: &streamPacketCipher{cipher: noneCipher{}},
|
|
||||||
pendingKeyChange: make(chan packetCipher, 1),
|
|
||||||
},
|
|
||||||
writer: connectionState{
|
|
||||||
packetCipher: &streamPacketCipher{cipher: noneCipher{}},
|
|
||||||
pendingKeyChange: make(chan packetCipher, 1),
|
|
||||||
},
|
|
||||||
Closer: rwc,
|
|
||||||
}
|
|
||||||
t.isClient = isClient
|
|
||||||
|
|
||||||
if isClient {
|
|
||||||
t.reader.dir = serverKeys
|
|
||||||
t.writer.dir = clientKeys
|
|
||||||
} else {
|
|
||||||
t.reader.dir = clientKeys
|
|
||||||
t.writer.dir = serverKeys
|
|
||||||
}
|
|
||||||
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
type direction struct {
|
|
||||||
ivTag []byte
|
|
||||||
keyTag []byte
|
|
||||||
macKeyTag []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
serverKeys = direction{[]byte{'B'}, []byte{'D'}, []byte{'F'}}
|
|
||||||
clientKeys = direction{[]byte{'A'}, []byte{'C'}, []byte{'E'}}
|
|
||||||
)
|
|
||||||
|
|
||||||
// setupKeys sets the cipher and MAC keys from kex.K, kex.H and sessionId, as
|
|
||||||
// described in RFC 4253, section 6.4. direction should either be serverKeys
|
|
||||||
// (to setup server->client keys) or clientKeys (for client->server keys).
|
|
||||||
func newPacketCipher(d direction, algs directionAlgorithms, kex *kexResult) (packetCipher, error) {
|
|
||||||
cipherMode := cipherModes[algs.Cipher]
|
|
||||||
macMode := macModes[algs.MAC]
|
|
||||||
|
|
||||||
iv := make([]byte, cipherMode.ivSize)
|
|
||||||
key := make([]byte, cipherMode.keySize)
|
|
||||||
macKey := make([]byte, macMode.keySize)
|
|
||||||
|
|
||||||
generateKeyMaterial(iv, d.ivTag, kex)
|
|
||||||
generateKeyMaterial(key, d.keyTag, kex)
|
|
||||||
generateKeyMaterial(macKey, d.macKeyTag, kex)
|
|
||||||
|
|
||||||
return cipherModes[algs.Cipher].create(key, iv, macKey, algs)
|
|
||||||
}
|
|
||||||
|
|
||||||
// generateKeyMaterial fills out with key material generated from tag, K, H
|
|
||||||
// and sessionId, as specified in RFC 4253, section 7.2.
|
|
||||||
func generateKeyMaterial(out, tag []byte, r *kexResult) {
|
|
||||||
var digestsSoFar []byte
|
|
||||||
|
|
||||||
h := r.Hash.New()
|
|
||||||
for len(out) > 0 {
|
|
||||||
h.Reset()
|
|
||||||
h.Write(r.K)
|
|
||||||
h.Write(r.H)
|
|
||||||
|
|
||||||
if len(digestsSoFar) == 0 {
|
|
||||||
h.Write(tag)
|
|
||||||
h.Write(r.SessionID)
|
|
||||||
} else {
|
|
||||||
h.Write(digestsSoFar)
|
|
||||||
}
|
|
||||||
|
|
||||||
digest := h.Sum(nil)
|
|
||||||
n := copy(out, digest)
|
|
||||||
out = out[n:]
|
|
||||||
if len(out) > 0 {
|
|
||||||
digestsSoFar = append(digestsSoFar, digest...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const packageVersion = "SSH-2.0-Go"
|
|
||||||
|
|
||||||
// Sends and receives a version line. The versionLine string should
|
|
||||||
// be US ASCII, start with "SSH-2.0-", and should not include a
|
|
||||||
// newline. exchangeVersions returns the other side's version line.
|
|
||||||
func exchangeVersions(rw io.ReadWriter, versionLine []byte) (them []byte, err error) {
|
|
||||||
// Contrary to the RFC, we do not ignore lines that don't
|
|
||||||
// start with "SSH-2.0-" to make the library usable with
|
|
||||||
// nonconforming servers.
|
|
||||||
for _, c := range versionLine {
|
|
||||||
// The spec disallows non US-ASCII chars, and
|
|
||||||
// specifically forbids null chars.
|
|
||||||
if c < 32 {
|
|
||||||
return nil, errors.New("ssh: junk character in version line")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if _, err = rw.Write(append(versionLine, '\r', '\n')); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
them, err = readVersion(rw)
|
|
||||||
return them, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// maxVersionStringBytes is the maximum number of bytes that we'll
|
|
||||||
// accept as a version string. RFC 4253 section 4.2 limits this at 255
|
|
||||||
// chars
|
|
||||||
const maxVersionStringBytes = 255
|
|
||||||
|
|
||||||
// Read version string as specified by RFC 4253, section 4.2.
|
|
||||||
func readVersion(r io.Reader) ([]byte, error) {
|
|
||||||
versionString := make([]byte, 0, 64)
|
|
||||||
var ok bool
|
|
||||||
var buf [1]byte
|
|
||||||
|
|
||||||
for length := 0; length < maxVersionStringBytes; length++ {
|
|
||||||
_, err := io.ReadFull(r, buf[:])
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// The RFC says that the version should be terminated with \r\n
|
|
||||||
// but several SSH servers actually only send a \n.
|
|
||||||
if buf[0] == '\n' {
|
|
||||||
if !bytes.HasPrefix(versionString, []byte("SSH-")) {
|
|
||||||
// RFC 4253 says we need to ignore all version string lines
|
|
||||||
// except the one containing the SSH version (provided that
|
|
||||||
// all the lines do not exceed 255 bytes in total).
|
|
||||||
versionString = versionString[:0]
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
ok = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
// non ASCII chars are disallowed, but we are lenient,
|
|
||||||
// since Go doesn't use null-terminated strings.
|
|
||||||
|
|
||||||
// The RFC allows a comment after a space, however,
|
|
||||||
// all of it (version and comments) goes into the
|
|
||||||
// session hash.
|
|
||||||
versionString = append(versionString, buf[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
if !ok {
|
|
||||||
return nil, errors.New("ssh: overflow reading version string")
|
|
||||||
}
|
|
||||||
|
|
||||||
// There might be a '\r' on the end which we should remove.
|
|
||||||
if len(versionString) > 0 && versionString[len(versionString)-1] == '\r' {
|
|
||||||
versionString = versionString[:len(versionString)-1]
|
|
||||||
}
|
|
||||||
return versionString, nil
|
|
||||||
}
|
|
3
vendor/golang.org/x/sys/AUTHORS
generated
vendored
3
vendor/golang.org/x/sys/AUTHORS
generated
vendored
@ -1,3 +0,0 @@
|
|||||||
# 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.
|
|
3
vendor/golang.org/x/sys/CONTRIBUTORS
generated
vendored
3
vendor/golang.org/x/sys/CONTRIBUTORS
generated
vendored
@ -1,3 +0,0 @@
|
|||||||
# 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.
|
|
27
vendor/golang.org/x/sys/LICENSE
generated
vendored
27
vendor/golang.org/x/sys/LICENSE
generated
vendored
@ -1,27 +0,0 @@
|
|||||||
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/golang.org/x/sys/PATENTS
generated
vendored
22
vendor/golang.org/x/sys/PATENTS
generated
vendored
@ -1,22 +0,0 @@
|
|||||||
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.
|
|
17
vendor/golang.org/x/sys/cpu/asm_aix_ppc64.s
generated
vendored
17
vendor/golang.org/x/sys/cpu/asm_aix_ppc64.s
generated
vendored
@ -1,17 +0,0 @@
|
|||||||
// Copyright 2018 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.
|
|
||||||
|
|
||||||
// +build !gccgo
|
|
||||||
|
|
||||||
#include "textflag.h"
|
|
||||||
|
|
||||||
//
|
|
||||||
// System calls for ppc64, AIX are implemented in runtime/syscall_aix.go
|
|
||||||
//
|
|
||||||
|
|
||||||
TEXT ·syscall6(SB),NOSPLIT,$0-88
|
|
||||||
JMP syscall·syscall6(SB)
|
|
||||||
|
|
||||||
TEXT ·rawSyscall6(SB),NOSPLIT,$0-88
|
|
||||||
JMP syscall·rawSyscall6(SB)
|
|
30
vendor/golang.org/x/sys/cpu/byteorder.go
generated
vendored
30
vendor/golang.org/x/sys/cpu/byteorder.go
generated
vendored
@ -1,30 +0,0 @@
|
|||||||
// Copyright 2019 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 cpu
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/binary"
|
|
||||||
"runtime"
|
|
||||||
)
|
|
||||||
|
|
||||||
// hostByteOrder returns binary.LittleEndian on little-endian machines and
|
|
||||||
// binary.BigEndian on big-endian machines.
|
|
||||||
func hostByteOrder() binary.ByteOrder {
|
|
||||||
switch runtime.GOARCH {
|
|
||||||
case "386", "amd64", "amd64p32",
|
|
||||||
"arm", "arm64",
|
|
||||||
"mipsle", "mips64le", "mips64p32le",
|
|
||||||
"ppc64le",
|
|
||||||
"riscv", "riscv64":
|
|
||||||
return binary.LittleEndian
|
|
||||||
case "armbe", "arm64be",
|
|
||||||
"mips", "mips64", "mips64p32",
|
|
||||||
"ppc", "ppc64",
|
|
||||||
"s390", "s390x",
|
|
||||||
"sparc", "sparc64":
|
|
||||||
return binary.BigEndian
|
|
||||||
}
|
|
||||||
panic("unknown architecture")
|
|
||||||
}
|
|
126
vendor/golang.org/x/sys/cpu/cpu.go
generated
vendored
126
vendor/golang.org/x/sys/cpu/cpu.go
generated
vendored
@ -1,126 +0,0 @@
|
|||||||
// Copyright 2018 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 cpu implements processor feature detection for
|
|
||||||
// various CPU architectures.
|
|
||||||
package cpu
|
|
||||||
|
|
||||||
// Initialized reports whether the CPU features were initialized.
|
|
||||||
//
|
|
||||||
// For some GOOS/GOARCH combinations initialization of the CPU features depends
|
|
||||||
// on reading an operating specific file, e.g. /proc/self/auxv on linux/arm
|
|
||||||
// Initialized will report false if reading the file fails.
|
|
||||||
var Initialized bool
|
|
||||||
|
|
||||||
// CacheLinePad is used to pad structs to avoid false sharing.
|
|
||||||
type CacheLinePad struct{ _ [cacheLineSize]byte }
|
|
||||||
|
|
||||||
// X86 contains the supported CPU features of the
|
|
||||||
// current X86/AMD64 platform. If the current platform
|
|
||||||
// is not X86/AMD64 then all feature flags are false.
|
|
||||||
//
|
|
||||||
// X86 is padded to avoid false sharing. Further the HasAVX
|
|
||||||
// and HasAVX2 are only set if the OS supports XMM and YMM
|
|
||||||
// registers in addition to the CPUID feature bit being set.
|
|
||||||
var X86 struct {
|
|
||||||
_ CacheLinePad
|
|
||||||
HasAES bool // AES hardware implementation (AES NI)
|
|
||||||
HasADX bool // Multi-precision add-carry instruction extensions
|
|
||||||
HasAVX bool // Advanced vector extension
|
|
||||||
HasAVX2 bool // Advanced vector extension 2
|
|
||||||
HasBMI1 bool // Bit manipulation instruction set 1
|
|
||||||
HasBMI2 bool // Bit manipulation instruction set 2
|
|
||||||
HasERMS bool // Enhanced REP for MOVSB and STOSB
|
|
||||||
HasFMA bool // Fused-multiply-add instructions
|
|
||||||
HasOSXSAVE bool // OS supports XSAVE/XRESTOR for saving/restoring XMM registers.
|
|
||||||
HasPCLMULQDQ bool // PCLMULQDQ instruction - most often used for AES-GCM
|
|
||||||
HasPOPCNT bool // Hamming weight instruction POPCNT.
|
|
||||||
HasRDRAND bool // RDRAND instruction (on-chip random number generator)
|
|
||||||
HasRDSEED bool // RDSEED instruction (on-chip random number generator)
|
|
||||||
HasSSE2 bool // Streaming SIMD extension 2 (always available on amd64)
|
|
||||||
HasSSE3 bool // Streaming SIMD extension 3
|
|
||||||
HasSSSE3 bool // Supplemental streaming SIMD extension 3
|
|
||||||
HasSSE41 bool // Streaming SIMD extension 4 and 4.1
|
|
||||||
HasSSE42 bool // Streaming SIMD extension 4 and 4.2
|
|
||||||
_ CacheLinePad
|
|
||||||
}
|
|
||||||
|
|
||||||
// ARM64 contains the supported CPU features of the
|
|
||||||
// current ARMv8(aarch64) platform. If the current platform
|
|
||||||
// is not arm64 then all feature flags are false.
|
|
||||||
var ARM64 struct {
|
|
||||||
_ CacheLinePad
|
|
||||||
HasFP bool // Floating-point instruction set (always available)
|
|
||||||
HasASIMD bool // Advanced SIMD (always available)
|
|
||||||
HasEVTSTRM bool // Event stream support
|
|
||||||
HasAES bool // AES hardware implementation
|
|
||||||
HasPMULL bool // Polynomial multiplication instruction set
|
|
||||||
HasSHA1 bool // SHA1 hardware implementation
|
|
||||||
HasSHA2 bool // SHA2 hardware implementation
|
|
||||||
HasCRC32 bool // CRC32 hardware implementation
|
|
||||||
HasATOMICS bool // Atomic memory operation instruction set
|
|
||||||
HasFPHP bool // Half precision floating-point instruction set
|
|
||||||
HasASIMDHP bool // Advanced SIMD half precision instruction set
|
|
||||||
HasCPUID bool // CPUID identification scheme registers
|
|
||||||
HasASIMDRDM bool // Rounding double multiply add/subtract instruction set
|
|
||||||
HasJSCVT bool // Javascript conversion from floating-point to integer
|
|
||||||
HasFCMA bool // Floating-point multiplication and addition of complex numbers
|
|
||||||
HasLRCPC bool // Release Consistent processor consistent support
|
|
||||||
HasDCPOP bool // Persistent memory support
|
|
||||||
HasSHA3 bool // SHA3 hardware implementation
|
|
||||||
HasSM3 bool // SM3 hardware implementation
|
|
||||||
HasSM4 bool // SM4 hardware implementation
|
|
||||||
HasASIMDDP bool // Advanced SIMD double precision instruction set
|
|
||||||
HasSHA512 bool // SHA512 hardware implementation
|
|
||||||
HasSVE bool // Scalable Vector Extensions
|
|
||||||
HasASIMDFHM bool // Advanced SIMD multiplication FP16 to FP32
|
|
||||||
_ CacheLinePad
|
|
||||||
}
|
|
||||||
|
|
||||||
// PPC64 contains the supported CPU features of the current ppc64/ppc64le platforms.
|
|
||||||
// If the current platform is not ppc64/ppc64le then all feature flags are false.
|
|
||||||
//
|
|
||||||
// For ppc64/ppc64le, it is safe to check only for ISA level starting on ISA v3.00,
|
|
||||||
// since there are no optional categories. There are some exceptions that also
|
|
||||||
// require kernel support to work (DARN, SCV), so there are feature bits for
|
|
||||||
// those as well. The minimum processor requirement is POWER8 (ISA 2.07).
|
|
||||||
// The struct is padded to avoid false sharing.
|
|
||||||
var PPC64 struct {
|
|
||||||
_ CacheLinePad
|
|
||||||
HasDARN bool // Hardware random number generator (requires kernel enablement)
|
|
||||||
HasSCV bool // Syscall vectored (requires kernel enablement)
|
|
||||||
IsPOWER8 bool // ISA v2.07 (POWER8)
|
|
||||||
IsPOWER9 bool // ISA v3.00 (POWER9)
|
|
||||||
_ CacheLinePad
|
|
||||||
}
|
|
||||||
|
|
||||||
// S390X contains the supported CPU features of the current IBM Z
|
|
||||||
// (s390x) platform. If the current platform is not IBM Z then all
|
|
||||||
// feature flags are false.
|
|
||||||
//
|
|
||||||
// S390X is padded to avoid false sharing. Further HasVX is only set
|
|
||||||
// if the OS supports vector registers in addition to the STFLE
|
|
||||||
// feature bit being set.
|
|
||||||
var S390X struct {
|
|
||||||
_ CacheLinePad
|
|
||||||
HasZARCH bool // z/Architecture mode is active [mandatory]
|
|
||||||
HasSTFLE bool // store facility list extended
|
|
||||||
HasLDISP bool // long (20-bit) displacements
|
|
||||||
HasEIMM bool // 32-bit immediates
|
|
||||||
HasDFP bool // decimal floating point
|
|
||||||
HasETF3EH bool // ETF-3 enhanced
|
|
||||||
HasMSA bool // message security assist (CPACF)
|
|
||||||
HasAES bool // KM-AES{128,192,256} functions
|
|
||||||
HasAESCBC bool // KMC-AES{128,192,256} functions
|
|
||||||
HasAESCTR bool // KMCTR-AES{128,192,256} functions
|
|
||||||
HasAESGCM bool // KMA-GCM-AES{128,192,256} functions
|
|
||||||
HasGHASH bool // KIMD-GHASH function
|
|
||||||
HasSHA1 bool // K{I,L}MD-SHA-1 functions
|
|
||||||
HasSHA256 bool // K{I,L}MD-SHA-256 functions
|
|
||||||
HasSHA512 bool // K{I,L}MD-SHA-512 functions
|
|
||||||
HasSHA3 bool // K{I,L}MD-SHA3-{224,256,384,512} and K{I,L}MD-SHAKE-{128,256} functions
|
|
||||||
HasVX bool // vector facility
|
|
||||||
HasVXE bool // vector-enhancements facility 1
|
|
||||||
_ CacheLinePad
|
|
||||||
}
|
|
34
vendor/golang.org/x/sys/cpu/cpu_aix_ppc64.go
generated
vendored
34
vendor/golang.org/x/sys/cpu/cpu_aix_ppc64.go
generated
vendored
@ -1,34 +0,0 @@
|
|||||||
// Copyright 2019 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.
|
|
||||||
|
|
||||||
// +build aix,ppc64
|
|
||||||
|
|
||||||
package cpu
|
|
||||||
|
|
||||||
const cacheLineSize = 128
|
|
||||||
|
|
||||||
const (
|
|
||||||
// getsystemcfg constants
|
|
||||||
_SC_IMPL = 2
|
|
||||||
_IMPL_POWER8 = 0x10000
|
|
||||||
_IMPL_POWER9 = 0x20000
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
impl := getsystemcfg(_SC_IMPL)
|
|
||||||
if impl&_IMPL_POWER8 != 0 {
|
|
||||||
PPC64.IsPOWER8 = true
|
|
||||||
}
|
|
||||||
if impl&_IMPL_POWER9 != 0 {
|
|
||||||
PPC64.IsPOWER9 = true
|
|
||||||
}
|
|
||||||
|
|
||||||
Initialized = true
|
|
||||||
}
|
|
||||||
|
|
||||||
func getsystemcfg(label int) (n uint64) {
|
|
||||||
r0, _ := callgetsystemcfg(label)
|
|
||||||
n = uint64(r0)
|
|
||||||
return
|
|
||||||
}
|
|
9
vendor/golang.org/x/sys/cpu/cpu_arm.go
generated
vendored
9
vendor/golang.org/x/sys/cpu/cpu_arm.go
generated
vendored
@ -1,9 +0,0 @@
|
|||||||
// Copyright 2018 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 cpu
|
|
||||||
|
|
||||||
const cacheLineSize = 32
|
|
||||||
|
|
||||||
func doinit() {}
|
|
21
vendor/golang.org/x/sys/cpu/cpu_gc_s390x.go
generated
vendored
21
vendor/golang.org/x/sys/cpu/cpu_gc_s390x.go
generated
vendored
@ -1,21 +0,0 @@
|
|||||||
// Copyright 2019 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.
|
|
||||||
|
|
||||||
// +build !gccgo
|
|
||||||
|
|
||||||
package cpu
|
|
||||||
|
|
||||||
// haveAsmFunctions reports whether the other functions in this file can
|
|
||||||
// be safely called.
|
|
||||||
func haveAsmFunctions() bool { return true }
|
|
||||||
|
|
||||||
// The following feature detection functions are defined in cpu_s390x.s.
|
|
||||||
// They are likely to be expensive to call so the results should be cached.
|
|
||||||
func stfle() facilityList
|
|
||||||
func kmQuery() queryResult
|
|
||||||
func kmcQuery() queryResult
|
|
||||||
func kmctrQuery() queryResult
|
|
||||||
func kmaQuery() queryResult
|
|
||||||
func kimdQuery() queryResult
|
|
||||||
func klmdQuery() queryResult
|
|
16
vendor/golang.org/x/sys/cpu/cpu_gc_x86.go
generated
vendored
16
vendor/golang.org/x/sys/cpu/cpu_gc_x86.go
generated
vendored
@ -1,16 +0,0 @@
|
|||||||
// Copyright 2018 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.
|
|
||||||
|
|
||||||
// +build 386 amd64 amd64p32
|
|
||||||
// +build !gccgo
|
|
||||||
|
|
||||||
package cpu
|
|
||||||
|
|
||||||
// cpuid is implemented in cpu_x86.s for gc compiler
|
|
||||||
// and in cpu_gccgo.c for gccgo.
|
|
||||||
func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32)
|
|
||||||
|
|
||||||
// xgetbv with ecx = 0 is implemented in cpu_x86.s for gc compiler
|
|
||||||
// and in cpu_gccgo.c for gccgo.
|
|
||||||
func xgetbv() (eax, edx uint32)
|
|
43
vendor/golang.org/x/sys/cpu/cpu_gccgo.c
generated
vendored
43
vendor/golang.org/x/sys/cpu/cpu_gccgo.c
generated
vendored
@ -1,43 +0,0 @@
|
|||||||
// Copyright 2018 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.
|
|
||||||
|
|
||||||
// +build 386 amd64 amd64p32
|
|
||||||
// +build gccgo
|
|
||||||
|
|
||||||
#include <cpuid.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
// Need to wrap __get_cpuid_count because it's declared as static.
|
|
||||||
int
|
|
||||||
gccgoGetCpuidCount(uint32_t leaf, uint32_t subleaf,
|
|
||||||
uint32_t *eax, uint32_t *ebx,
|
|
||||||
uint32_t *ecx, uint32_t *edx)
|
|
||||||
{
|
|
||||||
return __get_cpuid_count(leaf, subleaf, eax, ebx, ecx, edx);
|
|
||||||
}
|
|
||||||
|
|
||||||
// xgetbv reads the contents of an XCR (Extended Control Register)
|
|
||||||
// specified in the ECX register into registers EDX:EAX.
|
|
||||||
// Currently, the only supported value for XCR is 0.
|
|
||||||
//
|
|
||||||
// TODO: Replace with a better alternative:
|
|
||||||
//
|
|
||||||
// #include <xsaveintrin.h>
|
|
||||||
//
|
|
||||||
// #pragma GCC target("xsave")
|
|
||||||
//
|
|
||||||
// void gccgoXgetbv(uint32_t *eax, uint32_t *edx) {
|
|
||||||
// unsigned long long x = _xgetbv(0);
|
|
||||||
// *eax = x & 0xffffffff;
|
|
||||||
// *edx = (x >> 32) & 0xffffffff;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Note that _xgetbv is defined starting with GCC 8.
|
|
||||||
void
|
|
||||||
gccgoXgetbv(uint32_t *eax, uint32_t *edx)
|
|
||||||
{
|
|
||||||
__asm(" xorl %%ecx, %%ecx\n"
|
|
||||||
" xgetbv"
|
|
||||||
: "=a"(*eax), "=d"(*edx));
|
|
||||||
}
|
|
26
vendor/golang.org/x/sys/cpu/cpu_gccgo.go
generated
vendored
26
vendor/golang.org/x/sys/cpu/cpu_gccgo.go
generated
vendored
@ -1,26 +0,0 @@
|
|||||||
// Copyright 2018 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.
|
|
||||||
|
|
||||||
// +build 386 amd64 amd64p32
|
|
||||||
// +build gccgo
|
|
||||||
|
|
||||||
package cpu
|
|
||||||
|
|
||||||
//extern gccgoGetCpuidCount
|
|
||||||
func gccgoGetCpuidCount(eaxArg, ecxArg uint32, eax, ebx, ecx, edx *uint32)
|
|
||||||
|
|
||||||
func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32) {
|
|
||||||
var a, b, c, d uint32
|
|
||||||
gccgoGetCpuidCount(eaxArg, ecxArg, &a, &b, &c, &d)
|
|
||||||
return a, b, c, d
|
|
||||||
}
|
|
||||||
|
|
||||||
//extern gccgoXgetbv
|
|
||||||
func gccgoXgetbv(eax, edx *uint32)
|
|
||||||
|
|
||||||
func xgetbv() (eax, edx uint32) {
|
|
||||||
var a, d uint32
|
|
||||||
gccgoXgetbv(&a, &d)
|
|
||||||
return a, d
|
|
||||||
}
|
|
22
vendor/golang.org/x/sys/cpu/cpu_gccgo_s390x.go
generated
vendored
22
vendor/golang.org/x/sys/cpu/cpu_gccgo_s390x.go
generated
vendored
@ -1,22 +0,0 @@
|
|||||||
// Copyright 2019 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.
|
|
||||||
|
|
||||||
// +build gccgo
|
|
||||||
|
|
||||||
package cpu
|
|
||||||
|
|
||||||
// haveAsmFunctions reports whether the other functions in this file can
|
|
||||||
// be safely called.
|
|
||||||
func haveAsmFunctions() bool { return false }
|
|
||||||
|
|
||||||
// TODO(mundaym): the following feature detection functions are currently
|
|
||||||
// stubs. See https://golang.org/cl/162887 for how to fix this.
|
|
||||||
// They are likely to be expensive to call so the results should be cached.
|
|
||||||
func stfle() facilityList { panic("not implemented for gccgo") }
|
|
||||||
func kmQuery() queryResult { panic("not implemented for gccgo") }
|
|
||||||
func kmcQuery() queryResult { panic("not implemented for gccgo") }
|
|
||||||
func kmctrQuery() queryResult { panic("not implemented for gccgo") }
|
|
||||||
func kmaQuery() queryResult { panic("not implemented for gccgo") }
|
|
||||||
func kimdQuery() queryResult { panic("not implemented for gccgo") }
|
|
||||||
func klmdQuery() queryResult { panic("not implemented for gccgo") }
|
|
59
vendor/golang.org/x/sys/cpu/cpu_linux.go
generated
vendored
59
vendor/golang.org/x/sys/cpu/cpu_linux.go
generated
vendored
@ -1,59 +0,0 @@
|
|||||||
// Copyright 2018 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.
|
|
||||||
|
|
||||||
//+build !amd64,!amd64p32,!386
|
|
||||||
|
|
||||||
package cpu
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io/ioutil"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
_AT_HWCAP = 16
|
|
||||||
_AT_HWCAP2 = 26
|
|
||||||
|
|
||||||
procAuxv = "/proc/self/auxv"
|
|
||||||
|
|
||||||
uintSize = int(32 << (^uint(0) >> 63))
|
|
||||||
)
|
|
||||||
|
|
||||||
// For those platforms don't have a 'cpuid' equivalent we use HWCAP/HWCAP2
|
|
||||||
// These are initialized in cpu_$GOARCH.go
|
|
||||||
// and should not be changed after they are initialized.
|
|
||||||
var hwCap uint
|
|
||||||
var hwCap2 uint
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
buf, err := ioutil.ReadFile(procAuxv)
|
|
||||||
if err != nil {
|
|
||||||
// e.g. on android /proc/self/auxv is not accessible, so silently
|
|
||||||
// ignore the error and leave Initialized = false
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
bo := hostByteOrder()
|
|
||||||
for len(buf) >= 2*(uintSize/8) {
|
|
||||||
var tag, val uint
|
|
||||||
switch uintSize {
|
|
||||||
case 32:
|
|
||||||
tag = uint(bo.Uint32(buf[0:]))
|
|
||||||
val = uint(bo.Uint32(buf[4:]))
|
|
||||||
buf = buf[8:]
|
|
||||||
case 64:
|
|
||||||
tag = uint(bo.Uint64(buf[0:]))
|
|
||||||
val = uint(bo.Uint64(buf[8:]))
|
|
||||||
buf = buf[16:]
|
|
||||||
}
|
|
||||||
switch tag {
|
|
||||||
case _AT_HWCAP:
|
|
||||||
hwCap = val
|
|
||||||
case _AT_HWCAP2:
|
|
||||||
hwCap2 = val
|
|
||||||
}
|
|
||||||
}
|
|
||||||
doinit()
|
|
||||||
|
|
||||||
Initialized = true
|
|
||||||
}
|
|
67
vendor/golang.org/x/sys/cpu/cpu_linux_arm64.go
generated
vendored
67
vendor/golang.org/x/sys/cpu/cpu_linux_arm64.go
generated
vendored
@ -1,67 +0,0 @@
|
|||||||
// Copyright 2018 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 cpu
|
|
||||||
|
|
||||||
const cacheLineSize = 64
|
|
||||||
|
|
||||||
// HWCAP/HWCAP2 bits. These are exposed by Linux.
|
|
||||||
const (
|
|
||||||
hwcap_FP = 1 << 0
|
|
||||||
hwcap_ASIMD = 1 << 1
|
|
||||||
hwcap_EVTSTRM = 1 << 2
|
|
||||||
hwcap_AES = 1 << 3
|
|
||||||
hwcap_PMULL = 1 << 4
|
|
||||||
hwcap_SHA1 = 1 << 5
|
|
||||||
hwcap_SHA2 = 1 << 6
|
|
||||||
hwcap_CRC32 = 1 << 7
|
|
||||||
hwcap_ATOMICS = 1 << 8
|
|
||||||
hwcap_FPHP = 1 << 9
|
|
||||||
hwcap_ASIMDHP = 1 << 10
|
|
||||||
hwcap_CPUID = 1 << 11
|
|
||||||
hwcap_ASIMDRDM = 1 << 12
|
|
||||||
hwcap_JSCVT = 1 << 13
|
|
||||||
hwcap_FCMA = 1 << 14
|
|
||||||
hwcap_LRCPC = 1 << 15
|
|
||||||
hwcap_DCPOP = 1 << 16
|
|
||||||
hwcap_SHA3 = 1 << 17
|
|
||||||
hwcap_SM3 = 1 << 18
|
|
||||||
hwcap_SM4 = 1 << 19
|
|
||||||
hwcap_ASIMDDP = 1 << 20
|
|
||||||
hwcap_SHA512 = 1 << 21
|
|
||||||
hwcap_SVE = 1 << 22
|
|
||||||
hwcap_ASIMDFHM = 1 << 23
|
|
||||||
)
|
|
||||||
|
|
||||||
func doinit() {
|
|
||||||
// HWCAP feature bits
|
|
||||||
ARM64.HasFP = isSet(hwCap, hwcap_FP)
|
|
||||||
ARM64.HasASIMD = isSet(hwCap, hwcap_ASIMD)
|
|
||||||
ARM64.HasEVTSTRM = isSet(hwCap, hwcap_EVTSTRM)
|
|
||||||
ARM64.HasAES = isSet(hwCap, hwcap_AES)
|
|
||||||
ARM64.HasPMULL = isSet(hwCap, hwcap_PMULL)
|
|
||||||
ARM64.HasSHA1 = isSet(hwCap, hwcap_SHA1)
|
|
||||||
ARM64.HasSHA2 = isSet(hwCap, hwcap_SHA2)
|
|
||||||
ARM64.HasCRC32 = isSet(hwCap, hwcap_CRC32)
|
|
||||||
ARM64.HasATOMICS = isSet(hwCap, hwcap_ATOMICS)
|
|
||||||
ARM64.HasFPHP = isSet(hwCap, hwcap_FPHP)
|
|
||||||
ARM64.HasASIMDHP = isSet(hwCap, hwcap_ASIMDHP)
|
|
||||||
ARM64.HasCPUID = isSet(hwCap, hwcap_CPUID)
|
|
||||||
ARM64.HasASIMDRDM = isSet(hwCap, hwcap_ASIMDRDM)
|
|
||||||
ARM64.HasJSCVT = isSet(hwCap, hwcap_JSCVT)
|
|
||||||
ARM64.HasFCMA = isSet(hwCap, hwcap_FCMA)
|
|
||||||
ARM64.HasLRCPC = isSet(hwCap, hwcap_LRCPC)
|
|
||||||
ARM64.HasDCPOP = isSet(hwCap, hwcap_DCPOP)
|
|
||||||
ARM64.HasSHA3 = isSet(hwCap, hwcap_SHA3)
|
|
||||||
ARM64.HasSM3 = isSet(hwCap, hwcap_SM3)
|
|
||||||
ARM64.HasSM4 = isSet(hwCap, hwcap_SM4)
|
|
||||||
ARM64.HasASIMDDP = isSet(hwCap, hwcap_ASIMDDP)
|
|
||||||
ARM64.HasSHA512 = isSet(hwCap, hwcap_SHA512)
|
|
||||||
ARM64.HasSVE = isSet(hwCap, hwcap_SVE)
|
|
||||||
ARM64.HasASIMDFHM = isSet(hwCap, hwcap_ASIMDFHM)
|
|
||||||
}
|
|
||||||
|
|
||||||
func isSet(hwc uint, value uint) bool {
|
|
||||||
return hwc&value != 0
|
|
||||||
}
|
|
33
vendor/golang.org/x/sys/cpu/cpu_linux_ppc64x.go
generated
vendored
33
vendor/golang.org/x/sys/cpu/cpu_linux_ppc64x.go
generated
vendored
@ -1,33 +0,0 @@
|
|||||||
// Copyright 2018 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.
|
|
||||||
|
|
||||||
// +build linux
|
|
||||||
// +build ppc64 ppc64le
|
|
||||||
|
|
||||||
package cpu
|
|
||||||
|
|
||||||
const cacheLineSize = 128
|
|
||||||
|
|
||||||
// HWCAP/HWCAP2 bits. These are exposed by the kernel.
|
|
||||||
const (
|
|
||||||
// ISA Level
|
|
||||||
_PPC_FEATURE2_ARCH_2_07 = 0x80000000
|
|
||||||
_PPC_FEATURE2_ARCH_3_00 = 0x00800000
|
|
||||||
|
|
||||||
// CPU features
|
|
||||||
_PPC_FEATURE2_DARN = 0x00200000
|
|
||||||
_PPC_FEATURE2_SCV = 0x00100000
|
|
||||||
)
|
|
||||||
|
|
||||||
func doinit() {
|
|
||||||
// HWCAP2 feature bits
|
|
||||||
PPC64.IsPOWER8 = isSet(hwCap2, _PPC_FEATURE2_ARCH_2_07)
|
|
||||||
PPC64.IsPOWER9 = isSet(hwCap2, _PPC_FEATURE2_ARCH_3_00)
|
|
||||||
PPC64.HasDARN = isSet(hwCap2, _PPC_FEATURE2_DARN)
|
|
||||||
PPC64.HasSCV = isSet(hwCap2, _PPC_FEATURE2_SCV)
|
|
||||||
}
|
|
||||||
|
|
||||||
func isSet(hwc uint, value uint) bool {
|
|
||||||
return hwc&value != 0
|
|
||||||
}
|
|
161
vendor/golang.org/x/sys/cpu/cpu_linux_s390x.go
generated
vendored
161
vendor/golang.org/x/sys/cpu/cpu_linux_s390x.go
generated
vendored
@ -1,161 +0,0 @@
|
|||||||
// Copyright 2019 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 cpu
|
|
||||||
|
|
||||||
const cacheLineSize = 256
|
|
||||||
|
|
||||||
const (
|
|
||||||
// bit mask values from /usr/include/bits/hwcap.h
|
|
||||||
hwcap_ZARCH = 2
|
|
||||||
hwcap_STFLE = 4
|
|
||||||
hwcap_MSA = 8
|
|
||||||
hwcap_LDISP = 16
|
|
||||||
hwcap_EIMM = 32
|
|
||||||
hwcap_DFP = 64
|
|
||||||
hwcap_ETF3EH = 256
|
|
||||||
hwcap_VX = 2048
|
|
||||||
hwcap_VXE = 8192
|
|
||||||
)
|
|
||||||
|
|
||||||
// bitIsSet reports whether the bit at index is set. The bit index
|
|
||||||
// is in big endian order, so bit index 0 is the leftmost bit.
|
|
||||||
func bitIsSet(bits []uint64, index uint) bool {
|
|
||||||
return bits[index/64]&((1<<63)>>(index%64)) != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// function is the code for the named cryptographic function.
|
|
||||||
type function uint8
|
|
||||||
|
|
||||||
const (
|
|
||||||
// KM{,A,C,CTR} function codes
|
|
||||||
aes128 function = 18 // AES-128
|
|
||||||
aes192 function = 19 // AES-192
|
|
||||||
aes256 function = 20 // AES-256
|
|
||||||
|
|
||||||
// K{I,L}MD function codes
|
|
||||||
sha1 function = 1 // SHA-1
|
|
||||||
sha256 function = 2 // SHA-256
|
|
||||||
sha512 function = 3 // SHA-512
|
|
||||||
sha3_224 function = 32 // SHA3-224
|
|
||||||
sha3_256 function = 33 // SHA3-256
|
|
||||||
sha3_384 function = 34 // SHA3-384
|
|
||||||
sha3_512 function = 35 // SHA3-512
|
|
||||||
shake128 function = 36 // SHAKE-128
|
|
||||||
shake256 function = 37 // SHAKE-256
|
|
||||||
|
|
||||||
// KLMD function codes
|
|
||||||
ghash function = 65 // GHASH
|
|
||||||
)
|
|
||||||
|
|
||||||
// queryResult contains the result of a Query function
|
|
||||||
// call. Bits are numbered in big endian order so the
|
|
||||||
// leftmost bit (the MSB) is at index 0.
|
|
||||||
type queryResult struct {
|
|
||||||
bits [2]uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
// Has reports whether the given functions are present.
|
|
||||||
func (q *queryResult) Has(fns ...function) bool {
|
|
||||||
if len(fns) == 0 {
|
|
||||||
panic("no function codes provided")
|
|
||||||
}
|
|
||||||
for _, f := range fns {
|
|
||||||
if !bitIsSet(q.bits[:], uint(f)) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// facility is a bit index for the named facility.
|
|
||||||
type facility uint8
|
|
||||||
|
|
||||||
const (
|
|
||||||
// cryptography facilities
|
|
||||||
msa4 facility = 77 // message-security-assist extension 4
|
|
||||||
msa8 facility = 146 // message-security-assist extension 8
|
|
||||||
)
|
|
||||||
|
|
||||||
// facilityList contains the result of an STFLE call.
|
|
||||||
// Bits are numbered in big endian order so the
|
|
||||||
// leftmost bit (the MSB) is at index 0.
|
|
||||||
type facilityList struct {
|
|
||||||
bits [4]uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
// Has reports whether the given facilities are present.
|
|
||||||
func (s *facilityList) Has(fs ...facility) bool {
|
|
||||||
if len(fs) == 0 {
|
|
||||||
panic("no facility bits provided")
|
|
||||||
}
|
|
||||||
for _, f := range fs {
|
|
||||||
if !bitIsSet(s.bits[:], uint(f)) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func doinit() {
|
|
||||||
// test HWCAP bit vector
|
|
||||||
has := func(featureMask uint) bool {
|
|
||||||
return hwCap&featureMask == featureMask
|
|
||||||
}
|
|
||||||
|
|
||||||
// mandatory
|
|
||||||
S390X.HasZARCH = has(hwcap_ZARCH)
|
|
||||||
|
|
||||||
// optional
|
|
||||||
S390X.HasSTFLE = has(hwcap_STFLE)
|
|
||||||
S390X.HasLDISP = has(hwcap_LDISP)
|
|
||||||
S390X.HasEIMM = has(hwcap_EIMM)
|
|
||||||
S390X.HasETF3EH = has(hwcap_ETF3EH)
|
|
||||||
S390X.HasDFP = has(hwcap_DFP)
|
|
||||||
S390X.HasMSA = has(hwcap_MSA)
|
|
||||||
S390X.HasVX = has(hwcap_VX)
|
|
||||||
if S390X.HasVX {
|
|
||||||
S390X.HasVXE = has(hwcap_VXE)
|
|
||||||
}
|
|
||||||
|
|
||||||
// We need implementations of stfle, km and so on
|
|
||||||
// to detect cryptographic features.
|
|
||||||
if !haveAsmFunctions() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// optional cryptographic functions
|
|
||||||
if S390X.HasMSA {
|
|
||||||
aes := []function{aes128, aes192, aes256}
|
|
||||||
|
|
||||||
// cipher message
|
|
||||||
km, kmc := kmQuery(), kmcQuery()
|
|
||||||
S390X.HasAES = km.Has(aes...)
|
|
||||||
S390X.HasAESCBC = kmc.Has(aes...)
|
|
||||||
if S390X.HasSTFLE {
|
|
||||||
facilities := stfle()
|
|
||||||
if facilities.Has(msa4) {
|
|
||||||
kmctr := kmctrQuery()
|
|
||||||
S390X.HasAESCTR = kmctr.Has(aes...)
|
|
||||||
}
|
|
||||||
if facilities.Has(msa8) {
|
|
||||||
kma := kmaQuery()
|
|
||||||
S390X.HasAESGCM = kma.Has(aes...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// compute message digest
|
|
||||||
kimd := kimdQuery() // intermediate (no padding)
|
|
||||||
klmd := klmdQuery() // last (padding)
|
|
||||||
S390X.HasSHA1 = kimd.Has(sha1) && klmd.Has(sha1)
|
|
||||||
S390X.HasSHA256 = kimd.Has(sha256) && klmd.Has(sha256)
|
|
||||||
S390X.HasSHA512 = kimd.Has(sha512) && klmd.Has(sha512)
|
|
||||||
S390X.HasGHASH = kimd.Has(ghash) // KLMD-GHASH does not exist
|
|
||||||
sha3 := []function{
|
|
||||||
sha3_224, sha3_256, sha3_384, sha3_512,
|
|
||||||
shake128, shake256,
|
|
||||||
}
|
|
||||||
S390X.HasSHA3 = kimd.Has(sha3...) && klmd.Has(sha3...)
|
|
||||||
}
|
|
||||||
}
|
|
11
vendor/golang.org/x/sys/cpu/cpu_mips64x.go
generated
vendored
11
vendor/golang.org/x/sys/cpu/cpu_mips64x.go
generated
vendored
@ -1,11 +0,0 @@
|
|||||||
// Copyright 2018 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.
|
|
||||||
|
|
||||||
// +build mips64 mips64le
|
|
||||||
|
|
||||||
package cpu
|
|
||||||
|
|
||||||
const cacheLineSize = 32
|
|
||||||
|
|
||||||
func doinit() {}
|
|
11
vendor/golang.org/x/sys/cpu/cpu_mipsx.go
generated
vendored
11
vendor/golang.org/x/sys/cpu/cpu_mipsx.go
generated
vendored
@ -1,11 +0,0 @@
|
|||||||
// Copyright 2018 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.
|
|
||||||
|
|
||||||
// +build mips mipsle
|
|
||||||
|
|
||||||
package cpu
|
|
||||||
|
|
||||||
const cacheLineSize = 32
|
|
||||||
|
|
||||||
func doinit() {}
|
|
11
vendor/golang.org/x/sys/cpu/cpu_other_arm64.go
generated
vendored
11
vendor/golang.org/x/sys/cpu/cpu_other_arm64.go
generated
vendored
@ -1,11 +0,0 @@
|
|||||||
// Copyright 2019 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.
|
|
||||||
|
|
||||||
// +build !linux,arm64
|
|
||||||
|
|
||||||
package cpu
|
|
||||||
|
|
||||||
const cacheLineSize = 64
|
|
||||||
|
|
||||||
func doinit() {}
|
|
57
vendor/golang.org/x/sys/cpu/cpu_s390x.s
generated
vendored
57
vendor/golang.org/x/sys/cpu/cpu_s390x.s
generated
vendored
@ -1,57 +0,0 @@
|
|||||||
// Copyright 2019 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.
|
|
||||||
|
|
||||||
// +build !gccgo
|
|
||||||
|
|
||||||
#include "textflag.h"
|
|
||||||
|
|
||||||
// func stfle() facilityList
|
|
||||||
TEXT ·stfle(SB), NOSPLIT|NOFRAME, $0-32
|
|
||||||
MOVD $ret+0(FP), R1
|
|
||||||
MOVD $3, R0 // last doubleword index to store
|
|
||||||
XC $32, (R1), (R1) // clear 4 doublewords (32 bytes)
|
|
||||||
WORD $0xb2b01000 // store facility list extended (STFLE)
|
|
||||||
RET
|
|
||||||
|
|
||||||
// func kmQuery() queryResult
|
|
||||||
TEXT ·kmQuery(SB), NOSPLIT|NOFRAME, $0-16
|
|
||||||
MOVD $0, R0 // set function code to 0 (KM-Query)
|
|
||||||
MOVD $ret+0(FP), R1 // address of 16-byte return value
|
|
||||||
WORD $0xB92E0024 // cipher message (KM)
|
|
||||||
RET
|
|
||||||
|
|
||||||
// func kmcQuery() queryResult
|
|
||||||
TEXT ·kmcQuery(SB), NOSPLIT|NOFRAME, $0-16
|
|
||||||
MOVD $0, R0 // set function code to 0 (KMC-Query)
|
|
||||||
MOVD $ret+0(FP), R1 // address of 16-byte return value
|
|
||||||
WORD $0xB92F0024 // cipher message with chaining (KMC)
|
|
||||||
RET
|
|
||||||
|
|
||||||
// func kmctrQuery() queryResult
|
|
||||||
TEXT ·kmctrQuery(SB), NOSPLIT|NOFRAME, $0-16
|
|
||||||
MOVD $0, R0 // set function code to 0 (KMCTR-Query)
|
|
||||||
MOVD $ret+0(FP), R1 // address of 16-byte return value
|
|
||||||
WORD $0xB92D4024 // cipher message with counter (KMCTR)
|
|
||||||
RET
|
|
||||||
|
|
||||||
// func kmaQuery() queryResult
|
|
||||||
TEXT ·kmaQuery(SB), NOSPLIT|NOFRAME, $0-16
|
|
||||||
MOVD $0, R0 // set function code to 0 (KMA-Query)
|
|
||||||
MOVD $ret+0(FP), R1 // address of 16-byte return value
|
|
||||||
WORD $0xb9296024 // cipher message with authentication (KMA)
|
|
||||||
RET
|
|
||||||
|
|
||||||
// func kimdQuery() queryResult
|
|
||||||
TEXT ·kimdQuery(SB), NOSPLIT|NOFRAME, $0-16
|
|
||||||
MOVD $0, R0 // set function code to 0 (KIMD-Query)
|
|
||||||
MOVD $ret+0(FP), R1 // address of 16-byte return value
|
|
||||||
WORD $0xB93E0024 // compute intermediate message digest (KIMD)
|
|
||||||
RET
|
|
||||||
|
|
||||||
// func klmdQuery() queryResult
|
|
||||||
TEXT ·klmdQuery(SB), NOSPLIT|NOFRAME, $0-16
|
|
||||||
MOVD $0, R0 // set function code to 0 (KLMD-Query)
|
|
||||||
MOVD $ret+0(FP), R1 // address of 16-byte return value
|
|
||||||
WORD $0xB93F0024 // compute last message digest (KLMD)
|
|
||||||
RET
|
|
15
vendor/golang.org/x/sys/cpu/cpu_wasm.go
generated
vendored
15
vendor/golang.org/x/sys/cpu/cpu_wasm.go
generated
vendored
@ -1,15 +0,0 @@
|
|||||||
// Copyright 2019 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.
|
|
||||||
|
|
||||||
// +build wasm
|
|
||||||
|
|
||||||
package cpu
|
|
||||||
|
|
||||||
// We're compiling the cpu package for an unknown (software-abstracted) CPU.
|
|
||||||
// Make CacheLinePad an empty struct and hope that the usual struct alignment
|
|
||||||
// rules are good enough.
|
|
||||||
|
|
||||||
const cacheLineSize = 0
|
|
||||||
|
|
||||||
func doinit() {}
|
|
59
vendor/golang.org/x/sys/cpu/cpu_x86.go
generated
vendored
59
vendor/golang.org/x/sys/cpu/cpu_x86.go
generated
vendored
@ -1,59 +0,0 @@
|
|||||||
// Copyright 2018 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.
|
|
||||||
|
|
||||||
// +build 386 amd64 amd64p32
|
|
||||||
|
|
||||||
package cpu
|
|
||||||
|
|
||||||
const cacheLineSize = 64
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
Initialized = true
|
|
||||||
|
|
||||||
maxID, _, _, _ := cpuid(0, 0)
|
|
||||||
|
|
||||||
if maxID < 1 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
_, _, ecx1, edx1 := cpuid(1, 0)
|
|
||||||
X86.HasSSE2 = isSet(26, edx1)
|
|
||||||
|
|
||||||
X86.HasSSE3 = isSet(0, ecx1)
|
|
||||||
X86.HasPCLMULQDQ = isSet(1, ecx1)
|
|
||||||
X86.HasSSSE3 = isSet(9, ecx1)
|
|
||||||
X86.HasFMA = isSet(12, ecx1)
|
|
||||||
X86.HasSSE41 = isSet(19, ecx1)
|
|
||||||
X86.HasSSE42 = isSet(20, ecx1)
|
|
||||||
X86.HasPOPCNT = isSet(23, ecx1)
|
|
||||||
X86.HasAES = isSet(25, ecx1)
|
|
||||||
X86.HasOSXSAVE = isSet(27, ecx1)
|
|
||||||
X86.HasRDRAND = isSet(30, ecx1)
|
|
||||||
|
|
||||||
osSupportsAVX := false
|
|
||||||
// For XGETBV, OSXSAVE bit is required and sufficient.
|
|
||||||
if X86.HasOSXSAVE {
|
|
||||||
eax, _ := xgetbv()
|
|
||||||
// Check if XMM and YMM registers have OS support.
|
|
||||||
osSupportsAVX = isSet(1, eax) && isSet(2, eax)
|
|
||||||
}
|
|
||||||
|
|
||||||
X86.HasAVX = isSet(28, ecx1) && osSupportsAVX
|
|
||||||
|
|
||||||
if maxID < 7 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
_, ebx7, _, _ := cpuid(7, 0)
|
|
||||||
X86.HasBMI1 = isSet(3, ebx7)
|
|
||||||
X86.HasAVX2 = isSet(5, ebx7) && osSupportsAVX
|
|
||||||
X86.HasBMI2 = isSet(8, ebx7)
|
|
||||||
X86.HasERMS = isSet(9, ebx7)
|
|
||||||
X86.HasRDSEED = isSet(18, ebx7)
|
|
||||||
X86.HasADX = isSet(19, ebx7)
|
|
||||||
}
|
|
||||||
|
|
||||||
func isSet(bitpos uint, value uint32) bool {
|
|
||||||
return value&(1<<bitpos) != 0
|
|
||||||
}
|
|
27
vendor/golang.org/x/sys/cpu/cpu_x86.s
generated
vendored
27
vendor/golang.org/x/sys/cpu/cpu_x86.s
generated
vendored
@ -1,27 +0,0 @@
|
|||||||
// Copyright 2018 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.
|
|
||||||
|
|
||||||
// +build 386 amd64 amd64p32
|
|
||||||
// +build !gccgo
|
|
||||||
|
|
||||||
#include "textflag.h"
|
|
||||||
|
|
||||||
// func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32)
|
|
||||||
TEXT ·cpuid(SB), NOSPLIT, $0-24
|
|
||||||
MOVL eaxArg+0(FP), AX
|
|
||||||
MOVL ecxArg+4(FP), CX
|
|
||||||
CPUID
|
|
||||||
MOVL AX, eax+8(FP)
|
|
||||||
MOVL BX, ebx+12(FP)
|
|
||||||
MOVL CX, ecx+16(FP)
|
|
||||||
MOVL DX, edx+20(FP)
|
|
||||||
RET
|
|
||||||
|
|
||||||
// func xgetbv() (eax, edx uint32)
|
|
||||||
TEXT ·xgetbv(SB),NOSPLIT,$0-8
|
|
||||||
MOVL $0, CX
|
|
||||||
XGETBV
|
|
||||||
MOVL AX, eax+0(FP)
|
|
||||||
MOVL DX, edx+4(FP)
|
|
||||||
RET
|
|
36
vendor/golang.org/x/sys/cpu/syscall_aix_ppc64_gc.go
generated
vendored
36
vendor/golang.org/x/sys/cpu/syscall_aix_ppc64_gc.go
generated
vendored
@ -1,36 +0,0 @@
|
|||||||
// Copyright 2019 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.
|
|
||||||
|
|
||||||
// Minimal copy of x/sys/unix so the cpu package can make a
|
|
||||||
// system call on AIX without depending on x/sys/unix.
|
|
||||||
// (See golang.org/issue/32102)
|
|
||||||
|
|
||||||
// +build aix,ppc64
|
|
||||||
// +build !gccgo
|
|
||||||
|
|
||||||
package cpu
|
|
||||||
|
|
||||||
import (
|
|
||||||
"syscall"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
//go:cgo_import_dynamic libc_getsystemcfg getsystemcfg "libc.a/shr_64.o"
|
|
||||||
|
|
||||||
//go:linkname libc_getsystemcfg libc_getsystemcfg
|
|
||||||
|
|
||||||
type syscallFunc uintptr
|
|
||||||
|
|
||||||
var libc_getsystemcfg syscallFunc
|
|
||||||
|
|
||||||
type errno = syscall.Errno
|
|
||||||
|
|
||||||
// Implemented in runtime/syscall_aix.go.
|
|
||||||
func rawSyscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err errno)
|
|
||||||
func syscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err errno)
|
|
||||||
|
|
||||||
func callgetsystemcfg(label int) (r1 uintptr, e1 errno) {
|
|
||||||
r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_getsystemcfg)), 1, uintptr(label), 0, 0, 0, 0, 0)
|
|
||||||
return
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user