This commit is contained in:
MXi4oyu 2019-05-07 09:50:05 +08:00
parent 53cce63f9e
commit bd25a1f6d0
1409 changed files with 162554 additions and 210504 deletions

View File

@ -1,3 +0,0 @@
This repository holds supplementary Go cryptography libraries.
To submit changes to this repository, see http://golang.org/doc/contribute.html.

View File

@ -128,11 +128,7 @@ func (c *Client) Discover(ctx context.Context) (Directory, error) {
return *c.dir, nil
}
dirURL := c.DirectoryURL
if dirURL == "" {
dirURL = LetsEncryptURL
}
res, err := c.get(ctx, dirURL, wantStatus(http.StatusOK))
res, err := c.get(ctx, c.directoryURL(), wantStatus(http.StatusOK))
if err != nil {
return Directory{}, err
}
@ -165,6 +161,13 @@ func (c *Client) Discover(ctx context.Context) (Directory, error) {
return *c.dir, nil
}
func (c *Client) directoryURL() string {
if c.DirectoryURL != "" {
return c.DirectoryURL
}
return LetsEncryptURL
}
// CreateCert requests a new certificate using the Certificate Signing Request csr encoded in DER format.
// The exp argument indicates the desired certificate validity duration. CA may issue a certificate
// with a different duration.
@ -323,6 +326,20 @@ func (c *Client) UpdateReg(ctx context.Context, a *Account) (*Account, error) {
// a valid authorization (Authorization.Status is StatusValid). If so, the caller
// need not fulfill any challenge and can proceed to requesting a certificate.
func (c *Client) Authorize(ctx context.Context, domain string) (*Authorization, error) {
return c.authorize(ctx, "dns", domain)
}
// AuthorizeIP is the same as Authorize but requests IP address authorization.
// Clients which successfully obtain such authorization may request to issue
// a certificate for IP addresses.
//
// See the ACME spec extension for more details about IP address identifiers:
// https://tools.ietf.org/html/draft-ietf-acme-ip.
func (c *Client) AuthorizeIP(ctx context.Context, ipaddr string) (*Authorization, error) {
return c.authorize(ctx, "ip", ipaddr)
}
func (c *Client) authorize(ctx context.Context, typ, val string) (*Authorization, error) {
if _, err := c.Discover(ctx); err != nil {
return nil, err
}
@ -336,7 +353,7 @@ func (c *Client) Authorize(ctx context.Context, domain string) (*Authorization,
Identifier authzID `json:"identifier"`
}{
Resource: "new-authz",
Identifier: authzID{Type: "dns", Value: domain},
Identifier: authzID{Type: typ, Value: val},
}
res, err := c.post(ctx, c.Key, c.dir.AuthzURL, req, wantStatus(http.StatusCreated))
if err != nil {
@ -697,12 +714,18 @@ func (c *Client) doReg(ctx context.Context, url string, typ string, acct *Accoun
}
// popNonce returns a nonce value previously stored with c.addNonce
// or fetches a fresh one from the given URL.
// or fetches a fresh one from a URL by issuing a HEAD request.
// It first tries c.directoryURL() and then the provided url if the former fails.
func (c *Client) popNonce(ctx context.Context, url string) (string, error) {
c.noncesMu.Lock()
defer c.noncesMu.Unlock()
if len(c.nonces) == 0 {
return c.fetchNonce(ctx, url)
dirURL := c.directoryURL()
v, err := c.fetchNonce(ctx, dirURL)
if err != nil && url != dirURL {
v, err = c.fetchNonce(ctx, url)
}
return v, err
}
var nonce string
for nonce = range c.nonces {

View File

@ -75,6 +75,7 @@ func TestDiscover(t *testing.T) {
)
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.Header().Set("Replay-Nonce", "testnonce")
fmt.Fprintf(w, `{
"new-reg": %q,
"new-authz": %q,
@ -100,6 +101,9 @@ func TestDiscover(t *testing.T) {
if dir.RevokeURL != revoke {
t.Errorf("dir.RevokeURL = %q; want %q", dir.RevokeURL, revoke)
}
if _, exist := c.nonces["testnonce"]; !exist {
t.Errorf("c.nonces = %q; want 'testnonce' in the map", c.nonces)
}
}
func TestRegister(t *testing.T) {
@ -147,7 +151,11 @@ func TestRegister(t *testing.T) {
return false
}
c := Client{Key: testKeyEC, dir: &Directory{RegURL: ts.URL}}
c := Client{
Key: testKeyEC,
DirectoryURL: ts.URL,
dir: &Directory{RegURL: ts.URL},
}
a := &Account{Contact: contacts}
var err error
if a, err = c.Register(context.Background(), a, prompt); err != nil {
@ -288,106 +296,131 @@ func TestGetReg(t *testing.T) {
}
func TestAuthorize(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method == "HEAD" {
w.Header().Set("Replay-Nonce", "test-nonce")
return
}
if r.Method != "POST" {
t.Errorf("r.Method = %q; want POST", r.Method)
}
var j struct {
Resource string
Identifier struct {
Type string
Value string
}
}
decodeJWSRequest(t, &j, r)
// Test request
if j.Resource != "new-authz" {
t.Errorf("j.Resource = %q; want new-authz", j.Resource)
}
if j.Identifier.Type != "dns" {
t.Errorf("j.Identifier.Type = %q; want dns", j.Identifier.Type)
}
if j.Identifier.Value != "example.com" {
t.Errorf("j.Identifier.Value = %q; want example.com", j.Identifier.Value)
}
w.Header().Set("Location", "https://ca.tld/acme/auth/1")
w.WriteHeader(http.StatusCreated)
fmt.Fprintf(w, `{
"identifier": {"type":"dns","value":"example.com"},
"status":"pending",
"challenges":[
{
"type":"http-01",
"status":"pending",
"uri":"https://ca.tld/acme/challenge/publickey/id1",
"token":"token1"
},
{
"type":"tls-sni-01",
"status":"pending",
"uri":"https://ca.tld/acme/challenge/publickey/id2",
"token":"token2"
tt := []struct{ typ, value string }{
{"dns", "example.com"},
{"ip", "1.2.3.4"},
}
for _, test := range tt {
t.Run(test.typ, func(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method == "HEAD" {
w.Header().Set("Replay-Nonce", "test-nonce")
return
}
if r.Method != "POST" {
t.Errorf("r.Method = %q; want POST", r.Method)
}
],
"combinations":[[0],[1]]}`)
}))
defer ts.Close()
cl := Client{Key: testKeyEC, dir: &Directory{AuthzURL: ts.URL}}
auth, err := cl.Authorize(context.Background(), "example.com")
if err != nil {
t.Fatal(err)
}
var j struct {
Resource string
Identifier struct {
Type string
Value string
}
}
decodeJWSRequest(t, &j, r)
if auth.URI != "https://ca.tld/acme/auth/1" {
t.Errorf("URI = %q; want https://ca.tld/acme/auth/1", auth.URI)
}
if auth.Status != "pending" {
t.Errorf("Status = %q; want pending", auth.Status)
}
if auth.Identifier.Type != "dns" {
t.Errorf("Identifier.Type = %q; want dns", auth.Identifier.Type)
}
if auth.Identifier.Value != "example.com" {
t.Errorf("Identifier.Value = %q; want example.com", auth.Identifier.Value)
}
// Test request
if j.Resource != "new-authz" {
t.Errorf("j.Resource = %q; want new-authz", j.Resource)
}
if j.Identifier.Type != test.typ {
t.Errorf("j.Identifier.Type = %q; want %q", j.Identifier.Type, test.typ)
}
if j.Identifier.Value != test.value {
t.Errorf("j.Identifier.Value = %q; want %q", j.Identifier.Value, test.value)
}
if n := len(auth.Challenges); n != 2 {
t.Fatalf("len(auth.Challenges) = %d; want 2", n)
}
w.Header().Set("Location", "https://ca.tld/acme/auth/1")
w.WriteHeader(http.StatusCreated)
fmt.Fprintf(w, `{
"identifier": {"type":%q,"value":%q},
"status":"pending",
"challenges":[
{
"type":"http-01",
"status":"pending",
"uri":"https://ca.tld/acme/challenge/publickey/id1",
"token":"token1"
},
{
"type":"tls-sni-01",
"status":"pending",
"uri":"https://ca.tld/acme/challenge/publickey/id2",
"token":"token2"
}
],
"combinations":[[0],[1]]
}`, test.typ, test.value)
}))
defer ts.Close()
c := auth.Challenges[0]
if c.Type != "http-01" {
t.Errorf("c.Type = %q; want http-01", c.Type)
}
if c.URI != "https://ca.tld/acme/challenge/publickey/id1" {
t.Errorf("c.URI = %q; want https://ca.tld/acme/challenge/publickey/id1", c.URI)
}
if c.Token != "token1" {
t.Errorf("c.Token = %q; want token1", c.Token)
}
var (
auth *Authorization
err error
)
cl := Client{
Key: testKeyEC,
DirectoryURL: ts.URL,
dir: &Directory{AuthzURL: ts.URL},
}
switch test.typ {
case "dns":
auth, err = cl.Authorize(context.Background(), test.value)
case "ip":
auth, err = cl.AuthorizeIP(context.Background(), test.value)
default:
t.Fatalf("unknown identifier type: %q", test.typ)
}
if err != nil {
t.Fatal(err)
}
c = auth.Challenges[1]
if c.Type != "tls-sni-01" {
t.Errorf("c.Type = %q; want tls-sni-01", c.Type)
}
if c.URI != "https://ca.tld/acme/challenge/publickey/id2" {
t.Errorf("c.URI = %q; want https://ca.tld/acme/challenge/publickey/id2", c.URI)
}
if c.Token != "token2" {
t.Errorf("c.Token = %q; want token2", c.Token)
}
if auth.URI != "https://ca.tld/acme/auth/1" {
t.Errorf("URI = %q; want https://ca.tld/acme/auth/1", auth.URI)
}
if auth.Status != "pending" {
t.Errorf("Status = %q; want pending", auth.Status)
}
if auth.Identifier.Type != test.typ {
t.Errorf("Identifier.Type = %q; want %q", auth.Identifier.Type, test.typ)
}
if auth.Identifier.Value != test.value {
t.Errorf("Identifier.Value = %q; want %q", auth.Identifier.Value, test.value)
}
combs := [][]int{{0}, {1}}
if !reflect.DeepEqual(auth.Combinations, combs) {
t.Errorf("auth.Combinations: %+v\nwant: %+v\n", auth.Combinations, combs)
if n := len(auth.Challenges); n != 2 {
t.Fatalf("len(auth.Challenges) = %d; want 2", n)
}
c := auth.Challenges[0]
if c.Type != "http-01" {
t.Errorf("c.Type = %q; want http-01", c.Type)
}
if c.URI != "https://ca.tld/acme/challenge/publickey/id1" {
t.Errorf("c.URI = %q; want https://ca.tld/acme/challenge/publickey/id1", c.URI)
}
if c.Token != "token1" {
t.Errorf("c.Token = %q; want token1", c.Token)
}
c = auth.Challenges[1]
if c.Type != "tls-sni-01" {
t.Errorf("c.Type = %q; want tls-sni-01", c.Type)
}
if c.URI != "https://ca.tld/acme/challenge/publickey/id2" {
t.Errorf("c.URI = %q; want https://ca.tld/acme/challenge/publickey/id2", c.URI)
}
if c.Token != "token2" {
t.Errorf("c.Token = %q; want token2", c.Token)
}
combs := [][]int{{0}, {1}}
if !reflect.DeepEqual(auth.Combinations, combs) {
t.Errorf("auth.Combinations: %+v\nwant: %+v\n", auth.Combinations, combs)
}
})
}
}
@ -401,7 +434,11 @@ func TestAuthorizeValid(t *testing.T) {
w.Write([]byte(`{"status":"valid"}`))
}))
defer ts.Close()
client := Client{Key: testKey, dir: &Directory{AuthzURL: ts.URL}}
client := Client{
Key: testKey,
DirectoryURL: ts.URL,
dir: &Directory{AuthzURL: ts.URL},
}
_, err := client.Authorize(context.Background(), "example.com")
if err != nil {
t.Errorf("err = %v", err)
@ -1016,6 +1053,53 @@ func TestNonce_fetchError(t *testing.T) {
}
}
func TestNonce_popWhenEmpty(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != "HEAD" {
t.Errorf("r.Method = %q; want HEAD", r.Method)
}
switch r.URL.Path {
case "/dir-with-nonce":
w.Header().Set("Replay-Nonce", "dirnonce")
case "/new-nonce":
w.Header().Set("Replay-Nonce", "newnonce")
case "/dir-no-nonce", "/empty":
// No nonce in the header.
default:
t.Errorf("Unknown URL: %s", r.URL)
}
}))
defer ts.Close()
ctx := context.Background()
tt := []struct {
dirURL, popURL, nonce string
wantOK bool
}{
{ts.URL + "/dir-with-nonce", ts.URL + "/new-nonce", "dirnonce", true},
{ts.URL + "/dir-no-nonce", ts.URL + "/new-nonce", "newnonce", true},
{ts.URL + "/dir-no-nonce", ts.URL + "/empty", "", false},
}
for _, test := range tt {
t.Run(fmt.Sprintf("nonce:%s wantOK:%v", test.nonce, test.wantOK), func(t *testing.T) {
c := Client{DirectoryURL: test.dirURL}
v, err := c.popNonce(ctx, test.popURL)
if !test.wantOK {
if err == nil {
t.Fatalf("c.popNonce(%q) returned nil error", test.popURL)
}
return
}
if err != nil {
t.Fatalf("c.popNonce(%q): %v", test.popURL, err)
}
if v != test.nonce {
t.Errorf("c.popNonce(%q) = %q; want %q", test.popURL, v, test.nonce)
}
})
}
}
func TestNonce_postJWS(t *testing.T) {
var count int
seen := make(map[string]bool)
@ -1049,7 +1133,11 @@ func TestNonce_postJWS(t *testing.T) {
}))
defer ts.Close()
client := Client{Key: testKey, dir: &Directory{AuthzURL: ts.URL}}
client := Client{
Key: testKey,
DirectoryURL: ts.URL, // nonces are fetched from here first
dir: &Directory{AuthzURL: ts.URL},
}
if _, err := client.Authorize(context.Background(), "example.com"); err != nil {
t.Errorf("client.Authorize 1: %v", err)
}

View File

@ -32,6 +32,7 @@ import (
"time"
"golang.org/x/crypto/acme"
"golang.org/x/net/idna"
)
// createCertRetryAfter is how much time to wait before removing a failed state
@ -62,10 +63,16 @@ type HostPolicy func(ctx context.Context, host string) error
// HostWhitelist returns a policy where only the specified host names are allowed.
// Only exact matches are currently supported. Subdomains, regexp or wildcard
// will not match.
//
// Note that all hosts will be converted to Punycode via idna.Lookup.ToASCII so that
// Manager.GetCertificate can handle the Unicode IDN and mixedcase hosts correctly.
// Invalid hosts will be silently ignored.
func HostWhitelist(hosts ...string) HostPolicy {
whitelist := make(map[string]bool, len(hosts))
for _, h := range hosts {
whitelist[h] = true
if h, err := idna.Lookup.ToASCII(h); err == nil {
whitelist[h] = true
}
}
return func(_ context.Context, host string) error {
if !whitelist[host] {
@ -243,7 +250,17 @@ func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate,
if !strings.Contains(strings.Trim(name, "."), ".") {
return nil, errors.New("acme/autocert: server name component count invalid")
}
if strings.ContainsAny(name, `+/\`) {
// Note that this conversion is necessary because some server names in the handshakes
// started by some clients (such as cURL) are not converted to Punycode, which will
// prevent us from obtaining certificates for them. In addition, we should also treat
// example.com and EXAMPLE.COM as equivalent and return the same certificate for them.
// Fortunately, this conversion also helped us deal with this kind of mixedcase problems.
//
// Due to the "σςΣ" problem (see https://unicode.org/faq/idn.html#22), we can't use
// idna.Punycode.ToASCII (or just idna.ToASCII) here.
name, err := idna.Lookup.ToASCII(name)
if err != nil {
return nil, errors.New("acme/autocert: server name contains invalid character")
}

View File

@ -209,6 +209,28 @@ func TestGetCertificate_trailingDot(t *testing.T) {
testGetCertificate(t, man, "example.org", hello)
}
func TestGetCertificate_unicodeIDN(t *testing.T) {
man := &Manager{Prompt: AcceptTOS}
defer man.stopRenew()
hello := clientHelloInfo("σσσ.com", true)
testGetCertificate(t, man, "xn--4xaaa.com", hello)
hello = clientHelloInfo("σςΣ.com", true)
testGetCertificate(t, man, "xn--4xaaa.com", hello)
}
func TestGetCertificate_mixedcase(t *testing.T) {
man := &Manager{Prompt: AcceptTOS}
defer man.stopRenew()
hello := clientHelloInfo("example.org", true)
testGetCertificate(t, man, "example.org", hello)
hello = clientHelloInfo("EXAMPLE.ORG", true)
testGetCertificate(t, man, "example.org", hello)
}
func TestGetCertificate_ForceRSA(t *testing.T) {
man := &Manager{
Prompt: AcceptTOS,
@ -906,13 +928,14 @@ func TestCache(t *testing.T) {
}
func TestHostWhitelist(t *testing.T) {
policy := HostWhitelist("example.com", "example.org", "*.example.net")
policy := HostWhitelist("example.com", "EXAMPLE.ORG", "*.example.net", "σςΣ.com")
tt := []struct {
host string
allow bool
}{
{"example.com", true},
{"example.org", true},
{"xn--4xaaa.com", true},
{"one.example.com", false},
{"two.example.org", false},
{"three.example.net", false},

View File

@ -106,7 +106,11 @@ func TestPostWithRetries(t *testing.T) {
}))
defer ts.Close()
client := &Client{Key: testKey, dir: &Directory{AuthzURL: ts.URL}}
client := &Client{
Key: testKey,
DirectoryURL: ts.URL,
dir: &Directory{AuthzURL: ts.URL},
}
// This call will fail with badNonce, causing a retry
if _, err := client.Authorize(context.Background(), "example.com"); err != nil {
t.Errorf("client.Authorize 1: %v", err)

View File

@ -75,19 +75,19 @@ func Sum256(data []byte) [Size256]byte {
}
// New512 returns a new hash.Hash computing the BLAKE2b-512 checksum. A non-nil
// key turns the hash into a MAC. The key must between zero and 64 bytes long.
// key turns the hash into a MAC. The key must be between zero and 64 bytes long.
func New512(key []byte) (hash.Hash, error) { return newDigest(Size, key) }
// New384 returns a new hash.Hash computing the BLAKE2b-384 checksum. A non-nil
// key turns the hash into a MAC. The key must between zero and 64 bytes long.
// key turns the hash into a MAC. The key must be between zero and 64 bytes long.
func New384(key []byte) (hash.Hash, error) { return newDigest(Size384, key) }
// New256 returns a new hash.Hash computing the BLAKE2b-256 checksum. A non-nil
// key turns the hash into a MAC. The key must between zero and 64 bytes long.
// key turns the hash into a MAC. The key must be between zero and 64 bytes long.
func New256(key []byte) (hash.Hash, error) { return newDigest(Size256, key) }
// New returns a new hash.Hash computing the BLAKE2b checksum with a custom length.
// A non-nil key turns the hash into a MAC. The key must between zero and 64 bytes long.
// A non-nil key turns the hash into a MAC. The key must be between zero and 64 bytes long.
// The hash size can be a value between 1 and 64 but it is highly recommended to use
// values equal or greater than:
// - 32 if BLAKE2b is used as a hash function (The key is zero bytes long).

View File

@ -4,7 +4,10 @@
package blake2b
import "encoding/binary"
import (
"encoding/binary"
"math/bits"
)
// the precomputed values for BLAKE2b
// there are 12 16-byte arrays - one for each round
@ -51,118 +54,118 @@ func hashBlocksGeneric(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) {
v0 += m[s[0]]
v0 += v4
v12 ^= v0
v12 = v12<<(64-32) | v12>>32
v12 = bits.RotateLeft64(v12, -32)
v8 += v12
v4 ^= v8
v4 = v4<<(64-24) | v4>>24
v4 = bits.RotateLeft64(v4, -24)
v1 += m[s[1]]
v1 += v5
v13 ^= v1
v13 = v13<<(64-32) | v13>>32
v13 = bits.RotateLeft64(v13, -32)
v9 += v13
v5 ^= v9
v5 = v5<<(64-24) | v5>>24
v5 = bits.RotateLeft64(v5, -24)
v2 += m[s[2]]
v2 += v6
v14 ^= v2
v14 = v14<<(64-32) | v14>>32
v14 = bits.RotateLeft64(v14, -32)
v10 += v14
v6 ^= v10
v6 = v6<<(64-24) | v6>>24
v6 = bits.RotateLeft64(v6, -24)
v3 += m[s[3]]
v3 += v7
v15 ^= v3
v15 = v15<<(64-32) | v15>>32
v15 = bits.RotateLeft64(v15, -32)
v11 += v15
v7 ^= v11
v7 = v7<<(64-24) | v7>>24
v7 = bits.RotateLeft64(v7, -24)
v0 += m[s[4]]
v0 += v4
v12 ^= v0
v12 = v12<<(64-16) | v12>>16
v12 = bits.RotateLeft64(v12, -16)
v8 += v12
v4 ^= v8
v4 = v4<<(64-63) | v4>>63
v4 = bits.RotateLeft64(v4, -63)
v1 += m[s[5]]
v1 += v5
v13 ^= v1
v13 = v13<<(64-16) | v13>>16
v13 = bits.RotateLeft64(v13, -16)
v9 += v13
v5 ^= v9
v5 = v5<<(64-63) | v5>>63
v5 = bits.RotateLeft64(v5, -63)
v2 += m[s[6]]
v2 += v6
v14 ^= v2
v14 = v14<<(64-16) | v14>>16
v14 = bits.RotateLeft64(v14, -16)
v10 += v14
v6 ^= v10
v6 = v6<<(64-63) | v6>>63
v6 = bits.RotateLeft64(v6, -63)
v3 += m[s[7]]
v3 += v7
v15 ^= v3
v15 = v15<<(64-16) | v15>>16
v15 = bits.RotateLeft64(v15, -16)
v11 += v15
v7 ^= v11
v7 = v7<<(64-63) | v7>>63
v7 = bits.RotateLeft64(v7, -63)
v0 += m[s[8]]
v0 += v5
v15 ^= v0
v15 = v15<<(64-32) | v15>>32
v15 = bits.RotateLeft64(v15, -32)
v10 += v15
v5 ^= v10
v5 = v5<<(64-24) | v5>>24
v5 = bits.RotateLeft64(v5, -24)
v1 += m[s[9]]
v1 += v6
v12 ^= v1
v12 = v12<<(64-32) | v12>>32
v12 = bits.RotateLeft64(v12, -32)
v11 += v12
v6 ^= v11
v6 = v6<<(64-24) | v6>>24
v6 = bits.RotateLeft64(v6, -24)
v2 += m[s[10]]
v2 += v7
v13 ^= v2
v13 = v13<<(64-32) | v13>>32
v13 = bits.RotateLeft64(v13, -32)
v8 += v13
v7 ^= v8
v7 = v7<<(64-24) | v7>>24
v7 = bits.RotateLeft64(v7, -24)
v3 += m[s[11]]
v3 += v4
v14 ^= v3
v14 = v14<<(64-32) | v14>>32
v14 = bits.RotateLeft64(v14, -32)
v9 += v14
v4 ^= v9
v4 = v4<<(64-24) | v4>>24
v4 = bits.RotateLeft64(v4, -24)
v0 += m[s[12]]
v0 += v5
v15 ^= v0
v15 = v15<<(64-16) | v15>>16
v15 = bits.RotateLeft64(v15, -16)
v10 += v15
v5 ^= v10
v5 = v5<<(64-63) | v5>>63
v5 = bits.RotateLeft64(v5, -63)
v1 += m[s[13]]
v1 += v6
v12 ^= v1
v12 = v12<<(64-16) | v12>>16
v12 = bits.RotateLeft64(v12, -16)
v11 += v12
v6 ^= v11
v6 = v6<<(64-63) | v6>>63
v6 = bits.RotateLeft64(v6, -63)
v2 += m[s[14]]
v2 += v7
v13 ^= v2
v13 = v13<<(64-16) | v13>>16
v13 = bits.RotateLeft64(v13, -16)
v8 += v13
v7 ^= v8
v7 = v7<<(64-63) | v7>>63
v7 = bits.RotateLeft64(v7, -63)
v3 += m[s[15]]
v3 += v4
v14 ^= v3
v14 = v14<<(64-16) | v14>>16
v14 = bits.RotateLeft64(v14, -16)
v9 += v14
v4 ^= v9
v4 = v4<<(64-63) | v4>>63
v4 = bits.RotateLeft64(v4, -63)
}

View File

@ -4,6 +4,10 @@
package blake2s
import (
"math/bits"
)
// the precomputed values for BLAKE2s
// there are 10 16-byte arrays - one for each round
// the entries are calculated from the sigma constants.
@ -47,118 +51,118 @@ func hashBlocksGeneric(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte) {
v0 += m[s[0]]
v0 += v4
v12 ^= v0
v12 = v12<<(32-16) | v12>>16
v12 = bits.RotateLeft32(v12, -16)
v8 += v12
v4 ^= v8
v4 = v4<<(32-12) | v4>>12
v4 = bits.RotateLeft32(v4, -12)
v1 += m[s[1]]
v1 += v5
v13 ^= v1
v13 = v13<<(32-16) | v13>>16
v13 = bits.RotateLeft32(v13, -16)
v9 += v13
v5 ^= v9
v5 = v5<<(32-12) | v5>>12
v5 = bits.RotateLeft32(v5, -12)
v2 += m[s[2]]
v2 += v6
v14 ^= v2
v14 = v14<<(32-16) | v14>>16
v14 = bits.RotateLeft32(v14, -16)
v10 += v14
v6 ^= v10
v6 = v6<<(32-12) | v6>>12
v6 = bits.RotateLeft32(v6, -12)
v3 += m[s[3]]
v3 += v7
v15 ^= v3
v15 = v15<<(32-16) | v15>>16
v15 = bits.RotateLeft32(v15, -16)
v11 += v15
v7 ^= v11
v7 = v7<<(32-12) | v7>>12
v7 = bits.RotateLeft32(v7, -12)
v0 += m[s[4]]
v0 += v4
v12 ^= v0
v12 = v12<<(32-8) | v12>>8
v12 = bits.RotateLeft32(v12, -8)
v8 += v12
v4 ^= v8
v4 = v4<<(32-7) | v4>>7
v4 = bits.RotateLeft32(v4, -7)
v1 += m[s[5]]
v1 += v5
v13 ^= v1
v13 = v13<<(32-8) | v13>>8
v13 = bits.RotateLeft32(v13, -8)
v9 += v13
v5 ^= v9
v5 = v5<<(32-7) | v5>>7
v5 = bits.RotateLeft32(v5, -7)
v2 += m[s[6]]
v2 += v6
v14 ^= v2
v14 = v14<<(32-8) | v14>>8
v14 = bits.RotateLeft32(v14, -8)
v10 += v14
v6 ^= v10
v6 = v6<<(32-7) | v6>>7
v6 = bits.RotateLeft32(v6, -7)
v3 += m[s[7]]
v3 += v7
v15 ^= v3
v15 = v15<<(32-8) | v15>>8
v15 = bits.RotateLeft32(v15, -8)
v11 += v15
v7 ^= v11
v7 = v7<<(32-7) | v7>>7
v7 = bits.RotateLeft32(v7, -7)
v0 += m[s[8]]
v0 += v5
v15 ^= v0
v15 = v15<<(32-16) | v15>>16
v15 = bits.RotateLeft32(v15, -16)
v10 += v15
v5 ^= v10
v5 = v5<<(32-12) | v5>>12
v5 = bits.RotateLeft32(v5, -12)
v1 += m[s[9]]
v1 += v6
v12 ^= v1
v12 = v12<<(32-16) | v12>>16
v12 = bits.RotateLeft32(v12, -16)
v11 += v12
v6 ^= v11
v6 = v6<<(32-12) | v6>>12
v6 = bits.RotateLeft32(v6, -12)
v2 += m[s[10]]
v2 += v7
v13 ^= v2
v13 = v13<<(32-16) | v13>>16
v13 = bits.RotateLeft32(v13, -16)
v8 += v13
v7 ^= v8
v7 = v7<<(32-12) | v7>>12
v7 = bits.RotateLeft32(v7, -12)
v3 += m[s[11]]
v3 += v4
v14 ^= v3
v14 = v14<<(32-16) | v14>>16
v14 = bits.RotateLeft32(v14, -16)
v9 += v14
v4 ^= v9
v4 = v4<<(32-12) | v4>>12
v4 = bits.RotateLeft32(v4, -12)
v0 += m[s[12]]
v0 += v5
v15 ^= v0
v15 = v15<<(32-8) | v15>>8
v15 = bits.RotateLeft32(v15, -8)
v10 += v15
v5 ^= v10
v5 = v5<<(32-7) | v5>>7
v5 = bits.RotateLeft32(v5, -7)
v1 += m[s[13]]
v1 += v6
v12 ^= v1
v12 = v12<<(32-8) | v12>>8
v12 = bits.RotateLeft32(v12, -8)
v11 += v12
v6 ^= v11
v6 = v6<<(32-7) | v6>>7
v6 = bits.RotateLeft32(v6, -7)
v2 += m[s[14]]
v2 += v7
v13 ^= v2
v13 = v13<<(32-8) | v13>>8
v13 = bits.RotateLeft32(v13, -8)
v8 += v13
v7 ^= v8
v7 = v7<<(32-7) | v7>>7
v7 = bits.RotateLeft32(v7, -7)
v3 += m[s[15]]
v3 += v4
v14 ^= v3
v14 = v14<<(32-8) | v14>>8
v14 = bits.RotateLeft32(v14, -8)
v9 += v14
v4 ^= v9
v4 = v4<<(32-7) | v4>>7
v4 = bits.RotateLeft32(v4, -7)
}
h[0] ^= v0 ^ v8

View File

@ -3,6 +3,14 @@
// license that can be found in the LICENSE file.
// Package blowfish implements Bruce Schneier's Blowfish encryption algorithm.
//
// Blowfish is a legacy cipher and its short block size makes it vulnerable to
// birthday bound attacks (see https://sweet32.info). It should only be used
// where compatibility with legacy systems, not security, is the goal.
//
// Deprecated: any new system should use AES (from crypto/aes, if necessary in
// an AEAD mode like crypto/cipher.NewGCM) or XChaCha20-Poly1305 (from
// golang.org/x/crypto/chacha20poly1305).
package blowfish // import "golang.org/x/crypto/blowfish"
// The code is a port of Bruce Schneier's C implementation.

View File

@ -15,9 +15,14 @@
// http://cryptojedi.org/papers/dclxvi-20100714.pdf. Its output is compatible
// with the implementation described in that paper.
//
// (This package previously claimed to operate at a 128-bit security level.
// This package previously claimed to operate at a 128-bit security level.
// However, recent improvements in attacks mean that is no longer true. See
// https://moderncrypto.org/mail-archive/curves/2016/000740.html.)
// https://moderncrypto.org/mail-archive/curves/2016/000740.html.
//
// Deprecated: due to its weakened security, new systems should not rely on this
// elliptic curve. This package is frozen, and not implemented in constant time.
// There is a more complete implementation at github.com/cloudflare/bn256, but
// note that it suffers from the same security issues of the underlying curve.
package bn256 // import "golang.org/x/crypto/bn256"
import (
@ -26,9 +31,6 @@ import (
"math/big"
)
// BUG(agl): this implementation is not constant time.
// TODO(agl): keep GF(p²) elements in Mongomery form.
// G1 is an abstract cyclic group. The zero value is suitable for use as the
// output of an operation, but cannot be used as an input.
type G1 struct {
@ -54,6 +56,9 @@ func RandomG1(r io.Reader) (*big.Int, *G1, error) {
}
func (e *G1) String() string {
if e.p == nil {
return "bn256.G1" + newCurvePoint(nil).String()
}
return "bn256.G1" + e.p.String()
}
@ -77,7 +82,8 @@ func (e *G1) ScalarMult(a *G1, k *big.Int) *G1 {
}
// Add sets e to a+b and then returns e.
// BUG(agl): this function is not complete: a==b fails.
//
// Warning: this function is not complete, it fails for a equal to b.
func (e *G1) Add(a, b *G1) *G1 {
if e.p == nil {
e.p = newCurvePoint(nil)
@ -175,6 +181,9 @@ func RandomG2(r io.Reader) (*big.Int, *G2, error) {
}
func (e *G2) String() string {
if e.p == nil {
return "bn256.G2" + newTwistPoint(nil).String()
}
return "bn256.G2" + e.p.String()
}
@ -198,7 +207,8 @@ func (e *G2) ScalarMult(a *G2, k *big.Int) *G2 {
}
// Add sets e to a+b and then returns e.
// BUG(agl): this function is not complete: a==b fails.
//
// Warning: this function is not complete, it fails for a equal to b.
func (e *G2) Add(a, b *G2) *G2 {
if e.p == nil {
e.p = newTwistPoint(nil)
@ -277,8 +287,11 @@ type GT struct {
p *gfP12
}
func (g *GT) String() string {
return "bn256.GT" + g.p.String()
func (e *GT) String() string {
if e.p == nil {
return "bn256.GT" + newGFp12(nil).String()
}
return "bn256.GT" + e.p.String()
}
// ScalarMult sets e to a*k and then returns e.

View File

@ -125,8 +125,8 @@ func (e *gfP12) Mul(a, b *gfP12, pool *bnPool) *gfP12 {
}
func (e *gfP12) MulScalar(a *gfP12, b *gfP6, pool *bnPool) *gfP12 {
e.x.Mul(e.x, b, pool)
e.y.Mul(e.y, b, pool)
e.x.Mul(a.x, b, pool)
e.y.Mul(a.y, b, pool)
return e
}

View File

@ -2,8 +2,15 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package cast5 implements CAST5, as defined in RFC 2144. CAST5 is a common
// OpenPGP cipher.
// Package cast5 implements CAST5, as defined in RFC 2144.
//
// CAST5 is a legacy cipher and its short block size makes it vulnerable to
// birthday bound attacks (see https://sweet32.info). It should only be used
// where compatibility with legacy systems, not security, is the goal.
//
// Deprecated: any new system should use AES (from crypto/aes, if necessary in
// an AEAD mode like crypto/cipher.NewGCM) or XChaCha20-Poly1305 (from
// golang.org/x/crypto/chacha20poly1305).
package cast5 // import "golang.org/x/crypto/cast5"
import "errors"

View File

@ -200,7 +200,7 @@ GLOBL ·andMask<>(SB), (NOPTR+RODATA), $240
#define polyMulStage1 MOVQ (0*8)(BP), AX; MOVQ AX, t2; MULQ acc0; MOVQ AX, t0; MOVQ DX, t1; MOVQ (0*8)(BP), AX; MULQ acc1; IMULQ acc2, t2; ADDQ AX, t1; ADCQ DX, t2
#define polyMulStage2 MOVQ (1*8)(BP), AX; MOVQ AX, t3; MULQ acc0; ADDQ AX, t1; ADCQ $0, DX; MOVQ DX, acc0; MOVQ (1*8)(BP), AX; MULQ acc1; ADDQ AX, t2; ADCQ $0, DX
#define polyMulStage3 IMULQ acc2, t3; ADDQ acc0, t2; ADCQ DX, t3
#define polyMulReduceStage MOVQ t0, acc0; MOVQ t1, acc1; MOVQ t2, acc2; ANDQ $3, acc2; MOVQ t2, t0; ANDQ $-4, t0; MOVQ t3, t1; SHRQ $2, t2:t3; SHRQ $2, t3; ADDQ t0, acc0; ADCQ t1, acc1; ADCQ $0, acc2; ADDQ t2, acc0; ADCQ t3, acc1; ADCQ $0, acc2
#define polyMulReduceStage MOVQ t0, acc0; MOVQ t1, acc1; MOVQ t2, acc2; ANDQ $3, acc2; MOVQ t2, t0; ANDQ $-4, t0; MOVQ t3, t1; SHRQ $2, t3, t2; SHRQ $2, t3; ADDQ t0, acc0; ADCQ t1, acc1; ADCQ $0, acc2; ADDQ t2, acc0; ADCQ t3, acc1; ADCQ $0, acc2
#define polyMulStage1_AVX2 MOVQ (0*8)(BP), DX; MOVQ DX, t2; MULXQ acc0, t0, t1; IMULQ acc2, t2; MULXQ acc1, AX, DX; ADDQ AX, t1; ADCQ DX, t2
#define polyMulStage2_AVX2 MOVQ (1*8)(BP), DX; MULXQ acc0, acc0, AX; ADDQ acc0, t1; MULXQ acc1, acc1, t3; ADCQ acc1, t2; ADCQ $0, t3
@ -248,7 +248,7 @@ hashADTail:
ADDQ itr2, adp
hashADTailLoop:
SHLQ $8, t1:t0
SHLQ $8, t0, t1
SHLQ $8, t0
MOVB -1(adp), t2
XORQ t2, t0

File diff suppressed because one or more lines are too long

View File

@ -1,199 +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 "encoding/binary"
const rounds = 20
// core applies the ChaCha20 core function to 16-byte input in, 32-byte key k,
// and 16-byte constant c, and puts the result into 64-byte array out.
func core(out *[64]byte, in *[16]byte, k *[32]byte) {
j0 := uint32(0x61707865)
j1 := uint32(0x3320646e)
j2 := uint32(0x79622d32)
j3 := uint32(0x6b206574)
j4 := binary.LittleEndian.Uint32(k[0:4])
j5 := binary.LittleEndian.Uint32(k[4:8])
j6 := binary.LittleEndian.Uint32(k[8:12])
j7 := binary.LittleEndian.Uint32(k[12:16])
j8 := binary.LittleEndian.Uint32(k[16:20])
j9 := binary.LittleEndian.Uint32(k[20:24])
j10 := binary.LittleEndian.Uint32(k[24:28])
j11 := binary.LittleEndian.Uint32(k[28:32])
j12 := binary.LittleEndian.Uint32(in[0:4])
j13 := binary.LittleEndian.Uint32(in[4:8])
j14 := binary.LittleEndian.Uint32(in[8:12])
j15 := binary.LittleEndian.Uint32(in[12:16])
x0, x1, x2, x3, x4, x5, x6, x7 := j0, j1, j2, j3, j4, j5, j6, j7
x8, x9, x10, x11, x12, x13, x14, x15 := j8, j9, j10, j11, j12, j13, j14, j15
for i := 0; i < rounds; i += 2 {
x0 += x4
x12 ^= x0
x12 = (x12 << 16) | (x12 >> (16))
x8 += x12
x4 ^= x8
x4 = (x4 << 12) | (x4 >> (20))
x0 += x4
x12 ^= x0
x12 = (x12 << 8) | (x12 >> (24))
x8 += x12
x4 ^= x8
x4 = (x4 << 7) | (x4 >> (25))
x1 += x5
x13 ^= x1
x13 = (x13 << 16) | (x13 >> 16)
x9 += x13
x5 ^= x9
x5 = (x5 << 12) | (x5 >> 20)
x1 += x5
x13 ^= x1
x13 = (x13 << 8) | (x13 >> 24)
x9 += x13
x5 ^= x9
x5 = (x5 << 7) | (x5 >> 25)
x2 += x6
x14 ^= x2
x14 = (x14 << 16) | (x14 >> 16)
x10 += x14
x6 ^= x10
x6 = (x6 << 12) | (x6 >> 20)
x2 += x6
x14 ^= x2
x14 = (x14 << 8) | (x14 >> 24)
x10 += x14
x6 ^= x10
x6 = (x6 << 7) | (x6 >> 25)
x3 += x7
x15 ^= x3
x15 = (x15 << 16) | (x15 >> 16)
x11 += x15
x7 ^= x11
x7 = (x7 << 12) | (x7 >> 20)
x3 += x7
x15 ^= x3
x15 = (x15 << 8) | (x15 >> 24)
x11 += x15
x7 ^= x11
x7 = (x7 << 7) | (x7 >> 25)
x0 += x5
x15 ^= x0
x15 = (x15 << 16) | (x15 >> 16)
x10 += x15
x5 ^= x10
x5 = (x5 << 12) | (x5 >> 20)
x0 += x5
x15 ^= x0
x15 = (x15 << 8) | (x15 >> 24)
x10 += x15
x5 ^= x10
x5 = (x5 << 7) | (x5 >> 25)
x1 += x6
x12 ^= x1
x12 = (x12 << 16) | (x12 >> 16)
x11 += x12
x6 ^= x11
x6 = (x6 << 12) | (x6 >> 20)
x1 += x6
x12 ^= x1
x12 = (x12 << 8) | (x12 >> 24)
x11 += x12
x6 ^= x11
x6 = (x6 << 7) | (x6 >> 25)
x2 += x7
x13 ^= x2
x13 = (x13 << 16) | (x13 >> 16)
x8 += x13
x7 ^= x8
x7 = (x7 << 12) | (x7 >> 20)
x2 += x7
x13 ^= x2
x13 = (x13 << 8) | (x13 >> 24)
x8 += x13
x7 ^= x8
x7 = (x7 << 7) | (x7 >> 25)
x3 += x4
x14 ^= x3
x14 = (x14 << 16) | (x14 >> 16)
x9 += x14
x4 ^= x9
x4 = (x4 << 12) | (x4 >> 20)
x3 += x4
x14 ^= x3
x14 = (x14 << 8) | (x14 >> 24)
x9 += x14
x4 ^= x9
x4 = (x4 << 7) | (x4 >> 25)
}
x0 += j0
x1 += j1
x2 += j2
x3 += j3
x4 += j4
x5 += j5
x6 += j6
x7 += j7
x8 += j8
x9 += j9
x10 += j10
x11 += j11
x12 += j12
x13 += j13
x14 += j14
x15 += j15
binary.LittleEndian.PutUint32(out[0:4], x0)
binary.LittleEndian.PutUint32(out[4:8], x1)
binary.LittleEndian.PutUint32(out[8:12], x2)
binary.LittleEndian.PutUint32(out[12:16], x3)
binary.LittleEndian.PutUint32(out[16:20], x4)
binary.LittleEndian.PutUint32(out[20:24], x5)
binary.LittleEndian.PutUint32(out[24:28], x6)
binary.LittleEndian.PutUint32(out[28:32], x7)
binary.LittleEndian.PutUint32(out[32:36], x8)
binary.LittleEndian.PutUint32(out[36:40], x9)
binary.LittleEndian.PutUint32(out[40:44], x10)
binary.LittleEndian.PutUint32(out[44:48], x11)
binary.LittleEndian.PutUint32(out[48:52], x12)
binary.LittleEndian.PutUint32(out[52:56], x13)
binary.LittleEndian.PutUint32(out[56:60], x14)
binary.LittleEndian.PutUint32(out[60:64], x15)
}
// XORKeyStream crypts bytes from in to out using the given key and counters.
// In and out may be the same slice but otherwise should not overlap. 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) {
var block [64]byte
var counterCopy [16]byte
copy(counterCopy[:], counter[:])
for len(in) >= 64 {
core(&block, &counterCopy, key)
for i, x := range block {
out[i] = in[i] ^ x
}
u := uint32(1)
for i := 0; i < 4; i++ {
u += uint32(counterCopy[i])
counterCopy[i] = byte(u)
u >>= 8
}
in = in[64:]
out = out[64:]
}
if len(in) > 0 {
core(&block, &counterCopy, key)
for i, v := range in {
out[i] = v ^ block[i]
}
}
}

View File

@ -1,33 +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
import (
"encoding/hex"
"testing"
)
func TestCore(t *testing.T) {
// This is just a smoke test that checks the example from
// https://tools.ietf.org/html/rfc7539#section-2.3.2. The
// chacha20poly1305 package contains much more extensive tests of this
// code.
var key [32]byte
for i := range key {
key[i] = byte(i)
}
var input [16]byte
input[0] = 1
input[7] = 9
input[11] = 0x4a
var out [64]byte
XORKeyStream(out[:], out[:], &input, &key)
const expected = "10f1e7e4d13b5915500fdd1fa32071c4c7d1f4c733c068030422aa9ac3d46c4ed2826446079faa0914c2d705d98b02a2b5129cd1de164eb9cbd083e8a2503c4e"
if result := hex.EncodeToString(out[:]); result != expected {
t.Errorf("wanted %x but got %x", expected, result)
}
}

View File

@ -86,7 +86,7 @@ func feFromBytes(dst *fieldElement, src *[32]byte) {
h6 := load3(src[20:]) << 7
h7 := load3(src[23:]) << 5
h8 := load3(src[26:]) << 4
h9 := load3(src[29:]) << 2
h9 := (load3(src[29:]) & 0x7fffff) << 2
var carry [10]int64
carry[9] = (h9 + 1<<24) >> 25

View File

@ -5,6 +5,8 @@
package curve25519
import (
"bytes"
"crypto/rand"
"fmt"
"testing"
)
@ -28,6 +30,44 @@ func TestBaseScalarMult(t *testing.T) {
}
}
func TestTestVectors(t *testing.T) {
for _, tv := range testVectors {
var got [32]byte
ScalarMult(&got, &tv.In, &tv.Base)
if !bytes.Equal(got[:], tv.Expect[:]) {
t.Logf(" in = %x", tv.In)
t.Logf(" base = %x", tv.Base)
t.Logf(" got = %x", got)
t.Logf("expect = %x", tv.Expect)
t.Fail()
}
}
}
// TestHighBitIgnored tests the following requirement in RFC 7748:
//
// When receiving such an array, implementations of X25519 (but not X448) MUST
// mask the most significant bit in the final byte.
//
// Regression test for issue #30095.
func TestHighBitIgnored(t *testing.T) {
var s, u [32]byte
rand.Read(s[:])
rand.Read(u[:])
var hi0, hi1 [32]byte
u[31] &= 0x7f
ScalarMult(&hi0, &s, &u)
u[31] |= 0x80
ScalarMult(&hi1, &s, &u)
if !bytes.Equal(hi0[:], hi1[:]) {
t.Errorf("high bit of group point should not affect result")
}
}
func BenchmarkScalarBaseMult(b *testing.B) {
var in, out [32]byte
in[0] = 1

View File

@ -121,18 +121,18 @@ TEXT ·ladderstep(SB),0,$296-8
ADDQ AX,R12
ADCQ DX,R13
MOVQ $REDMASK51,DX
SHLQ $13,CX:SI
SHLQ $13,SI,CX
ANDQ DX,SI
SHLQ $13,R9:R8
SHLQ $13,R8,R9
ANDQ DX,R8
ADDQ CX,R8
SHLQ $13,R11:R10
SHLQ $13,R10,R11
ANDQ DX,R10
ADDQ R9,R10
SHLQ $13,R13:R12
SHLQ $13,R12,R13
ANDQ DX,R12
ADDQ R11,R12
SHLQ $13,R15:R14
SHLQ $13,R14,R15
ANDQ DX,R14
ADDQ R13,R14
IMUL3Q $19,R15,CX
@ -236,18 +236,18 @@ TEXT ·ladderstep(SB),0,$296-8
ADDQ AX,R12
ADCQ DX,R13
MOVQ $REDMASK51,DX
SHLQ $13,CX:SI
SHLQ $13,SI,CX
ANDQ DX,SI
SHLQ $13,R9:R8
SHLQ $13,R8,R9
ANDQ DX,R8
ADDQ CX,R8
SHLQ $13,R11:R10
SHLQ $13,R10,R11
ANDQ DX,R10
ADDQ R9,R10
SHLQ $13,R13:R12
SHLQ $13,R12,R13
ANDQ DX,R12
ADDQ R11,R12
SHLQ $13,R15:R14
SHLQ $13,R14,R15
ANDQ DX,R14
ADDQ R13,R14
IMUL3Q $19,R15,CX
@ -441,18 +441,18 @@ TEXT ·ladderstep(SB),0,$296-8
ADDQ AX,R12
ADCQ DX,R13
MOVQ $REDMASK51,DX
SHLQ $13,CX:SI
SHLQ $13,SI,CX
ANDQ DX,SI
SHLQ $13,R9:R8
SHLQ $13,R8,R9
ANDQ DX,R8
ADDQ CX,R8
SHLQ $13,R11:R10
SHLQ $13,R10,R11
ANDQ DX,R10
ADDQ R9,R10
SHLQ $13,R13:R12
SHLQ $13,R12,R13
ANDQ DX,R12
ADDQ R11,R12
SHLQ $13,R15:R14
SHLQ $13,R14,R15
ANDQ DX,R14
ADDQ R13,R14
IMUL3Q $19,R15,CX
@ -591,18 +591,18 @@ TEXT ·ladderstep(SB),0,$296-8
ADDQ AX,R12
ADCQ DX,R13
MOVQ $REDMASK51,DX
SHLQ $13,CX:SI
SHLQ $13,SI,CX
ANDQ DX,SI
SHLQ $13,R9:R8
SHLQ $13,R8,R9
ANDQ DX,R8
ADDQ CX,R8
SHLQ $13,R11:R10
SHLQ $13,R10,R11
ANDQ DX,R10
ADDQ R9,R10
SHLQ $13,R13:R12
SHLQ $13,R12,R13
ANDQ DX,R12
ADDQ R11,R12
SHLQ $13,R15:R14
SHLQ $13,R14,R15
ANDQ DX,R14
ADDQ R13,R14
IMUL3Q $19,R15,CX
@ -731,18 +731,18 @@ TEXT ·ladderstep(SB),0,$296-8
ADDQ AX,R12
ADCQ DX,R13
MOVQ $REDMASK51,DX
SHLQ $13,CX:SI
SHLQ $13,SI,CX
ANDQ DX,SI
SHLQ $13,R9:R8
SHLQ $13,R8,R9
ANDQ DX,R8
ADDQ CX,R8
SHLQ $13,R11:R10
SHLQ $13,R10,R11
ANDQ DX,R10
ADDQ R9,R10
SHLQ $13,R13:R12
SHLQ $13,R12,R13
ANDQ DX,R12
ADDQ R11,R12
SHLQ $13,R15:R14
SHLQ $13,R14,R15
ANDQ DX,R14
ADDQ R13,R14
IMUL3Q $19,R15,CX
@ -846,18 +846,18 @@ TEXT ·ladderstep(SB),0,$296-8
ADDQ AX,R12
ADCQ DX,R13
MOVQ $REDMASK51,DX
SHLQ $13,CX:SI
SHLQ $13,SI,CX
ANDQ DX,SI
SHLQ $13,R9:R8
SHLQ $13,R8,R9
ANDQ DX,R8
ADDQ CX,R8
SHLQ $13,R11:R10
SHLQ $13,R10,R11
ANDQ DX,R10
ADDQ R9,R10
SHLQ $13,R13:R12
SHLQ $13,R12,R13
ANDQ DX,R12
ADDQ R11,R12
SHLQ $13,R15:R14
SHLQ $13,R14,R15
ANDQ DX,R14
ADDQ R13,R14
IMUL3Q $19,R15,CX
@ -996,18 +996,18 @@ TEXT ·ladderstep(SB),0,$296-8
ADDQ AX,R12
ADCQ DX,R13
MOVQ $REDMASK51,DX
SHLQ $13,CX:SI
SHLQ $13,SI,CX
ANDQ DX,SI
SHLQ $13,R9:R8
SHLQ $13,R8,R9
ANDQ DX,R8
ADDQ CX,R8
SHLQ $13,R11:R10
SHLQ $13,R10,R11
ANDQ DX,R10
ADDQ R9,R10
SHLQ $13,R13:R12
SHLQ $13,R12,R13
ANDQ DX,R12
ADDQ R11,R12
SHLQ $13,R15:R14
SHLQ $13,R14,R15
ANDQ DX,R14
ADDQ R13,R14
IMUL3Q $19,R15,CX
@ -1146,18 +1146,18 @@ TEXT ·ladderstep(SB),0,$296-8
ADDQ AX,R12
ADCQ DX,R13
MOVQ $REDMASK51,DX
SHLQ $13,CX:SI
SHLQ $13,SI,CX
ANDQ DX,SI
SHLQ $13,R9:R8
SHLQ $13,R8,R9
ANDQ DX,R8
ADDQ CX,R8
SHLQ $13,R11:R10
SHLQ $13,R10,R11
ANDQ DX,R10
ADDQ R9,R10
SHLQ $13,R13:R12
SHLQ $13,R12,R13
ANDQ DX,R12
ADDQ R11,R12
SHLQ $13,R15:R14
SHLQ $13,R14,R15
ANDQ DX,R14
ADDQ R13,R14
IMUL3Q $19,R15,CX
@ -1332,18 +1332,18 @@ TEXT ·ladderstep(SB),0,$296-8
ADDQ AX,R12
ADCQ DX,R13
MOVQ $REDMASK51,DX
SHLQ $13,CX:SI
SHLQ $13,SI,CX
ANDQ DX,SI
SHLQ $13,R9:R8
SHLQ $13,R8,R9
ANDQ DX,R8
ADDQ CX,R8
SHLQ $13,R11:R10
SHLQ $13,R10,R11
ANDQ DX,R10
ADDQ R9,R10
SHLQ $13,R13:R12
SHLQ $13,R12,R13
ANDQ DX,R12
ADDQ R11,R12
SHLQ $13,R15:R14
SHLQ $13,R14,R15
ANDQ DX,R14
ADDQ R13,R14
IMUL3Q $19,R15,CX

View File

@ -124,18 +124,18 @@ TEXT ·mul(SB),0,$16-24
ADDQ AX,R14
ADCQ DX,R15
MOVQ $REDMASK51,SI
SHLQ $13,R9:R8
SHLQ $13,R8,R9
ANDQ SI,R8
SHLQ $13,R11:R10
SHLQ $13,R10,R11
ANDQ SI,R10
ADDQ R9,R10
SHLQ $13,R13:R12
SHLQ $13,R12,R13
ANDQ SI,R12
ADDQ R11,R12
SHLQ $13,R15:R14
SHLQ $13,R14,R15
ANDQ SI,R14
ADDQ R13,R14
SHLQ $13,BP:BX
SHLQ $13,BX,BP
ANDQ SI,BX
ADDQ R15,BX
IMUL3Q $19,BP,DX

View File

@ -87,18 +87,18 @@ TEXT ·square(SB),7,$0-16
ADDQ AX,R13
ADCQ DX,R14
MOVQ $REDMASK51,SI
SHLQ $13,R8:CX
SHLQ $13,CX,R8
ANDQ SI,CX
SHLQ $13,R10:R9
SHLQ $13,R9,R10
ANDQ SI,R9
ADDQ R8,R9
SHLQ $13,R12:R11
SHLQ $13,R11,R12
ANDQ SI,R11
ADDQ R10,R11
SHLQ $13,R14:R13
SHLQ $13,R13,R14
ANDQ SI,R13
ADDQ R12,R13
SHLQ $13,BX:R15
SHLQ $13,R15,BX
ANDQ SI,R15
ADDQ R14,R15
IMUL3Q $19,BX,DX

View File

@ -0,0 +1,93 @@
// 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 curve25519
// testVectors generated with BoringSSL.
var testVectors = []struct {
In [32]byte
Base [32]byte
Expect [32]byte
}{
{
In: [32]byte{0x66, 0x8f, 0xb9, 0xf7, 0x6a, 0xd9, 0x71, 0xc8, 0x1a, 0xc9, 0x0, 0x7, 0x1a, 0x15, 0x60, 0xbc, 0xe2, 0xca, 0x0, 0xca, 0xc7, 0xe6, 0x7a, 0xf9, 0x93, 0x48, 0x91, 0x37, 0x61, 0x43, 0x40, 0x14},
Base: [32]byte{0xdb, 0x5f, 0x32, 0xb7, 0xf8, 0x41, 0xe7, 0xa1, 0xa0, 0x9, 0x68, 0xef, 0xfd, 0xed, 0x12, 0x73, 0x5f, 0xc4, 0x7a, 0x3e, 0xb1, 0x3b, 0x57, 0x9a, 0xac, 0xad, 0xea, 0xe8, 0x9, 0x39, 0xa7, 0xdd},
Expect: [32]byte{0x9, 0xd, 0x85, 0xe5, 0x99, 0xea, 0x8e, 0x2b, 0xee, 0xb6, 0x13, 0x4, 0xd3, 0x7b, 0xe1, 0xe, 0xc5, 0xc9, 0x5, 0xf9, 0x92, 0x7d, 0x32, 0xf4, 0x2a, 0x9a, 0xa, 0xfb, 0x3e, 0xb, 0x40, 0x74},
},
{
In: [32]byte{0x63, 0x66, 0x95, 0xe3, 0x4f, 0x75, 0xb9, 0xa2, 0x79, 0xc8, 0x70, 0x6f, 0xad, 0x12, 0x89, 0xf2, 0xc0, 0xb1, 0xe2, 0x2e, 0x16, 0xf8, 0xb8, 0x86, 0x17, 0x29, 0xc1, 0xa, 0x58, 0x29, 0x58, 0xaf},
Base: [32]byte{0x9, 0xd, 0x7, 0x1, 0xf8, 0xfd, 0xe2, 0x8f, 0x70, 0x4, 0x3b, 0x83, 0xf2, 0x34, 0x62, 0x25, 0x41, 0x9b, 0x18, 0xa7, 0xf2, 0x7e, 0x9e, 0x3d, 0x2b, 0xfd, 0x4, 0xe1, 0xf, 0x3d, 0x21, 0x3e},
Expect: [32]byte{0xbf, 0x26, 0xec, 0x7e, 0xc4, 0x13, 0x6, 0x17, 0x33, 0xd4, 0x40, 0x70, 0xea, 0x67, 0xca, 0xb0, 0x2a, 0x85, 0xdc, 0x1b, 0xe8, 0xcf, 0xe1, 0xff, 0x73, 0xd5, 0x41, 0xcc, 0x8, 0x32, 0x55, 0x6},
},
{
In: [32]byte{0x73, 0x41, 0x81, 0xcd, 0x1a, 0x94, 0x6, 0x52, 0x2a, 0x56, 0xfe, 0x25, 0xe4, 0x3e, 0xcb, 0xf0, 0x29, 0x5d, 0xb5, 0xdd, 0xd0, 0x60, 0x9b, 0x3c, 0x2b, 0x4e, 0x79, 0xc0, 0x6f, 0x8b, 0xd4, 0x6d},
Base: [32]byte{0xf8, 0xa8, 0x42, 0x1c, 0x7d, 0x21, 0xa9, 0x2d, 0xb3, 0xed, 0xe9, 0x79, 0xe1, 0xfa, 0x6a, 0xcb, 0x6, 0x2b, 0x56, 0xb1, 0x88, 0x5c, 0x71, 0xc5, 0x11, 0x53, 0xcc, 0xb8, 0x80, 0xac, 0x73, 0x15},
Expect: [32]byte{0x11, 0x76, 0xd0, 0x16, 0x81, 0xf2, 0xcf, 0x92, 0x9d, 0xa2, 0xc7, 0xa3, 0xdf, 0x66, 0xb5, 0xd7, 0x72, 0x9f, 0xd4, 0x22, 0x22, 0x6f, 0xd6, 0x37, 0x42, 0x16, 0xbf, 0x7e, 0x2, 0xfd, 0xf, 0x62},
},
{
In: [32]byte{0x1f, 0x70, 0x39, 0x1f, 0x6b, 0xa8, 0x58, 0x12, 0x94, 0x13, 0xbd, 0x80, 0x1b, 0x12, 0xac, 0xbf, 0x66, 0x23, 0x62, 0x82, 0x5c, 0xa2, 0x50, 0x9c, 0x81, 0x87, 0x59, 0xa, 0x2b, 0xe, 0x61, 0x72},
Base: [32]byte{0xd3, 0xea, 0xd0, 0x7a, 0x0, 0x8, 0xf4, 0x45, 0x2, 0xd5, 0x80, 0x8b, 0xff, 0xc8, 0x97, 0x9f, 0x25, 0xa8, 0x59, 0xd5, 0xad, 0xf4, 0x31, 0x2e, 0xa4, 0x87, 0x48, 0x9c, 0x30, 0xe0, 0x1b, 0x3b},
Expect: [32]byte{0xf8, 0x48, 0x2f, 0x2e, 0x9e, 0x58, 0xbb, 0x6, 0x7e, 0x86, 0xb2, 0x87, 0x24, 0xb3, 0xc0, 0xa3, 0xbb, 0xb5, 0x7, 0x3e, 0x4c, 0x6a, 0xcd, 0x93, 0xdf, 0x54, 0x5e, 0xff, 0xdb, 0xba, 0x50, 0x5f},
},
{
In: [32]byte{0x3a, 0x7a, 0xe6, 0xcf, 0x8b, 0x88, 0x9d, 0x2b, 0x7a, 0x60, 0xa4, 0x70, 0xad, 0x6a, 0xd9, 0x99, 0x20, 0x6b, 0xf5, 0x7d, 0x90, 0x30, 0xdd, 0xf7, 0xf8, 0x68, 0xc, 0x8b, 0x1a, 0x64, 0x5d, 0xaa},
Base: [32]byte{0x4d, 0x25, 0x4c, 0x80, 0x83, 0xd8, 0x7f, 0x1a, 0x9b, 0x3e, 0xa7, 0x31, 0xef, 0xcf, 0xf8, 0xa6, 0xf2, 0x31, 0x2d, 0x6f, 0xed, 0x68, 0xe, 0xf8, 0x29, 0x18, 0x51, 0x61, 0xc8, 0xfc, 0x50, 0x60},
Expect: [32]byte{0x47, 0xb3, 0x56, 0xd5, 0x81, 0x8d, 0xe8, 0xef, 0xac, 0x77, 0x4b, 0x71, 0x4c, 0x42, 0xc4, 0x4b, 0xe6, 0x85, 0x23, 0xdd, 0x57, 0xdb, 0xd7, 0x39, 0x62, 0xd5, 0xa5, 0x26, 0x31, 0x87, 0x62, 0x37},
},
{
In: [32]byte{0x20, 0x31, 0x61, 0xc3, 0x15, 0x9a, 0x87, 0x6a, 0x2b, 0xea, 0xec, 0x29, 0xd2, 0x42, 0x7f, 0xb0, 0xc7, 0xc3, 0xd, 0x38, 0x2c, 0xd0, 0x13, 0xd2, 0x7c, 0xc3, 0xd3, 0x93, 0xdb, 0xd, 0xaf, 0x6f},
Base: [32]byte{0x6a, 0xb9, 0x5d, 0x1a, 0xbe, 0x68, 0xc0, 0x9b, 0x0, 0x5c, 0x3d, 0xb9, 0x4, 0x2c, 0xc9, 0x1a, 0xc8, 0x49, 0xf7, 0xe9, 0x4a, 0x2a, 0x4a, 0x9b, 0x89, 0x36, 0x78, 0x97, 0xb, 0x7b, 0x95, 0xbf},
Expect: [32]byte{0x11, 0xed, 0xae, 0xdc, 0x95, 0xff, 0x78, 0xf5, 0x63, 0xa1, 0xc8, 0xf1, 0x55, 0x91, 0xc0, 0x71, 0xde, 0xa0, 0x92, 0xb4, 0xd7, 0xec, 0xaa, 0xc8, 0xe0, 0x38, 0x7b, 0x5a, 0x16, 0xc, 0x4e, 0x5d},
},
{
In: [32]byte{0x13, 0xd6, 0x54, 0x91, 0xfe, 0x75, 0xf2, 0x3, 0xa0, 0x8, 0xb4, 0x41, 0x5a, 0xbc, 0x60, 0xd5, 0x32, 0xe6, 0x95, 0xdb, 0xd2, 0xf1, 0xe8, 0x3, 0xac, 0xcb, 0x34, 0xb2, 0xb7, 0x2c, 0x3d, 0x70},
Base: [32]byte{0x2e, 0x78, 0x4e, 0x4, 0xca, 0x0, 0x73, 0x33, 0x62, 0x56, 0xa8, 0x39, 0x25, 0x5e, 0xd2, 0xf7, 0xd4, 0x79, 0x6a, 0x64, 0xcd, 0xc3, 0x7f, 0x1e, 0xb0, 0xe5, 0xc4, 0xc8, 0xd1, 0xd1, 0xe0, 0xf5},
Expect: [32]byte{0x56, 0x3e, 0x8c, 0x9a, 0xda, 0xa7, 0xd7, 0x31, 0x1, 0xb0, 0xf2, 0xea, 0xd3, 0xca, 0xe1, 0xea, 0x5d, 0x8f, 0xcd, 0x5c, 0xd3, 0x60, 0x80, 0xbb, 0x8e, 0x6e, 0xc0, 0x3d, 0x61, 0x45, 0x9, 0x17},
},
{
In: [32]byte{0x68, 0x6f, 0x7d, 0xa9, 0x3b, 0xf2, 0x68, 0xe5, 0x88, 0x6, 0x98, 0x31, 0xf0, 0x47, 0x16, 0x3f, 0x33, 0x58, 0x99, 0x89, 0xd0, 0x82, 0x6e, 0x98, 0x8, 0xfb, 0x67, 0x8e, 0xd5, 0x7e, 0x67, 0x49},
Base: [32]byte{0x8b, 0x54, 0x9b, 0x2d, 0xf6, 0x42, 0xd3, 0xb2, 0x5f, 0xe8, 0x38, 0xf, 0x8c, 0xc4, 0x37, 0x5f, 0x99, 0xb7, 0xbb, 0x4d, 0x27, 0x5f, 0x77, 0x9f, 0x3b, 0x7c, 0x81, 0xb8, 0xa2, 0xbb, 0xc1, 0x29},
Expect: [32]byte{0x1, 0x47, 0x69, 0x65, 0x42, 0x6b, 0x61, 0x71, 0x74, 0x9a, 0x8a, 0xdd, 0x92, 0x35, 0x2, 0x5c, 0xe5, 0xf5, 0x57, 0xfe, 0x40, 0x9, 0xf7, 0x39, 0x30, 0x44, 0xeb, 0xbb, 0x8a, 0xe9, 0x52, 0x79},
},
{
In: [32]byte{0x82, 0xd6, 0x1c, 0xce, 0xdc, 0x80, 0x6a, 0x60, 0x60, 0xa3, 0x34, 0x9a, 0x5e, 0x87, 0xcb, 0xc7, 0xac, 0x11, 0x5e, 0x4f, 0x87, 0x77, 0x62, 0x50, 0xae, 0x25, 0x60, 0x98, 0xa7, 0xc4, 0x49, 0x59},
Base: [32]byte{0x8b, 0x6b, 0x9d, 0x8, 0xf6, 0x1f, 0xc9, 0x1f, 0xe8, 0xb3, 0x29, 0x53, 0xc4, 0x23, 0x40, 0xf0, 0x7, 0xb5, 0x71, 0xdc, 0xb0, 0xa5, 0x6d, 0x10, 0x72, 0x4e, 0xce, 0xf9, 0x95, 0xc, 0xfb, 0x25},
Expect: [32]byte{0x9c, 0x49, 0x94, 0x1f, 0x9c, 0x4f, 0x18, 0x71, 0xfa, 0x40, 0x91, 0xfe, 0xd7, 0x16, 0xd3, 0x49, 0x99, 0xc9, 0x52, 0x34, 0xed, 0xf2, 0xfd, 0xfb, 0xa6, 0xd1, 0x4a, 0x5a, 0xfe, 0x9e, 0x5, 0x58},
},
{
In: [32]byte{0x7d, 0xc7, 0x64, 0x4, 0x83, 0x13, 0x97, 0xd5, 0x88, 0x4f, 0xdf, 0x6f, 0x97, 0xe1, 0x74, 0x4c, 0x9e, 0xb1, 0x18, 0xa3, 0x1a, 0x7b, 0x23, 0xf8, 0xd7, 0x9f, 0x48, 0xce, 0x9c, 0xad, 0x15, 0x4b},
Base: [32]byte{0x1a, 0xcd, 0x29, 0x27, 0x84, 0xf4, 0x79, 0x19, 0xd4, 0x55, 0xf8, 0x87, 0x44, 0x83, 0x58, 0x61, 0xb, 0xb9, 0x45, 0x96, 0x70, 0xeb, 0x99, 0xde, 0xe4, 0x60, 0x5, 0xf6, 0x89, 0xca, 0x5f, 0xb6},
Expect: [32]byte{0x0, 0xf4, 0x3c, 0x2, 0x2e, 0x94, 0xea, 0x38, 0x19, 0xb0, 0x36, 0xae, 0x2b, 0x36, 0xb2, 0xa7, 0x61, 0x36, 0xaf, 0x62, 0x8a, 0x75, 0x1f, 0xe5, 0xd0, 0x1e, 0x3, 0xd, 0x44, 0x25, 0x88, 0x59},
},
{
In: [32]byte{0xfb, 0xc4, 0x51, 0x1d, 0x23, 0xa6, 0x82, 0xae, 0x4e, 0xfd, 0x8, 0xc8, 0x17, 0x9c, 0x1c, 0x6, 0x7f, 0x9c, 0x8b, 0xe7, 0x9b, 0xbc, 0x4e, 0xff, 0x5c, 0xe2, 0x96, 0xc6, 0xbc, 0x1f, 0xf4, 0x45},
Base: [32]byte{0x55, 0xca, 0xff, 0x21, 0x81, 0xf2, 0x13, 0x6b, 0xe, 0xd0, 0xe1, 0xe2, 0x99, 0x44, 0x48, 0xe1, 0x6c, 0xc9, 0x70, 0x64, 0x6a, 0x98, 0x3d, 0x14, 0xd, 0xc4, 0xea, 0xb3, 0xd9, 0x4c, 0x28, 0x4e},
Expect: [32]byte{0xae, 0x39, 0xd8, 0x16, 0x53, 0x23, 0x45, 0x79, 0x4d, 0x26, 0x91, 0xe0, 0x80, 0x1c, 0xaa, 0x52, 0x5f, 0xc3, 0x63, 0x4d, 0x40, 0x2c, 0xe9, 0x58, 0xb, 0x33, 0x38, 0xb4, 0x6f, 0x8b, 0xb9, 0x72},
},
{
In: [32]byte{0x4e, 0x6, 0xc, 0xe1, 0xc, 0xeb, 0xf0, 0x95, 0x9, 0x87, 0x16, 0xc8, 0x66, 0x19, 0xeb, 0x9f, 0x7d, 0xf6, 0x65, 0x24, 0x69, 0x8b, 0xa7, 0x98, 0x8c, 0x3b, 0x90, 0x95, 0xd9, 0xf5, 0x1, 0x34},
Base: [32]byte{0x57, 0x73, 0x3f, 0x2d, 0x86, 0x96, 0x90, 0xd0, 0xd2, 0xed, 0xae, 0xc9, 0x52, 0x3d, 0xaa, 0x2d, 0xa9, 0x54, 0x45, 0xf4, 0x4f, 0x57, 0x83, 0xc1, 0xfa, 0xec, 0x6c, 0x3a, 0x98, 0x28, 0x18, 0xf3},
Expect: [32]byte{0xa6, 0x1e, 0x74, 0x55, 0x2c, 0xce, 0x75, 0xf5, 0xe9, 0x72, 0xe4, 0x24, 0xf2, 0xcc, 0xb0, 0x9c, 0x83, 0xbc, 0x1b, 0x67, 0x1, 0x47, 0x48, 0xf0, 0x2c, 0x37, 0x1a, 0x20, 0x9e, 0xf2, 0xfb, 0x2c},
},
{
In: [32]byte{0x5c, 0x49, 0x2c, 0xba, 0x2c, 0xc8, 0x92, 0x48, 0x8a, 0x9c, 0xeb, 0x91, 0x86, 0xc2, 0xaa, 0xc2, 0x2f, 0x1, 0x5b, 0xf3, 0xef, 0x8d, 0x3e, 0xcc, 0x9c, 0x41, 0x76, 0x97, 0x62, 0x61, 0xaa, 0xb1},
Base: [32]byte{0x67, 0x97, 0xc2, 0xe7, 0xdc, 0x92, 0xcc, 0xbe, 0x7c, 0x5, 0x6b, 0xec, 0x35, 0xa, 0xb6, 0xd3, 0xbd, 0x2a, 0x2c, 0x6b, 0xc5, 0xa8, 0x7, 0xbb, 0xca, 0xe1, 0xf6, 0xc2, 0xaf, 0x80, 0x36, 0x44},
Expect: [32]byte{0xfc, 0xf3, 0x7, 0xdf, 0xbc, 0x19, 0x2, 0xb, 0x28, 0xa6, 0x61, 0x8c, 0x6c, 0x62, 0x2f, 0x31, 0x7e, 0x45, 0x96, 0x7d, 0xac, 0xf4, 0xae, 0x4a, 0xa, 0x69, 0x9a, 0x10, 0x76, 0x9f, 0xde, 0x14},
},
{
In: [32]byte{0xea, 0x33, 0x34, 0x92, 0x96, 0x5, 0x5a, 0x4e, 0x8b, 0x19, 0x2e, 0x3c, 0x23, 0xc5, 0xf4, 0xc8, 0x44, 0x28, 0x2a, 0x3b, 0xfc, 0x19, 0xec, 0xc9, 0xdc, 0x64, 0x6a, 0x42, 0xc3, 0x8d, 0xc2, 0x48},
Base: [32]byte{0x2c, 0x75, 0xd8, 0x51, 0x42, 0xec, 0xad, 0x3e, 0x69, 0x44, 0x70, 0x4, 0x54, 0xc, 0x1c, 0x23, 0x54, 0x8f, 0xc8, 0xf4, 0x86, 0x25, 0x1b, 0x8a, 0x19, 0x46, 0x3f, 0x3d, 0xf6, 0xf8, 0xac, 0x61},
Expect: [32]byte{0x5d, 0xca, 0xb6, 0x89, 0x73, 0xf9, 0x5b, 0xd3, 0xae, 0x4b, 0x34, 0xfa, 0xb9, 0x49, 0xfb, 0x7f, 0xb1, 0x5a, 0xf1, 0xd8, 0xca, 0xe2, 0x8c, 0xd6, 0x99, 0xf9, 0xc1, 0xaa, 0x33, 0x37, 0x34, 0x2f},
},
{
In: [32]byte{0x4f, 0x29, 0x79, 0xb1, 0xec, 0x86, 0x19, 0xe4, 0x5c, 0xa, 0xb, 0x2b, 0x52, 0x9, 0x34, 0x54, 0x1a, 0xb9, 0x44, 0x7, 0xb6, 0x4d, 0x19, 0xa, 0x76, 0xf3, 0x23, 0x14, 0xef, 0xe1, 0x84, 0xe7},
Base: [32]byte{0xf7, 0xca, 0xe1, 0x8d, 0x8d, 0x36, 0xa7, 0xf5, 0x61, 0x17, 0xb8, 0xb7, 0xe, 0x25, 0x52, 0x27, 0x7f, 0xfc, 0x99, 0xdf, 0x87, 0x56, 0xb5, 0xe1, 0x38, 0xbf, 0x63, 0x68, 0xbc, 0x87, 0xf7, 0x4c},
Expect: [32]byte{0xe4, 0xe6, 0x34, 0xeb, 0xb4, 0xfb, 0x66, 0x4f, 0xe8, 0xb2, 0xcf, 0xa1, 0x61, 0x5f, 0x0, 0xe6, 0x46, 0x6f, 0xff, 0x73, 0x2c, 0xe1, 0xf8, 0xa0, 0xc8, 0xd2, 0x72, 0x74, 0x31, 0xd1, 0x6f, 0x14},
},
{
In: [32]byte{0xf5, 0xd8, 0xa9, 0x27, 0x90, 0x1d, 0x4f, 0xa4, 0x24, 0x90, 0x86, 0xb7, 0xff, 0xec, 0x24, 0xf5, 0x29, 0x7d, 0x80, 0x11, 0x8e, 0x4a, 0xc9, 0xd3, 0xfc, 0x9a, 0x82, 0x37, 0x95, 0x1e, 0x3b, 0x7f},
Base: [32]byte{0x3c, 0x23, 0x5e, 0xdc, 0x2, 0xf9, 0x11, 0x56, 0x41, 0xdb, 0xf5, 0x16, 0xd5, 0xde, 0x8a, 0x73, 0x5d, 0x6e, 0x53, 0xe2, 0x2a, 0xa2, 0xac, 0x14, 0x36, 0x56, 0x4, 0x5f, 0xf2, 0xe9, 0x52, 0x49},
Expect: [32]byte{0xab, 0x95, 0x15, 0xab, 0x14, 0xaf, 0x9d, 0x27, 0xe, 0x1d, 0xae, 0xc, 0x56, 0x80, 0xcb, 0xc8, 0x88, 0xb, 0xd8, 0xa8, 0xe7, 0xeb, 0x67, 0xb4, 0xda, 0x42, 0xa6, 0x61, 0x96, 0x1e, 0xfc, 0xb},
},
}

6
x/crypto/go.mod Normal file
View File

@ -0,0 +1,6 @@
module golang.org/x/crypto
require (
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3
golang.org/x/sys v0.0.0-20190412213103-97732733099d
)

8
x/crypto/go.sum Normal file
View File

@ -0,0 +1,8 @@
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

View File

@ -0,0 +1,308 @@
// 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

View File

@ -0,0 +1,31 @@
// 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])
}
}

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !s390x gccgo appengine
// +build !arm64,!s390x arm64,!go1.11 gccgo appengine
package chacha20

View File

@ -6,15 +6,14 @@
package chacha20
var haveAsm = hasVectorFacility()
import (
"golang.org/x/sys/cpu"
)
var haveAsm = cpu.S390X.HasVX
const bufSize = 256
// hasVectorFacility reports whether the machine supports the vector
// facility (vx).
// Implementation in asm_s390x.s.
func hasVectorFacility() bool
// xorKeyStreamVX is an assembly implementation of XORKeyStream. It must only
// be called when the vector facility is available.
// Implementation in asm_s390x.s.

View File

@ -258,26 +258,3 @@ tail:
MOVD R8, R3
MOVD $0, R4
JMP continue
// func hasVectorFacility() bool
TEXT ·hasVectorFacility(SB), NOSPLIT, $24-1
MOVD $x-24(SP), R1
XC $24, 0(R1), 0(R1) // clear the storage
MOVD $2, R0 // R0 is the number of double words stored -1
WORD $0xB2B01000 // STFLE 0(R1)
XOR R0, R0 // reset the value of R0
MOVBZ z-8(SP), R1
AND $0x40, R1
BEQ novector
vectorinstalled:
// check if the vector instruction has been enabled
VLEIB $0, $0xF, V16
VLGVB $0, V16, R1
CMPBNE R1, $0xF, novector
MOVB $1, ret+0(FP) // have vx
RET
novector:
MOVB $0, ret+0(FP) // no vx
RET

View File

@ -3,6 +3,10 @@
// license that can be found in the LICENSE file.
// Package md4 implements the MD4 hash algorithm as defined in RFC 1320.
//
// Deprecated: MD4 is cryptographically broken and should should only be used
// where compatibility with legacy systems, not security, is the goal. Instead,
// use a secure hash like SHA-256 (from crypto/sha256).
package md4 // import "golang.org/x/crypto/md4"
import (

View File

@ -40,7 +40,7 @@ func TestOpen(t *testing.T) {
if !bytes.Equal(message, testMessage) {
t.Fatalf("message did not match, got\n%x\n, expected\n%x", message, testMessage)
}
message, ok = Open(nil, testSignedMessage[1:], &testPublicKey)
_, ok = Open(nil, testSignedMessage[1:], &testPublicKey)
if ok {
t.Fatalf("invalid signed message successfully verified")
}

View File

@ -487,6 +487,9 @@ func ParseResponseForCert(bytes []byte, cert, issuer *x509.Certificate) (*Respon
if err != nil {
return nil, err
}
if len(rest) > 0 {
return nil, ParseError("trailing data in OCSP response")
}
if n := len(basicResp.TBSResponseData.Responses); n == 0 || cert == nil && n > 1 {
return nil, ParseError("OCSP response contains bad number of responses")

View File

@ -18,6 +18,7 @@ import (
"io"
"net/textproto"
"strconv"
"strings"
"golang.org/x/crypto/openpgp/armor"
"golang.org/x/crypto/openpgp/errors"
@ -27,7 +28,7 @@ import (
// A Block represents a clearsigned message. A signature on a Block can
// be checked by passing Bytes into openpgp.CheckDetachedSignature.
type Block struct {
Headers textproto.MIMEHeader // Optional message headers
Headers textproto.MIMEHeader // Optional unverified Hash headers
Plaintext []byte // The original message text
Bytes []byte // The signed message
ArmoredSignature *armor.Block // The signature block
@ -69,8 +70,13 @@ func getLine(data []byte) (line, rest []byte) {
return data[0:i], data[j:]
}
// Decode finds the first clearsigned message in data and returns it, as well
// as the suffix of data which remains after the message.
// Decode finds the first clearsigned message in data and returns it, as well as
// the suffix of data which remains after the message. Any prefix data is
// discarded.
//
// If no message is found, or if the message is invalid, Decode returns nil and
// the whole data slice. The only allowed header type is Hash, and it is not
// verified against the signature hash.
func Decode(data []byte) (b *Block, rest []byte) {
// start begins with a newline. However, at the very beginning of
// the byte array, we'll accept the start string without it.
@ -83,8 +89,11 @@ func Decode(data []byte) (b *Block, rest []byte) {
return nil, data
}
// Consume the start line.
_, rest = getLine(rest)
// Consume the start line and check it does not have a suffix.
suffix, rest := getLine(rest)
if len(suffix) != 0 {
return nil, data
}
var line []byte
b = &Block{
@ -103,15 +112,25 @@ func Decode(data []byte) (b *Block, rest []byte) {
break
}
// Reject headers with control or Unicode characters.
if i := bytes.IndexFunc(line, func(r rune) bool {
return r < 0x20 || r > 0x7e
}); i != -1 {
return nil, data
}
i := bytes.Index(line, []byte{':'})
if i == -1 {
return nil, data
}
key, val := line[0:i], line[i+1:]
key = bytes.TrimSpace(key)
val = bytes.TrimSpace(val)
b.Headers.Add(string(key), string(val))
key, val := string(line[0:i]), string(line[i+1:])
key = strings.TrimSpace(key)
if key != "Hash" {
return nil, data
}
val = strings.TrimSpace(val)
b.Headers.Add(key, val)
}
firstLine := true

View File

@ -47,12 +47,6 @@ func TestParse(t *testing.T) {
testParse(t, clearsignInput2, "\r\n\r\n(This message has a couple of blank lines at the start and end.)\r\n\r\n", "\n\n(This message has a couple of blank lines at the start and end.)\n\n\n")
}
func TestParseInvalid(t *testing.T) {
if b, _ := Decode(clearsignInput3); b != nil {
t.Fatal("decoded a bad clearsigned message without any error")
}
}
func TestParseWithNoNewlineAtEnd(t *testing.T) {
input := clearsignInput
input = input[:len(input)-len("trailing")-1]
@ -140,6 +134,10 @@ func (qr *quickRand) Read(p []byte) (int, error) {
}
func TestMultiSign(t *testing.T) {
if testing.Short() {
t.Skip("skipping long test in -short mode")
}
zero := quickRand(0)
config := packet.Config{Rand: &zero}
@ -193,6 +191,59 @@ func TestMultiSign(t *testing.T) {
}
}
const signatureBlock = `
-----BEGIN PGP SIGNATURE-----
Version: OpenPrivacy 0.99
yDgBO22WxBHv7O8X7O/jygAEzol56iUKiXmV+XmpCtmpqQUKiQrFqclFqUDBovzS
vBSFjNSiVHsuAA==
=njUN
-----END PGP SIGNATURE-----
`
var invalidInputs = []string{
`
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256
(This message was truncated.)
`,
`
-----BEGIN PGP SIGNED MESSAGE-----garbage
Hash: SHA256
_o/
` + signatureBlock,
`
garbage-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256
_o/
` + signatureBlock,
`
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA` + "\x0b\x0b" + `256
_o/
` + signatureBlock,
`
-----BEGIN PGP SIGNED MESSAGE-----
NotHash: SHA256
_o/
` + signatureBlock,
}
func TestParseInvalid(t *testing.T) {
for i, input := range invalidInputs {
if b, rest := Decode([]byte(input)); b != nil {
t.Errorf("#%d: decoded a bad clearsigned message without any error", i)
} else if string(rest) != input {
t.Errorf("#%d: did not return all data with a bad message", i)
}
}
}
var clearsignInput = []byte(`
;lasjlkfdsa
@ -235,13 +286,6 @@ qZg6BaTvOxepqOxnhVU=
trailing`)
var clearsignInput3 = []byte(`
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256
(This message was truncated.)
`)
var signingKey = `-----BEGIN PGP PRIVATE KEY BLOCK-----
Version: GnuPG v1.4.10 (GNU/Linux)

View File

@ -504,7 +504,7 @@ const defaultRSAKeyBits = 2048
// which may be empty but must not contain any of "()<>\x00".
// If config is nil, sensible defaults will be used.
func NewEntity(name, comment, email string, config *packet.Config) (*Entity, error) {
currentTime := config.Now()
creationTime := config.Now()
bits := defaultRSAKeyBits
if config != nil && config.RSABits != 0 {
@ -525,8 +525,8 @@ func NewEntity(name, comment, email string, config *packet.Config) (*Entity, err
}
e := &Entity{
PrimaryKey: packet.NewRSAPublicKey(currentTime, &signingPriv.PublicKey),
PrivateKey: packet.NewRSAPrivateKey(currentTime, signingPriv),
PrimaryKey: packet.NewRSAPublicKey(creationTime, &signingPriv.PublicKey),
PrivateKey: packet.NewRSAPrivateKey(creationTime, signingPriv),
Identities: make(map[string]*Identity),
}
isPrimaryId := true
@ -534,7 +534,7 @@ func NewEntity(name, comment, email string, config *packet.Config) (*Entity, err
Name: uid.Id,
UserId: uid,
SelfSignature: &packet.Signature{
CreationTime: currentTime,
CreationTime: creationTime,
SigType: packet.SigTypePositiveCert,
PubKeyAlgo: packet.PubKeyAlgoRSA,
Hash: config.Hash(),
@ -563,10 +563,10 @@ func NewEntity(name, comment, email string, config *packet.Config) (*Entity, err
e.Subkeys = make([]Subkey, 1)
e.Subkeys[0] = Subkey{
PublicKey: packet.NewRSAPublicKey(currentTime, &encryptingPriv.PublicKey),
PrivateKey: packet.NewRSAPrivateKey(currentTime, encryptingPriv),
PublicKey: packet.NewRSAPublicKey(creationTime, &encryptingPriv.PublicKey),
PrivateKey: packet.NewRSAPrivateKey(creationTime, encryptingPriv),
Sig: &packet.Signature{
CreationTime: currentTime,
CreationTime: creationTime,
SigType: packet.SigTypeSubkeyBinding,
PubKeyAlgo: packet.PubKeyAlgoRSA,
Hash: config.Hash(),

View File

@ -32,7 +32,7 @@ func TestOpaqueParseReason(t *testing.T) {
break
}
// try to parse opaque packet
p, err := op.Parse()
p, _ := op.Parse()
switch pkt := p.(type) {
case *UserId:
uid = pkt

View File

@ -36,49 +36,49 @@ type PrivateKey struct {
iv []byte
}
func NewRSAPrivateKey(currentTime time.Time, priv *rsa.PrivateKey) *PrivateKey {
func NewRSAPrivateKey(creationTime time.Time, priv *rsa.PrivateKey) *PrivateKey {
pk := new(PrivateKey)
pk.PublicKey = *NewRSAPublicKey(currentTime, &priv.PublicKey)
pk.PublicKey = *NewRSAPublicKey(creationTime, &priv.PublicKey)
pk.PrivateKey = priv
return pk
}
func NewDSAPrivateKey(currentTime time.Time, priv *dsa.PrivateKey) *PrivateKey {
func NewDSAPrivateKey(creationTime time.Time, priv *dsa.PrivateKey) *PrivateKey {
pk := new(PrivateKey)
pk.PublicKey = *NewDSAPublicKey(currentTime, &priv.PublicKey)
pk.PublicKey = *NewDSAPublicKey(creationTime, &priv.PublicKey)
pk.PrivateKey = priv
return pk
}
func NewElGamalPrivateKey(currentTime time.Time, priv *elgamal.PrivateKey) *PrivateKey {
func NewElGamalPrivateKey(creationTime time.Time, priv *elgamal.PrivateKey) *PrivateKey {
pk := new(PrivateKey)
pk.PublicKey = *NewElGamalPublicKey(currentTime, &priv.PublicKey)
pk.PublicKey = *NewElGamalPublicKey(creationTime, &priv.PublicKey)
pk.PrivateKey = priv
return pk
}
func NewECDSAPrivateKey(currentTime time.Time, priv *ecdsa.PrivateKey) *PrivateKey {
func NewECDSAPrivateKey(creationTime time.Time, priv *ecdsa.PrivateKey) *PrivateKey {
pk := new(PrivateKey)
pk.PublicKey = *NewECDSAPublicKey(currentTime, &priv.PublicKey)
pk.PublicKey = *NewECDSAPublicKey(creationTime, &priv.PublicKey)
pk.PrivateKey = priv
return pk
}
// NewSignerPrivateKey creates a PrivateKey from a crypto.Signer that
// implements RSA or ECDSA.
func NewSignerPrivateKey(currentTime time.Time, signer crypto.Signer) *PrivateKey {
func NewSignerPrivateKey(creationTime time.Time, signer crypto.Signer) *PrivateKey {
pk := new(PrivateKey)
// In general, the public Keys should be used as pointers. We still
// type-switch on the values, for backwards-compatibility.
switch pubkey := signer.Public().(type) {
case *rsa.PublicKey:
pk.PublicKey = *NewRSAPublicKey(currentTime, pubkey)
pk.PublicKey = *NewRSAPublicKey(creationTime, pubkey)
case rsa.PublicKey:
pk.PublicKey = *NewRSAPublicKey(currentTime, &pubkey)
pk.PublicKey = *NewRSAPublicKey(creationTime, &pubkey)
case *ecdsa.PublicKey:
pk.PublicKey = *NewECDSAPublicKey(currentTime, pubkey)
pk.PublicKey = *NewECDSAPublicKey(creationTime, pubkey)
case ecdsa.PublicKey:
pk.PublicKey = *NewECDSAPublicKey(currentTime, &pubkey)
pk.PublicKey = *NewECDSAPublicKey(creationTime, &pubkey)
default:
panic("openpgp: unknown crypto.Signer type in NewSignerPrivateKey")
}

View File

@ -4,6 +4,10 @@
// Package otr implements the Off The Record protocol as specified in
// http://www.cypherpunks.ca/otr/Protocol-v2-3.1.0.html
//
// The version of OTR implemented by this package has been deprecated
// (https://bugs.otr.im/lib/libotr/issues/140). An implementation of OTRv3 is
// available at https://github.com/coyim/otr3.
package otr // import "golang.org/x/crypto/otr"
import (
@ -637,7 +641,7 @@ func (c *Conversation) serializeDHKey() []byte {
}
func (c *Conversation) processDHKey(in []byte) (isSame bool, err error) {
gy, in, ok := getMPI(in)
gy, _, ok := getMPI(in)
if !ok {
err = errors.New("otr: corrupt DH key message")
return

View File

@ -7,6 +7,9 @@
// This implementation is distilled from https://tools.ietf.org/html/rfc7292
// and referenced documents. It is intended for decoding P12/PFX-stored
// certificates and keys for use with the crypto/tls package.
//
// This package is frozen. If it's missing functionality you need, consider
// an alternative like software.sslmate.com/src/go-pkcs12.
package pkcs12
import (
@ -100,7 +103,7 @@ func unmarshal(in []byte, out interface{}) error {
return nil
}
// ConvertToPEM converts all "safe bags" contained in pfxData to PEM blocks.
// ToPEM converts all "safe bags" contained in pfxData to PEM blocks.
func ToPEM(pfxData []byte, password string) ([]*pem.Block, error) {
encodedPassword, err := bmpString(password)
if err != nil {
@ -208,7 +211,7 @@ func convertAttribute(attribute *pkcs12Attribute) (key, value string, err error)
// Decode extracts a certificate and private key from pfxData. This function
// assumes that there is only one certificate and only one private key in the
// pfxData.
// pfxData; if there are more use ToPEM instead.
func Decode(pfxData []byte, password string) (privateKey interface{}, certificate *x509.Certificate, err error) {
encodedPassword, err := bmpString(password)
if err != nil {

View File

@ -2,8 +2,10 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !windows
// +build !amd64 gccgo appengine
package source
package poly1305
const fileSchemePrefix = "file://"
type mac struct{ macGeneric }
func newMAC(key *[32]byte) mac { return mac{newMACGeneric(key)} }

View File

@ -2,21 +2,19 @@
// 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 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"
@ -31,3 +29,55 @@ func Verify(mac *[16]byte, m []byte, key *[32]byte) bool {
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[:]...)
}

View File

@ -100,7 +100,50 @@ func TestSumUnaligned(t *testing.T) { testSum(t, true, Sum) }
func TestSumGeneric(t *testing.T) { testSum(t, false, sumGeneric) }
func TestSumGenericUnaligned(t *testing.T) { testSum(t, true, sumGeneric) }
func benchmark(b *testing.B, size int, unaligned bool) {
func TestWriteGeneric(t *testing.T) { testWriteGeneric(t, false) }
func TestWriteGenericUnaligned(t *testing.T) { testWriteGeneric(t, true) }
func TestWrite(t *testing.T) { testWrite(t, false) }
func TestWriteUnaligned(t *testing.T) { testWrite(t, true) }
func testWriteGeneric(t *testing.T, unaligned bool) {
for i, v := range testData {
key := v.Key()
input := v.Input()
var out [16]byte
if unaligned {
input = unalignBytes(input)
}
h := newMACGeneric(&key)
h.Write(input[:len(input)/2])
h.Write(input[len(input)/2:])
h.Sum(&out)
if tag := v.Tag(); out != tag {
t.Errorf("%d: expected %x, got %x", i, tag[:], out[:])
}
}
}
func testWrite(t *testing.T, unaligned bool) {
for i, v := range testData {
key := v.Key()
input := v.Input()
var out [16]byte
if unaligned {
input = unalignBytes(input)
}
h := New(&key)
h.Write(input[:len(input)/2])
h.Write(input[len(input)/2:])
h.Sum(out[:0])
if tag := v.Tag(); out != tag {
t.Errorf("%d: expected %x, got %x", i, tag[:], out[:])
}
}
}
func benchmarkSum(b *testing.B, size int, unaligned bool) {
var out [16]byte
var key [32]byte
in := make([]byte, size)
@ -114,11 +157,33 @@ func benchmark(b *testing.B, size int, unaligned bool) {
}
}
func Benchmark64(b *testing.B) { benchmark(b, 64, false) }
func Benchmark1K(b *testing.B) { benchmark(b, 1024, false) }
func Benchmark64Unaligned(b *testing.B) { benchmark(b, 64, true) }
func Benchmark1KUnaligned(b *testing.B) { benchmark(b, 1024, true) }
func Benchmark2M(b *testing.B) { benchmark(b, 2097152, true) }
func benchmarkWrite(b *testing.B, size int, unaligned bool) {
var key [32]byte
h := New(&key)
in := make([]byte, size)
if unaligned {
in = unalignBytes(in)
}
b.SetBytes(int64(len(in)))
b.ResetTimer()
for i := 0; i < b.N; i++ {
h.Write(in)
}
}
func Benchmark64(b *testing.B) { benchmarkSum(b, 64, false) }
func Benchmark1K(b *testing.B) { benchmarkSum(b, 1024, false) }
func Benchmark2M(b *testing.B) { benchmarkSum(b, 2*1024*1024, false) }
func Benchmark64Unaligned(b *testing.B) { benchmarkSum(b, 64, true) }
func Benchmark1KUnaligned(b *testing.B) { benchmarkSum(b, 1024, true) }
func Benchmark2MUnaligned(b *testing.B) { benchmarkSum(b, 2*1024*1024, true) }
func BenchmarkWrite64(b *testing.B) { benchmarkWrite(b, 64, false) }
func BenchmarkWrite1K(b *testing.B) { benchmarkWrite(b, 1024, false) }
func BenchmarkWrite2M(b *testing.B) { benchmarkWrite(b, 2*1024*1024, false) }
func BenchmarkWrite64Unaligned(b *testing.B) { benchmarkWrite(b, 64, true) }
func BenchmarkWrite1KUnaligned(b *testing.B) { benchmarkWrite(b, 1024, true) }
func BenchmarkWrite2MUnaligned(b *testing.B) { benchmarkWrite(b, 2*1024*1024, true) }
func unalignBytes(in []byte) []byte {
out := make([]byte, len(in)+1)

View File

@ -6,17 +6,63 @@
package poly1305
// This function is implemented in sum_amd64.s
//go:noescape
func poly1305(out *[16]byte, m *byte, mlen uint64, key *[32]byte)
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) {
var mPtr *byte
if len(m) > 0 {
mPtr = &m[0]
}
poly1305(out, mPtr, uint64(len(m)), key)
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)
}

View File

@ -58,20 +58,17 @@ DATA ·poly1305Mask<>+0x00(SB)/8, $0x0FFFFFFC0FFFFFFF
DATA ·poly1305Mask<>+0x08(SB)/8, $0x0FFFFFFC0FFFFFFC
GLOBL ·poly1305Mask<>(SB), RODATA, $16
// func poly1305(out *[16]byte, m *byte, mlen uint64, key *[32]key)
TEXT ·poly1305(SB), $0-32
MOVQ out+0(FP), DI
MOVQ m+8(FP), SI
MOVQ mlen+16(FP), R15
MOVQ key+24(FP), AX
// 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(AX), R11
MOVQ 8(AX), R12
ANDQ ·poly1305Mask<>(SB), R11 // r0
ANDQ ·poly1305Mask<>+8(SB), R12 // r1
XORQ R8, R8 // h0
XORQ R9, R9 // h1
XORQ R10, R10 // h2
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
@ -109,16 +106,42 @@ flush_buffer:
JMP multiply
done:
MOVQ R8, AX
MOVQ R9, BX
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, R10
SBBQ $3, CX
CMOVQCS R8, AX
CMOVQCS R9, BX
MOVQ key+24(FP), R8
ADDQ 16(R8), AX
ADCQ 24(R8), BX
ADDQ 40(SI), AX
ADCQ 48(SI), BX
MOVQ AX, 0(DI)
MOVQ BX, 8(DI)

View File

@ -1,4 +1,4 @@
// Copyright 2012 The Go Authors. All rights reserved.
// 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.
@ -6,21 +6,79 @@ 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) {
var (
h0, h1, h2, h3, h4 uint32 // the hash accumulators
r0, r1, r2, r3, r4 uint64 // the r part of the key
)
h := newMACGeneric(key)
h.Write(msg)
h.Sum(out)
}
r0 = uint64(binary.LittleEndian.Uint32(key[0:]) & 0x3ffffff)
r1 = uint64((binary.LittleEndian.Uint32(key[3:]) >> 2) & 0x3ffff03)
r2 = uint64((binary.LittleEndian.Uint32(key[6:]) >> 4) & 0x3ffc0ff)
r3 = uint64((binary.LittleEndian.Uint32(key[9:]) >> 6) & 0x3f03fff)
r4 = uint64((binary.LittleEndian.Uint32(key[12:]) >> 8) & 0x00fffff)
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 {
@ -29,7 +87,7 @@ func sumGeneric(out *[TagSize]byte, msg []byte, key *[32]byte) {
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) | (1 << 24)
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)
@ -52,36 +110,11 @@ func sumGeneric(out *[TagSize]byte, msg []byte, key *[32]byte) {
msg = msg[TagSize:]
}
if len(msg) > 0 {
var block [TagSize]byte
off := copy(block[:], msg)
block[off] = 0x01
h[0], h[1], h[2], h[3], h[4] = h0, h1, h2, h3, h4
}
// h += msg
h0 += binary.LittleEndian.Uint32(block[0:]) & 0x3ffffff
h1 += (binary.LittleEndian.Uint32(block[3:]) >> 2) & 0x3ffffff
h2 += (binary.LittleEndian.Uint32(block[6:]) >> 4) & 0x3ffffff
h3 += (binary.LittleEndian.Uint32(block[9:]) >> 6) & 0x3ffffff
h4 += (binary.LittleEndian.Uint32(block[12:]) >> 8)
// 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
}
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
@ -123,13 +156,13 @@ func sumGeneric(out *[TagSize]byte, msg []byte, key *[32]byte) {
// s: the s part of the key
// tag = (h + s) % (2^128)
t := uint64(h0) + uint64(binary.LittleEndian.Uint32(key[16:]))
t := uint64(h0) + uint64(s[0])
h0 = uint32(t)
t = uint64(h1) + uint64(binary.LittleEndian.Uint32(key[20:])) + (t >> 32)
t = uint64(h1) + uint64(s[1]) + (t >> 32)
h1 = uint32(t)
t = uint64(h2) + uint64(binary.LittleEndian.Uint32(key[24:])) + (t >> 32)
t = uint64(h2) + uint64(s[2]) + (t >> 32)
h2 = uint32(t)
t = uint64(h3) + uint64(binary.LittleEndian.Uint32(key[28:])) + (t >> 32)
t = uint64(h3) + uint64(s[3]) + (t >> 32)
h3 = uint32(t)
binary.LittleEndian.PutUint32(out[0:], h0)

View File

@ -10,5 +10,7 @@ package poly1305
// 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) {
sumGeneric(out, msg, key)
h := newMAC(key)
h.Write(msg)
h.Sum(out)
}

View File

@ -6,16 +6,9 @@
package poly1305
// hasVectorFacility reports whether the machine supports
// the vector facility (vx).
func hasVectorFacility() bool
// hasVMSLFacility reports whether the machine supports
// Vector Multiply Sum Logical (VMSL).
func hasVMSLFacility() bool
var hasVX = hasVectorFacility()
var hasVMSL = hasVMSLFacility()
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
@ -33,12 +26,12 @@ func poly1305vmsl(out *[16]byte, m *byte, mlen uint64, key *[32]byte)
// 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 hasVX {
if cpu.S390X.HasVX {
var mPtr *byte
if len(m) > 0 {
mPtr = &m[0]
}
if hasVMSL && len(m) > 256 {
if cpu.S390X.HasVXE && len(m) > 256 {
poly1305vmsl(out, mPtr, uint64(len(m)), key)
} else {
poly1305vx(out, mPtr, uint64(len(m)), key)

View File

@ -376,25 +376,3 @@ b1:
MOVD $0, R3
BR multiply
TEXT ·hasVectorFacility(SB), NOSPLIT, $24-1
MOVD $x-24(SP), R1
XC $24, 0(R1), 0(R1) // clear the storage
MOVD $2, R0 // R0 is the number of double words stored -1
WORD $0xB2B01000 // STFLE 0(R1)
XOR R0, R0 // reset the value of R0
MOVBZ z-8(SP), R1
AND $0x40, R1
BEQ novector
vectorinstalled:
// check if the vector instruction has been enabled
VLEIB $0, $0xF, V16
VLGVB $0, V16, R1
CMPBNE R1, $0xF, novector
MOVB $1, ret+0(FP) // have vx
RET
novector:
MOVB $0, ret+0(FP) // no vx
RET

View File

@ -907,25 +907,3 @@ square:
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
TEXT ·hasVMSLFacility(SB), NOSPLIT, $24-1
MOVD $x-24(SP), R1
XC $24, 0(R1), 0(R1) // clear the storage
MOVD $2, R0 // R0 is the number of double words stored -1
WORD $0xB2B01000 // STFLE 0(R1)
XOR R0, R0 // reset the value of R0
MOVBZ z-8(SP), R1
AND $0x01, R1
BEQ novmsl
vectorinstalled:
// check if the vector instruction has been enabled
VLEIB $0, $0xF, V16
VLGVB $0, V16, R1
CMPBNE R1, $0xF, novmsl
MOVB $1, ret+0(FP) // have vx
RET
novmsl:
MOVB $0, ret+0(FP) // no vx
RET

View File

@ -3,6 +3,10 @@
// license that can be found in the LICENSE file.
// Package ripemd160 implements the RIPEMD-160 hash algorithm.
//
// Deprecated: RIPEMD-160 is a legacy hash and should not be used for new
// applications. Also, this package does not and will not provide an optimized
// implementation. Instead, use a modern hash like SHA-256 (from crypto/sha256).
package ripemd160 // import "golang.org/x/crypto/ripemd160"
// RIPEMD-160 is designed by Hans Dobbertin, Antoon Bosselaers, and Bart

View File

@ -6,10 +6,9 @@
package salsa
// This function is implemented in salsa2020_amd64.s.
//go:noescape
// salsa2020XORKeyStream is implemented in salsa20_amd64.s.
func salsa2020XORKeyStream(out, in *byte, n uint64, nonce, key *byte)
// XORKeyStream crypts bytes from in to out using the given key and counters.

View File

@ -99,30 +99,24 @@ TEXT ·salsa2020XORKeyStream(SB),0,$456-40 // frame = 424 + 32 byte alignment
MOVL 36 (SP),CX
MOVL DX,288(SP)
MOVL CX,304(SP)
ADDQ $1,DX
SHLQ $32,CX
ADDQ CX,DX
ADDQ $1,DX
MOVQ DX,CX
SHRQ $32,CX
MOVL DX, 292 (SP)
MOVL CX, 308 (SP)
ADDQ $1,DX
SHLQ $32,CX
ADDQ CX,DX
MOVQ DX,CX
SHRQ $32,CX
MOVL DX, 296 (SP)
MOVL CX, 312 (SP)
ADDQ $1,DX
SHLQ $32,CX
ADDQ CX,DX
MOVQ DX,CX
SHRQ $32,CX
MOVL DX, 300 (SP)
MOVL CX, 316 (SP)
ADDQ $1,DX
SHLQ $32,CX
ADDQ CX,DX
MOVQ DX,CX
SHRQ $32,CX
MOVL DX,16(SP)

View File

@ -0,0 +1,31 @@
// 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 amd64,!appengine,!gccgo
package salsa
import (
"bytes"
"testing"
)
func TestCounterOverflow(t *testing.T) {
in := make([]byte, 4096)
key := &[32]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5,
6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2}
for n, counter := range []*[16]byte{
&[16]byte{0, 1, 2, 3, 4, 5, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0}, // zero counter
&[16]byte{0, 1, 2, 3, 4, 5, 6, 7, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff}, // counter about to overflow 32 bits
&[16]byte{0, 1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 0xff, 0xff, 0xff, 0xff}, // counter above 32 bits
} {
out := make([]byte, 4096)
XORKeyStream(out, in, counter, key)
outGeneric := make([]byte, 4096)
genericXORKeyStream(outGeneric, in, counter, key)
if !bytes.Equal(out, outGeneric) {
t.Errorf("%d: assembly and go implementations disagree", n)
}
}
}

View File

@ -0,0 +1,14 @@
// 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 !amd64 appengine gccgo
package salsa
// 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 salsa20 counter bytes (both nonce and block counter).
func XORKeyStream(out, in []byte, counter *[16]byte, key *[32]byte) {
genericXORKeyStream(out, in, counter, key)
}

View File

@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !amd64 appengine gccgo
package salsa
const rounds = 20
@ -202,10 +200,9 @@ func core(out *[64]byte, in *[16]byte, k *[32]byte, c *[16]byte) {
out[63] = byte(x15 >> 24)
}
// 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 salsa20 counter bytes (both nonce and block counter).
func XORKeyStream(out, in []byte, counter *[16]byte, key *[32]byte) {
// genericXORKeyStream is the generic implementation of XORKeyStream to be used
// when no assembly implementation is available.
func genericXORKeyStream(out, in []byte, counter *[16]byte, key *[32]byte) {
var block [64]byte
var counterCopy [16]byte
copy(counterCopy[:], counter[:])

View File

@ -10,6 +10,7 @@ package scrypt // import "golang.org/x/crypto/scrypt"
import (
"crypto/sha256"
"errors"
"math/bits"
"golang.org/x/crypto/pbkdf2"
)
@ -52,77 +53,45 @@ func salsaXOR(tmp *[16]uint32, in, out []uint32) {
x9, x10, x11, x12, x13, x14, x15 := w9, w10, w11, w12, w13, w14, w15
for i := 0; i < 8; i += 2 {
u := x0 + x12
x4 ^= u<<7 | u>>(32-7)
u = x4 + x0
x8 ^= u<<9 | u>>(32-9)
u = x8 + x4
x12 ^= u<<13 | u>>(32-13)
u = x12 + x8
x0 ^= u<<18 | u>>(32-18)
x4 ^= bits.RotateLeft32(x0+x12, 7)
x8 ^= bits.RotateLeft32(x4+x0, 9)
x12 ^= bits.RotateLeft32(x8+x4, 13)
x0 ^= bits.RotateLeft32(x12+x8, 18)
u = x5 + x1
x9 ^= u<<7 | u>>(32-7)
u = x9 + x5
x13 ^= u<<9 | u>>(32-9)
u = x13 + x9
x1 ^= u<<13 | u>>(32-13)
u = x1 + x13
x5 ^= u<<18 | u>>(32-18)
x9 ^= bits.RotateLeft32(x5+x1, 7)
x13 ^= bits.RotateLeft32(x9+x5, 9)
x1 ^= bits.RotateLeft32(x13+x9, 13)
x5 ^= bits.RotateLeft32(x1+x13, 18)
u = x10 + x6
x14 ^= u<<7 | u>>(32-7)
u = x14 + x10
x2 ^= u<<9 | u>>(32-9)
u = x2 + x14
x6 ^= u<<13 | u>>(32-13)
u = x6 + x2
x10 ^= u<<18 | u>>(32-18)
x14 ^= bits.RotateLeft32(x10+x6, 7)
x2 ^= bits.RotateLeft32(x14+x10, 9)
x6 ^= bits.RotateLeft32(x2+x14, 13)
x10 ^= bits.RotateLeft32(x6+x2, 18)
u = x15 + x11
x3 ^= u<<7 | u>>(32-7)
u = x3 + x15
x7 ^= u<<9 | u>>(32-9)
u = x7 + x3
x11 ^= u<<13 | u>>(32-13)
u = x11 + x7
x15 ^= u<<18 | u>>(32-18)
x3 ^= bits.RotateLeft32(x15+x11, 7)
x7 ^= bits.RotateLeft32(x3+x15, 9)
x11 ^= bits.RotateLeft32(x7+x3, 13)
x15 ^= bits.RotateLeft32(x11+x7, 18)
u = x0 + x3
x1 ^= u<<7 | u>>(32-7)
u = x1 + x0
x2 ^= u<<9 | u>>(32-9)
u = x2 + x1
x3 ^= u<<13 | u>>(32-13)
u = x3 + x2
x0 ^= u<<18 | u>>(32-18)
x1 ^= bits.RotateLeft32(x0+x3, 7)
x2 ^= bits.RotateLeft32(x1+x0, 9)
x3 ^= bits.RotateLeft32(x2+x1, 13)
x0 ^= bits.RotateLeft32(x3+x2, 18)
u = x5 + x4
x6 ^= u<<7 | u>>(32-7)
u = x6 + x5
x7 ^= u<<9 | u>>(32-9)
u = x7 + x6
x4 ^= u<<13 | u>>(32-13)
u = x4 + x7
x5 ^= u<<18 | u>>(32-18)
x6 ^= bits.RotateLeft32(x5+x4, 7)
x7 ^= bits.RotateLeft32(x6+x5, 9)
x4 ^= bits.RotateLeft32(x7+x6, 13)
x5 ^= bits.RotateLeft32(x4+x7, 18)
u = x10 + x9
x11 ^= u<<7 | u>>(32-7)
u = x11 + x10
x8 ^= u<<9 | u>>(32-9)
u = x8 + x11
x9 ^= u<<13 | u>>(32-13)
u = x9 + x8
x10 ^= u<<18 | u>>(32-18)
x11 ^= bits.RotateLeft32(x10+x9, 7)
x8 ^= bits.RotateLeft32(x11+x10, 9)
x9 ^= bits.RotateLeft32(x8+x11, 13)
x10 ^= bits.RotateLeft32(x9+x8, 18)
u = x15 + x14
x12 ^= u<<7 | u>>(32-7)
u = x12 + x15
x13 ^= u<<9 | u>>(32-9)
u = x13 + x12
x14 ^= u<<13 | u>>(32-13)
u = x14 + x13
x15 ^= u<<18 | u>>(32-18)
x12 ^= bits.RotateLeft32(x15+x14, 7)
x13 ^= bits.RotateLeft32(x12+x15, 9)
x14 ^= bits.RotateLeft32(x13+x12, 13)
x15 ^= bits.RotateLeft32(x14+x13, 18)
}
x0 += w0
x1 += w1

View File

@ -58,6 +58,12 @@ func New512() hash.Hash {
// that uses non-standard padding. All other users should use New256 instead.
func NewLegacyKeccak256() hash.Hash { return &state{rate: 136, outputLen: 32, dsbyte: 0x01} }
// NewLegacyKeccak512 creates a new Keccak-512 hash.
//
// Only use this function if you require compatibility with an existing cryptosystem
// that uses non-standard padding. All other users should use New512 instead.
func NewLegacyKeccak512() hash.Hash { return &state{rate: 72, outputLen: 64, dsbyte: 0x01} }
// Sum224 returns the SHA3-224 digest of the data.
func Sum224(data []byte) (digest [28]byte) {
h := New224()

View File

@ -12,6 +12,8 @@ package sha3
import (
"hash"
"golang.org/x/sys/cpu"
)
// codes represent 7-bit KIMD/KLMD function codes as defined in
@ -29,13 +31,6 @@ const (
nopad = 0x100
)
// hasMSA6 reports whether the machine supports the SHA-3 and SHAKE function
// codes, as defined in message-security-assist extension 6.
func hasMSA6() bool
// hasAsm caches the result of hasMSA6 (which might be expensive to call).
var hasAsm = hasMSA6()
// kimd is a wrapper for the 'compute intermediate message digest' instruction.
// src must be a multiple of the rate for the given function code.
//go:noescape
@ -237,7 +232,7 @@ func (s *asmState) Clone() ShakeHash {
// new224Asm returns an assembly implementation of SHA3-224 if available,
// otherwise it returns nil.
func new224Asm() hash.Hash {
if hasAsm {
if cpu.S390X.HasSHA3 {
return newAsmState(sha3_224)
}
return nil
@ -246,7 +241,7 @@ func new224Asm() hash.Hash {
// new256Asm returns an assembly implementation of SHA3-256 if available,
// otherwise it returns nil.
func new256Asm() hash.Hash {
if hasAsm {
if cpu.S390X.HasSHA3 {
return newAsmState(sha3_256)
}
return nil
@ -255,7 +250,7 @@ func new256Asm() hash.Hash {
// new384Asm returns an assembly implementation of SHA3-384 if available,
// otherwise it returns nil.
func new384Asm() hash.Hash {
if hasAsm {
if cpu.S390X.HasSHA3 {
return newAsmState(sha3_384)
}
return nil
@ -264,7 +259,7 @@ func new384Asm() hash.Hash {
// new512Asm returns an assembly implementation of SHA3-512 if available,
// otherwise it returns nil.
func new512Asm() hash.Hash {
if hasAsm {
if cpu.S390X.HasSHA3 {
return newAsmState(sha3_512)
}
return nil
@ -273,7 +268,7 @@ func new512Asm() hash.Hash {
// newShake128Asm returns an assembly implementation of SHAKE-128 if available,
// otherwise it returns nil.
func newShake128Asm() ShakeHash {
if hasAsm {
if cpu.S390X.HasSHA3 {
return newAsmState(shake_128)
}
return nil
@ -282,7 +277,7 @@ func newShake128Asm() ShakeHash {
// newShake256Asm returns an assembly implementation of SHAKE-256 if available,
// otherwise it returns nil.
func newShake256Asm() ShakeHash {
if hasAsm {
if cpu.S390X.HasSHA3 {
return newAsmState(shake_256)
}
return nil

View File

@ -6,26 +6,10 @@
#include "textflag.h"
TEXT ·hasMSA6(SB), NOSPLIT, $16-1
MOVD $0, R0 // KIMD-Query function code
MOVD $tmp-16(SP), R1 // parameter block
XC $16, (R1), (R1) // clear the parameter block
WORD $0xB93E0002 // KIMD --, --
WORD $0x91FC1004 // TM 4(R1), 0xFC (test bits [32-37])
BVS yes
no:
MOVB $0, ret+0(FP)
RET
yes:
MOVB $1, ret+0(FP)
RET
// func kimd(function code, params *[200]byte, src []byte)
// func kimd(function code, chain *[200]byte, src []byte)
TEXT ·kimd(SB), NOFRAME|NOSPLIT, $0-40
MOVD function+0(FP), R0
MOVD params+8(FP), R1
MOVD chain+8(FP), R1
LMG src+16(FP), R2, R3 // R2=base, R3=len
continue:
@ -34,11 +18,11 @@ continue:
MOVD $0, R0 // reset R0 for pre-go1.8 compilers
RET
// func klmd(function code, params *[200]byte, dst, src []byte)
// func klmd(function code, chain *[200]byte, dst, src []byte)
TEXT ·klmd(SB), NOFRAME|NOSPLIT, $0-64
// TODO: SHAKE support
MOVD function+0(FP), R0
MOVD params+8(FP), R1
MOVD chain+8(FP), R1
LMG dst+16(FP), R2, R3 // R2=base, R3=len
LMG src+40(FP), R4, R5 // R4=base, R5=len

View File

@ -27,14 +27,6 @@ const (
katFilename = "testdata/keccakKats.json.deflate"
)
// Internal-use instances of SHAKE used to test against KATs.
func newHashShake128() hash.Hash {
return &state{rate: 168, dsbyte: 0x1f, outputLen: 512}
}
func newHashShake256() hash.Hash {
return &state{rate: 136, dsbyte: 0x1f, outputLen: 512}
}
// testDigests contains functions returning hash.Hash instances
// with output-length equal to the KAT length for SHA-3, Keccak
// and SHAKE instances.
@ -44,15 +36,21 @@ var testDigests = map[string]func() hash.Hash{
"SHA3-384": New384,
"SHA3-512": New512,
"Keccak-256": NewLegacyKeccak256,
"SHAKE128": newHashShake128,
"SHAKE256": newHashShake256,
"Keccak-512": NewLegacyKeccak512,
}
// testShakes contains functions that return ShakeHash instances for
// testing the ShakeHash-specific interface.
var testShakes = map[string]func() ShakeHash{
"SHAKE128": NewShake128,
"SHAKE256": NewShake256,
// testShakes contains functions that return sha3.ShakeHash instances for
// with output-length equal to the KAT length.
var testShakes = map[string]struct {
constructor func(N []byte, S []byte) ShakeHash
defAlgoName string
defCustomStr string
}{
// NewCShake without customization produces same result as SHAKE
"SHAKE128": {NewCShake128, "", ""},
"SHAKE256": {NewCShake256, "", ""},
"cSHAKE128": {NewCShake128, "CSHAKE128", "CustomStrign"},
"cSHAKE256": {NewCShake256, "CSHAKE256", "CustomStrign"},
}
// decodeHex converts a hex-encoded string into a raw byte string.
@ -70,6 +68,10 @@ type KeccakKats struct {
Digest string `json:"digest"`
Length int64 `json:"length"`
Message string `json:"message"`
// Defined only for cSHAKE
N string `json:"N"`
S string `json:"S"`
}
}
@ -102,10 +104,9 @@ func TestKeccakKats(t *testing.T) {
t.Errorf("error decoding KATs: %s", err)
}
// Do the KATs.
for functionName, kats := range katSet.Kats {
d := testDigests[functionName]()
for _, kat := range kats {
for algo, function := range testDigests {
d := function()
for _, kat := range katSet.Kats[algo] {
d.Reset()
in, err := hex.DecodeString(kat.Message)
if err != nil {
@ -114,8 +115,39 @@ func TestKeccakKats(t *testing.T) {
d.Write(in[:kat.Length/8])
got := strings.ToUpper(hex.EncodeToString(d.Sum(nil)))
if got != kat.Digest {
t.Errorf("function=%s, implementation=%s, length=%d\nmessage:\n %s\ngot:\n %s\nwanted:\n %s",
functionName, impl, kat.Length, kat.Message, got, kat.Digest)
t.Errorf("function=%s, implementation=%s, length=%d\nmessage:\n %s\ngot:\n %s\nwanted:\n %s",
algo, impl, kat.Length, kat.Message, got, kat.Digest)
t.Logf("wanted %+v", kat)
t.FailNow()
}
continue
}
}
for algo, v := range testShakes {
for _, kat := range katSet.Kats[algo] {
N, err := hex.DecodeString(kat.N)
if err != nil {
t.Errorf("error decoding KAT: %s", err)
}
S, err := hex.DecodeString(kat.S)
if err != nil {
t.Errorf("error decoding KAT: %s", err)
}
d := v.constructor(N, S)
in, err := hex.DecodeString(kat.Message)
if err != nil {
t.Errorf("error decoding KAT: %s", err)
}
d.Write(in[:kat.Length/8])
out := make([]byte, len(kat.Digest)/2)
d.Read(out)
got := strings.ToUpper(hex.EncodeToString(out))
if got != kat.Digest {
t.Errorf("function=%s, implementation=%s, length=%d N:%s\n S:%s\nmessage:\n %s \ngot:\n %s\nwanted:\n %s",
algo, impl, kat.Length, kat.N, kat.S, kat.Message, got, kat.Digest)
t.Logf("wanted %+v", kat)
t.FailNow()
}
@ -137,6 +169,11 @@ func TestKeccak(t *testing.T) {
[]byte("abc"),
"4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45",
},
{
NewLegacyKeccak512,
[]byte("abc"),
"18587dc2ea106b9a1563e32b3312421ca164c7f1f07bc922a9c83d77cea3a1e5d0c69910739025372dc14ac9642629379540c17e2a65b19d77aa511a9d00bb96",
},
}
for _, u := range tests {
@ -178,6 +215,34 @@ func TestUnalignedWrite(t *testing.T) {
t.Errorf("Unaligned writes, implementation=%s, alg=%s\ngot %q, want %q", impl, alg, got, want)
}
}
// Same for SHAKE
for alg, df := range testShakes {
want := make([]byte, 16)
got := make([]byte, 16)
d := df.constructor([]byte(df.defAlgoName), []byte(df.defCustomStr))
d.Reset()
d.Write(buf)
d.Read(want)
d.Reset()
for i := 0; i < len(buf); {
// Cycle through offsets which make a 137 byte sequence.
// Because 137 is prime this sequence should exercise all corner cases.
offsets := [17]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1}
for _, j := range offsets {
if v := len(buf) - i; v < j {
j = v
}
d.Write(buf[i : i+j])
i += j
}
}
d.Read(got)
if !bytes.Equal(got, want) {
t.Errorf("Unaligned writes, implementation=%s, alg=%s\ngot %q, want %q", impl, alg, got, want)
}
}
})
}
@ -219,13 +284,13 @@ func TestAppendNoRealloc(t *testing.T) {
// the same output as repeatedly squeezing the instance.
func TestSqueezing(t *testing.T) {
testUnalignedAndGeneric(t, func(impl string) {
for functionName, newShakeHash := range testShakes {
d0 := newShakeHash()
for algo, v := range testShakes {
d0 := v.constructor([]byte(v.defAlgoName), []byte(v.defCustomStr))
d0.Write([]byte(testString))
ref := make([]byte, 32)
d0.Read(ref)
d1 := newShakeHash()
d1 := v.constructor([]byte(v.defAlgoName), []byte(v.defCustomStr))
d1.Write([]byte(testString))
var multiple []byte
for range ref {
@ -234,7 +299,7 @@ func TestSqueezing(t *testing.T) {
multiple = append(multiple, one...)
}
if !bytes.Equal(ref, multiple) {
t.Errorf("%s (%s): squeezing %d bytes one at a time failed", functionName, impl, len(ref))
t.Errorf("%s (%s): squeezing %d bytes one at a time failed", algo, impl, len(ref))
}
}
})
@ -249,6 +314,50 @@ func sequentialBytes(size int) []byte {
return result
}
func TestReset(t *testing.T) {
out1 := make([]byte, 32)
out2 := make([]byte, 32)
for _, v := range testShakes {
// Calculate hash for the first time
c := v.constructor(nil, []byte{0x99, 0x98})
c.Write(sequentialBytes(0x100))
c.Read(out1)
// Calculate hash again
c.Reset()
c.Write(sequentialBytes(0x100))
c.Read(out2)
if !bytes.Equal(out1, out2) {
t.Error("\nExpected:\n", out1, "\ngot:\n", out2)
}
}
}
func TestClone(t *testing.T) {
out1 := make([]byte, 16)
out2 := make([]byte, 16)
in := sequentialBytes(0x100)
for _, v := range testShakes {
h1 := v.constructor(nil, []byte{0x01})
h1.Write([]byte{0x01})
h2 := h1.Clone()
h1.Write(in)
h1.Read(out1)
h2.Write(in)
h2.Read(out2)
if !bytes.Equal(out1, out2) {
t.Error("\nExpected:\n", hex.EncodeToString(out1), "\ngot:\n", hex.EncodeToString(out2))
}
}
}
// BenchmarkPermutationFunction measures the speed of the permutation function
// with no input data.
func BenchmarkPermutationFunction(b *testing.B) {
@ -335,3 +444,37 @@ func Example_mac() {
fmt.Printf("%x\n", h)
// Output: 78de2974bd2711d5549ffd32b753ef0f5fa80a0db2556db60f0987eb8a9218ff
}
func ExampleNewCShake256() {
out := make([]byte, 32)
msg := []byte("The quick brown fox jumps over the lazy dog")
// Example 1: Simple cshake
c1 := NewCShake256([]byte("NAME"), []byte("Partition1"))
c1.Write(msg)
c1.Read(out)
fmt.Println(hex.EncodeToString(out))
// Example 2: Different customization string produces different digest
c1 = NewCShake256([]byte("NAME"), []byte("Partition2"))
c1.Write(msg)
c1.Read(out)
fmt.Println(hex.EncodeToString(out))
// Example 3: Longer output length produces longer digest
out = make([]byte, 64)
c1 = NewCShake256([]byte("NAME"), []byte("Partition1"))
c1.Write(msg)
c1.Read(out)
fmt.Println(hex.EncodeToString(out))
// Example 4: Next read produces different result
c1.Read(out)
fmt.Println(hex.EncodeToString(out))
// Output:
//a90a4c6ca9af2156eba43dc8398279e6b60dcd56fb21837afe6c308fd4ceb05b
//a8db03e71f3e4da5c4eee9d28333cdd355f51cef3c567e59be5beb4ecdbb28f0
//a90a4c6ca9af2156eba43dc8398279e6b60dcd56fb21837afe6c308fd4ceb05b9dd98c6ee866ca7dc5a39d53e960f400bcd5a19c8a2d6ec6459f63696543a0d8
//85e73a72228d08b46515553ca3a29d47df3047e5d84b12d6c2c63e579f4fd1105716b7838e92e981863907f434bfd4443c9e56ea09da998d2f9b47db71988109
}

View File

@ -5,10 +5,18 @@
package sha3
// This file defines the ShakeHash interface, and provides
// functions for creating SHAKE instances, as well as utility
// functions for creating SHAKE and cSHAKE instances, as well as utility
// functions for hashing bytes to arbitrary-length output.
//
//
// SHAKE implementation is based on FIPS PUB 202 [1]
// cSHAKE implementations is based on NIST SP 800-185 [2]
//
// [1] https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf
// [2] https://doi.org/10.6028/NIST.SP.800-185
import (
"encoding/binary"
"io"
)
@ -31,8 +39,77 @@ type ShakeHash interface {
Reset()
}
func (d *state) Clone() ShakeHash {
return d.clone()
// cSHAKE specific context
type cshakeState struct {
state // SHA-3 state context and Read/Write operations
// initBlock is the cSHAKE specific initialization set of bytes. It is initialized
// by newCShake function and stores concatenation of N followed by S, encoded
// by the method specified in 3.3 of [1].
// It is stored here in order for Reset() to be able to put context into
// initial state.
initBlock []byte
}
// Consts for configuring initial SHA-3 state
const (
dsbyteShake = 0x1f
dsbyteCShake = 0x04
rate128 = 168
rate256 = 136
)
func bytepad(input []byte, w int) []byte {
// leftEncode always returns max 9 bytes
buf := make([]byte, 0, 9+len(input)+w)
buf = append(buf, leftEncode(uint64(w))...)
buf = append(buf, input...)
padlen := w - (len(buf) % w)
return append(buf, make([]byte, padlen)...)
}
func leftEncode(value uint64) []byte {
var b [9]byte
binary.BigEndian.PutUint64(b[1:], value)
// Trim all but last leading zero bytes
i := byte(1)
for i < 8 && b[i] == 0 {
i++
}
// Prepend number of encoded bytes
b[i-1] = 9 - i
return b[i-1:]
}
func newCShake(N, S []byte, rate int, dsbyte byte) ShakeHash {
c := cshakeState{state: state{rate: rate, dsbyte: dsbyte}}
// leftEncode returns max 9 bytes
c.initBlock = make([]byte, 0, 9*2+len(N)+len(S))
c.initBlock = append(c.initBlock, leftEncode(uint64(len(N)*8))...)
c.initBlock = append(c.initBlock, N...)
c.initBlock = append(c.initBlock, leftEncode(uint64(len(S)*8))...)
c.initBlock = append(c.initBlock, S...)
c.Write(bytepad(c.initBlock, c.rate))
return &c
}
// Reset resets the hash to initial state.
func (c *cshakeState) Reset() {
c.state.Reset()
c.Write(bytepad(c.initBlock, c.rate))
}
// Clone returns copy of a cSHAKE context within its current state.
func (c *cshakeState) Clone() ShakeHash {
b := make([]byte, len(c.initBlock))
copy(b, c.initBlock)
return &cshakeState{state: *c.clone(), initBlock: b}
}
// Clone returns copy of SHAKE context within its current state.
func (c *state) Clone() ShakeHash {
return c.clone()
}
// NewShake128 creates a new SHAKE128 variable-output-length ShakeHash.
@ -42,7 +119,7 @@ func NewShake128() ShakeHash {
if h := newShake128Asm(); h != nil {
return h
}
return &state{rate: 168, dsbyte: 0x1f}
return &state{rate: rate128, dsbyte: dsbyteShake}
}
// NewShake256 creates a new SHAKE256 variable-output-length ShakeHash.
@ -52,7 +129,33 @@ func NewShake256() ShakeHash {
if h := newShake256Asm(); h != nil {
return h
}
return &state{rate: 136, dsbyte: 0x1f}
return &state{rate: rate256, dsbyte: dsbyteShake}
}
// NewCShake128 creates a new instance of cSHAKE128 variable-output-length ShakeHash,
// a customizable variant of SHAKE128.
// N is used to define functions based on cSHAKE, it can be empty when plain cSHAKE is
// desired. S is a customization byte string used for domain separation - two cSHAKE
// computations on same input with different S yield unrelated outputs.
// When N and S are both empty, this is equivalent to NewShake128.
func NewCShake128(N, S []byte) ShakeHash {
if len(N) == 0 && len(S) == 0 {
return NewShake128()
}
return newCShake(N, S, rate128, dsbyteCShake)
}
// NewCShake256 creates a new instance of cSHAKE256 variable-output-length ShakeHash,
// a customizable variant of SHAKE256.
// N is used to define functions based on cSHAKE, it can be empty when plain cSHAKE is
// desired. S is a customization byte string used for domain separation - two cSHAKE
// computations on same input with different S yield unrelated outputs.
// When N and S are both empty, this is equivalent to NewShake256.
func NewCShake256(N, S []byte) ShakeHash {
if len(N) == 0 && len(S) == 0 {
return NewShake256()
}
return newCShake(N, S, rate256, dsbyteCShake)
}
// ShakeSum128 writes an arbitrary-length digest of data into hash.

Binary file not shown.

View File

@ -8,11 +8,13 @@ import (
"bytes"
"crypto/rand"
"errors"
"io"
"net"
"os"
"os/exec"
"path/filepath"
"strconv"
"sync"
"testing"
"time"
@ -196,6 +198,63 @@ func testAgentInterface(t *testing.T, agent ExtendedAgent, key interface{}, cert
}
func TestMalformedRequests(t *testing.T) {
keyringAgent := NewKeyring()
listener, err := netListener()
if err != nil {
t.Fatalf("netListener: %v", err)
}
defer listener.Close()
testCase := func(t *testing.T, requestBytes []byte, wantServerErr bool) {
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
c, err := listener.Accept()
if err != nil {
t.Errorf("listener.Accept: %v", err)
return
}
defer c.Close()
err = ServeAgent(keyringAgent, c)
if err == nil {
t.Error("ServeAgent should have returned an error to malformed input")
} else {
if (err != io.EOF) != wantServerErr {
t.Errorf("ServeAgent returned expected error: %v", err)
}
}
}()
c, err := net.Dial("tcp", listener.Addr().String())
if err != nil {
t.Fatalf("net.Dial: %v", err)
}
_, err = c.Write(requestBytes)
if err != nil {
t.Errorf("Unexpected error writing raw bytes on connection: %v", err)
}
c.Close()
wg.Wait()
}
var testCases = []struct {
name string
requestBytes []byte
wantServerErr bool
}{
{"Empty request", []byte{}, false},
{"Short header", []byte{0x00}, true},
{"Empty body", []byte{0x00, 0x00, 0x00, 0x00}, true},
{"Short body", []byte{0x00, 0x00, 0x00, 0x01}, false},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) { testCase(t, tc.requestBytes, tc.wantServerErr) })
}
}
func TestAgent(t *testing.T) {
for _, keyType := range []string{"rsa", "dsa", "ecdsa", "ed25519"} {
testOpenSSHAgent(t, testPrivateKeys[keyType], nil, 0)
@ -215,17 +274,26 @@ func TestCert(t *testing.T) {
testKeyringAgent(t, testPrivateKeys["rsa"], cert, 0)
}
// netPipe is analogous to net.Pipe, but it uses a real net.Conn, and
// therefore is buffered (net.Pipe deadlocks if both sides start with
// a write.)
func netPipe() (net.Conn, net.Conn, error) {
// netListener creates a localhost network listener.
func netListener() (net.Listener, error) {
listener, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
listener, err = net.Listen("tcp", "[::1]:0")
if err != nil {
return nil, nil, err
return nil, err
}
}
return listener, nil
}
// netPipe is analogous to net.Pipe, but it uses a real net.Conn, and
// therefore is buffered (net.Pipe deadlocks if both sides start with
// a write.)
func netPipe() (net.Conn, net.Conn, error) {
listener, err := netListener()
if err != nil {
return nil, nil, err
}
defer listener.Close()
c1, err := net.Dial("tcp", listener.Addr().String())
if err != nil {
@ -444,14 +512,14 @@ func (r *keyringExtended) Extension(extensionType string, contents []byte) ([]by
func TestAgentExtensions(t *testing.T) {
agent, _, cleanup := startOpenSSHAgent(t)
defer cleanup()
result, err := agent.Extension("my-extension@example.com", []byte{0x00, 0x01, 0x02})
_, err := agent.Extension("my-extension@example.com", []byte{0x00, 0x01, 0x02})
if err == nil {
t.Fatal("should have gotten agent extension failure")
}
agent, cleanup = startAgent(t, &keyringExtended{})
defer cleanup()
result, err = agent.Extension("my-extension@example.com", []byte{0x00, 0x01, 0x02})
result, err := agent.Extension("my-extension@example.com", []byte{0x00, 0x01, 0x02})
if err != nil {
t.Fatalf("agent extension failure: %v", err)
}
@ -459,7 +527,7 @@ func TestAgentExtensions(t *testing.T) {
t.Fatalf("agent extension result invalid: %v", result)
}
result, err = agent.Extension("bad-extension@example.com", []byte{0x00, 0x01, 0x02})
_, err = agent.Extension("bad-extension@example.com", []byte{0x00, 0x01, 0x02})
if err == nil {
t.Fatal("should have gotten agent extension failure")
}

View File

@ -541,6 +541,9 @@ func ServeAgent(agent Agent, c io.ReadWriter) error {
return err
}
l := binary.BigEndian.Uint32(length[:])
if l == 0 {
return fmt.Errorf("agent: request size is 0")
}
if l > maxAgentResponseBytes {
// We also cap requests.
return fmt.Errorf("agent: request too large: %d", l)

View File

@ -93,6 +93,9 @@ func BenchmarkEndToEnd(b *testing.B) {
b.Fatalf("Client: %v", err)
}
ch, incoming, err := newCh.Accept()
if err != nil {
b.Fatalf("Accept: %v", err)
}
go DiscardRequests(incoming)
for i := 0; i < b.N; i++ {
if _, err := io.ReadFull(ch, output); err != nil {

View File

@ -149,8 +149,8 @@ type streamPacketCipher struct {
macResult []byte
}
// readPacket reads and decrypt a single packet from the reader argument.
func (s *streamPacketCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) {
// 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
}
@ -221,8 +221,8 @@ func (s *streamPacketCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, err
return s.packetData[:length-paddingLength-1], nil
}
// writePacket encrypts and sends a packet of data to the writer argument
func (s *streamPacketCipher) writePacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error {
// 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")
}
@ -327,7 +327,7 @@ func newGCMCipher(key, iv, unusedMacKey []byte, unusedAlgs directionAlgorithms)
const gcmTagSize = 16
func (c *gcmCipher) writePacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error {
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)
@ -370,7 +370,7 @@ func (c *gcmCipher) incIV() {
}
}
func (c *gcmCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) {
func (c *gcmCipher) readCipherPacket(seqNum uint32, r io.Reader) ([]byte, error) {
if _, err := io.ReadFull(r, c.prefix[:]); err != nil {
return nil, err
}
@ -486,8 +486,8 @@ type cbcError string
func (e cbcError) Error() string { return string(e) }
func (c *cbcCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) {
p, err := c.readPacketLeaky(seqNum, r)
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
@ -500,7 +500,7 @@ func (c *cbcCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) {
return p, err
}
func (c *cbcCipher) readPacketLeaky(seqNum uint32, r io.Reader) ([]byte, error) {
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
@ -576,7 +576,7 @@ func (c *cbcCipher) readPacketLeaky(seqNum uint32, r io.Reader) ([]byte, error)
return c.packetData[prefixLen:paddingStart], nil
}
func (c *cbcCipher) writePacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error {
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).
@ -665,7 +665,7 @@ func newChaCha20Cipher(key, unusedIV, unusedMACKey []byte, unusedAlgs directionA
return c, nil
}
func (c *chacha20Poly1305Cipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) {
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
@ -723,7 +723,7 @@ func (c *chacha20Poly1305Cipher) readPacket(seqNum uint32, r io.Reader) ([]byte,
return plain, nil
}
func (c *chacha20Poly1305Cipher) writePacket(seqNum uint32, w io.Writer, rand io.Reader, payload []byte) error {
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

View File

@ -56,13 +56,13 @@ func testPacketCipher(t *testing.T, cipher, mac string) {
want := "bla bla"
input := []byte(want)
buf := &bytes.Buffer{}
if err := client.writePacket(0, buf, rand.Reader, input); err != nil {
t.Fatalf("writePacket(%q, %q): %v", cipher, mac, err)
if err := client.writeCipherPacket(0, buf, rand.Reader, input); err != nil {
t.Fatalf("writeCipherPacket(%q, %q): %v", cipher, mac, err)
}
packet, err := server.readPacket(0, buf)
packet, err := server.readCipherPacket(0, buf)
if err != nil {
t.Fatalf("readPacket(%q, %q): %v", cipher, mac, err)
t.Fatalf("readCipherPacket(%q, %q): %v", cipher, mac, err)
}
if string(packet) != want {
@ -85,8 +85,8 @@ func TestCBCOracleCounterMeasure(t *testing.T) {
want := "bla bla"
input := []byte(want)
buf := &bytes.Buffer{}
if err := client.writePacket(0, buf, rand.Reader, input); err != nil {
t.Errorf("writePacket: %v", err)
if err := client.writeCipherPacket(0, buf, rand.Reader, input); err != nil {
t.Errorf("writeCipherPacket: %v", err)
}
packetSize := buf.Len()
@ -106,9 +106,9 @@ func TestCBCOracleCounterMeasure(t *testing.T) {
fresh.Bytes()[i] ^= 0x01
before := fresh.Len()
_, err = server.readPacket(0, fresh)
_, err = server.readCipherPacket(0, fresh)
if err == nil {
t.Errorf("corrupt byte %d: readPacket succeeded ", i)
t.Errorf("corrupt byte %d: readCipherPacket succeeded ", i)
continue
}
if _, ok := err.(cbcError); !ok {

View File

@ -10,6 +10,8 @@ import (
"errors"
"fmt"
"io"
"log"
"net"
"os"
"strings"
"testing"
@ -477,7 +479,7 @@ func TestRetryableAuth(t *testing.T) {
}
}
func ExampleRetryableAuthMethod(t *testing.T) {
func ExampleRetryableAuthMethod() {
user := "testuser"
NumberOfPrompts := 3
@ -495,9 +497,17 @@ func ExampleRetryableAuthMethod(t *testing.T) {
},
}
if err := tryAuth(t, config); err != nil {
t.Fatalf("unable to dial remote side: %s", err)
host := "mysshserver"
netConn, err := net.Dial("tcp", host)
if err != nil {
log.Fatal(err)
}
sshConn, _, _, err := NewClientConn(netConn, host, config)
if err != nil {
log.Fatal(err)
}
_ = sshConn
}
// Test if username is received on server side when NoClientAuth is used

View File

@ -109,6 +109,7 @@ func findCommon(what string, client []string, server []string) (common string, e
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
@ -137,7 +138,7 @@ type algorithms struct {
r directionAlgorithms
}
func findAgreedAlgorithms(clientKexInit, serverKexInit *kexInitMsg) (algs *algorithms, err error) {
func findAgreedAlgorithms(isClient bool, clientKexInit, serverKexInit *kexInitMsg) (algs *algorithms, err error) {
result := &algorithms{}
result.kex, err = findCommon("key exchange", clientKexInit.KexAlgos, serverKexInit.KexAlgos)
@ -150,32 +151,37 @@ func findAgreedAlgorithms(clientKexInit, serverKexInit *kexInitMsg) (algs *algor
return
}
result.w.Cipher, err = findCommon("client to server cipher", clientKexInit.CiphersClientServer, serverKexInit.CiphersClientServer)
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
}
result.r.Cipher, err = findCommon("server to client cipher", clientKexInit.CiphersServerClient, serverKexInit.CiphersServerClient)
stoc.Cipher, err = findCommon("server to client cipher", clientKexInit.CiphersServerClient, serverKexInit.CiphersServerClient)
if err != nil {
return
}
result.w.MAC, err = findCommon("client to server MAC", clientKexInit.MACsClientServer, serverKexInit.MACsClientServer)
ctos.MAC, err = findCommon("client to server MAC", clientKexInit.MACsClientServer, serverKexInit.MACsClientServer)
if err != nil {
return
}
result.r.MAC, err = findCommon("server to client MAC", clientKexInit.MACsServerClient, serverKexInit.MACsServerClient)
stoc.MAC, err = findCommon("server to client MAC", clientKexInit.MACsServerClient, serverKexInit.MACsServerClient)
if err != nil {
return
}
result.w.Compression, err = findCommon("client to server compression", clientKexInit.CompressionClientServer, serverKexInit.CompressionClientServer)
ctos.Compression, err = findCommon("client to server compression", clientKexInit.CompressionClientServer, serverKexInit.CompressionClientServer)
if err != nil {
return
}
result.r.Compression, err = findCommon("server to client compression", clientKexInit.CompressionServerClient, serverKexInit.CompressionServerClient)
stoc.Compression, err = findCommon("server to client compression", clientKexInit.CompressionServerClient, serverKexInit.CompressionServerClient)
if err != nil {
return
}

176
x/crypto/ssh/common_test.go Normal file
View File

@ -0,0 +1,176 @@
// 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 ssh
import (
"reflect"
"testing"
)
func TestFindAgreedAlgorithms(t *testing.T) {
initKex := func(k *kexInitMsg) {
if k.KexAlgos == nil {
k.KexAlgos = []string{"kex1"}
}
if k.ServerHostKeyAlgos == nil {
k.ServerHostKeyAlgos = []string{"hostkey1"}
}
if k.CiphersClientServer == nil {
k.CiphersClientServer = []string{"cipher1"}
}
if k.CiphersServerClient == nil {
k.CiphersServerClient = []string{"cipher1"}
}
if k.MACsClientServer == nil {
k.MACsClientServer = []string{"mac1"}
}
if k.MACsServerClient == nil {
k.MACsServerClient = []string{"mac1"}
}
if k.CompressionClientServer == nil {
k.CompressionClientServer = []string{"compression1"}
}
if k.CompressionServerClient == nil {
k.CompressionServerClient = []string{"compression1"}
}
if k.LanguagesClientServer == nil {
k.LanguagesClientServer = []string{"language1"}
}
if k.LanguagesServerClient == nil {
k.LanguagesServerClient = []string{"language1"}
}
}
initDirAlgs := func(a *directionAlgorithms) {
if a.Cipher == "" {
a.Cipher = "cipher1"
}
if a.MAC == "" {
a.MAC = "mac1"
}
if a.Compression == "" {
a.Compression = "compression1"
}
}
initAlgs := func(a *algorithms) {
if a.kex == "" {
a.kex = "kex1"
}
if a.hostKey == "" {
a.hostKey = "hostkey1"
}
initDirAlgs(&a.r)
initDirAlgs(&a.w)
}
type testcase struct {
name string
clientIn, serverIn kexInitMsg
wantClient, wantServer algorithms
wantErr bool
}
cases := []testcase{
testcase{
name: "standard",
},
testcase{
name: "no common hostkey",
serverIn: kexInitMsg{
ServerHostKeyAlgos: []string{"hostkey2"},
},
wantErr: true,
},
testcase{
name: "no common kex",
serverIn: kexInitMsg{
KexAlgos: []string{"kex2"},
},
wantErr: true,
},
testcase{
name: "no common cipher",
serverIn: kexInitMsg{
CiphersClientServer: []string{"cipher2"},
},
wantErr: true,
},
testcase{
name: "client decides cipher",
serverIn: kexInitMsg{
CiphersClientServer: []string{"cipher1", "cipher2"},
CiphersServerClient: []string{"cipher2", "cipher3"},
},
clientIn: kexInitMsg{
CiphersClientServer: []string{"cipher2", "cipher1"},
CiphersServerClient: []string{"cipher3", "cipher2"},
},
wantClient: algorithms{
r: directionAlgorithms{
Cipher: "cipher3",
},
w: directionAlgorithms{
Cipher: "cipher2",
},
},
wantServer: algorithms{
w: directionAlgorithms{
Cipher: "cipher3",
},
r: directionAlgorithms{
Cipher: "cipher2",
},
},
},
// TODO(hanwen): fix and add tests for AEAD ignoring
// the MACs field
}
for i := range cases {
initKex(&cases[i].clientIn)
initKex(&cases[i].serverIn)
initAlgs(&cases[i].wantClient)
initAlgs(&cases[i].wantServer)
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
serverAlgs, serverErr := findAgreedAlgorithms(false, &c.clientIn, &c.serverIn)
clientAlgs, clientErr := findAgreedAlgorithms(true, &c.clientIn, &c.serverIn)
serverHasErr := serverErr != nil
clientHasErr := clientErr != nil
if c.wantErr != serverHasErr || c.wantErr != clientHasErr {
t.Fatalf("got client/server error (%v, %v), want hasError %v",
clientErr, serverErr, c.wantErr)
}
if c.wantErr {
return
}
if !reflect.DeepEqual(serverAlgs, &c.wantServer) {
t.Errorf("server: got algs %#v, want %#v", serverAlgs, &c.wantServer)
}
if !reflect.DeepEqual(clientAlgs, &c.wantClient) {
t.Errorf("server: got algs %#v, want %#v", clientAlgs, &c.wantClient)
}
})
}
}

View File

@ -140,7 +140,7 @@ func ExampleNewServerConn() {
}
}
func ExampleHostKeyCheck() {
func ExampleClientConfig_HostKeyCallback() {
// Every client must provide a host key check. Here is a
// simple-minded parse of OpenSSH's known_hosts file
host := "hostname"

View File

@ -543,7 +543,8 @@ func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error {
clientInit := otherInit
serverInit := t.sentInitMsg
if len(t.hostKeys) == 0 {
isClient := len(t.hostKeys) == 0
if isClient {
clientInit, serverInit = serverInit, clientInit
magics.clientKexInit = t.sentInitPacket
@ -551,7 +552,7 @@ func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error {
}
var err error
t.algorithms, err = findAgreedAlgorithms(clientInit, serverInit)
t.algorithms, err = findAgreedAlgorithms(isClient, clientInit, serverInit)
if err != nil {
return err
}

View File

@ -350,8 +350,8 @@ func (db *hostKeyDB) check(address string, remote net.Addr, remoteKey ssh.Public
return db.checkAddr(hostToCheck, remoteKey)
}
// checkAddrs checks if we can find the given public key for any of
// the given addresses. If we only find an entry for the IP address,
// checkAddr checks if we can find the given public key for the
// given address. If we only find an entry for the IP address,
// or only the hostname, then this still succeeds.
func (db *hostKeyDB) checkAddr(a addr, remoteKey ssh.PublicKey) error {
// TODO(hanwen): are these the right semantics? What if there

View File

@ -764,3 +764,29 @@ func decode(packet []byte) (interface{}, error) {
}
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",
}

View File

@ -35,7 +35,7 @@ func dial(handler serverType, t *testing.T) *Client {
}
conf.AddHostKey(testSigners["rsa"])
_, chans, reqs, err := NewServerConn(c1, &conf)
conn, chans, reqs, err := NewServerConn(c1, &conf)
if err != nil {
t.Fatalf("Unable to handshake: %v", err)
}
@ -56,6 +56,9 @@ func dial(handler serverType, t *testing.T) *Client {
handler(ch, inReqs, t)
}()
}
if err := conn.Wait(); err != io.EOF {
t.Logf("server exit reason: %v", err)
}
}()
config := &ClientConfig{
@ -358,10 +361,9 @@ func TestServerWindow(t *testing.T) {
}
written, err := copyNRandomly("stdin", serverStdin, origBuf, windowTestBytes)
if err != nil {
t.Fatalf("failed to copy origBuf to serverStdin: %v", err)
}
if written != windowTestBytes {
t.Fatalf("Wrote only %d of %d bytes to server", written, windowTestBytes)
t.Errorf("failed to copy origBuf to serverStdin: %v", err)
} else if written != windowTestBytes {
t.Errorf("Wrote only %d of %d bytes to server", written, windowTestBytes)
}
echoedBytes := <-result

View File

@ -7,6 +7,7 @@ package terminal
import (
"bytes"
"io"
"strconv"
"sync"
"unicode/utf8"
)
@ -159,6 +160,10 @@ func bytesToKey(b []byte, pasteActive bool) (rune, []byte) {
return keyClearScreen, b[1:]
case 23: // ^W
return keyDeleteWord, b[1:]
case 14: // ^N
return keyDown, b[1:]
case 16: // ^P
return keyUp, b[1:]
}
}
@ -267,34 +272,44 @@ func (t *Terminal) moveCursorToPos(pos int) {
}
func (t *Terminal) move(up, down, left, right int) {
movement := make([]rune, 3*(up+down+left+right))
m := movement
for i := 0; i < up; i++ {
m[0] = keyEscape
m[1] = '['
m[2] = 'A'
m = m[3:]
}
for i := 0; i < down; i++ {
m[0] = keyEscape
m[1] = '['
m[2] = 'B'
m = m[3:]
}
for i := 0; i < left; i++ {
m[0] = keyEscape
m[1] = '['
m[2] = 'D'
m = m[3:]
}
for i := 0; i < right; i++ {
m[0] = keyEscape
m[1] = '['
m[2] = 'C'
m = m[3:]
m := []rune{}
// 1 unit up can be expressed as ^[[A or ^[A
// 5 units up can be expressed as ^[[5A
if up == 1 {
m = append(m, keyEscape, '[', 'A')
} else if up > 1 {
m = append(m, keyEscape, '[')
m = append(m, []rune(strconv.Itoa(up))...)
m = append(m, 'A')
}
t.queue(movement)
if down == 1 {
m = append(m, keyEscape, '[', 'B')
} else if down > 1 {
m = append(m, keyEscape, '[')
m = append(m, []rune(strconv.Itoa(down))...)
m = append(m, 'B')
}
if right == 1 {
m = append(m, keyEscape, '[', 'C')
} else if right > 1 {
m = append(m, keyEscape, '[')
m = append(m, []rune(strconv.Itoa(right))...)
m = append(m, 'C')
}
if left == 1 {
m = append(m, keyEscape, '[', 'D')
} else if left > 1 {
m = append(m, keyEscape, '[')
m = append(m, []rune(strconv.Itoa(left))...)
m = append(m, 'D')
}
t.queue(m)
}
func (t *Terminal) clearLineToRight() {

View File

@ -91,6 +91,12 @@ var keyPressTests = []struct {
{
in: "\x1b[B\r", // down
},
{
in: "\016\r", // ^P
},
{
in: "\014\r", // ^N
},
{
in: "line\x1b[A\x1b[B\r", // up then down
line: "line",
@ -231,6 +237,49 @@ func TestKeyPresses(t *testing.T) {
}
}
var renderTests = []struct {
in string
received string
err error
}{
{
// Cursor move after keyHome (left 4) then enter (right 4, newline)
in: "abcd\x1b[H\r",
received: "> abcd\x1b[4D\x1b[4C\r\n",
},
{
// Write, home, prepend, enter. Prepends rewrites the line.
in: "cdef\x1b[Hab\r",
received: "> cdef" + // Initial input
"\x1b[4Da" + // Move cursor back, insert first char
"cdef" + // Copy over original string
"\x1b[4Dbcdef" + // Repeat for second char with copy
"\x1b[4D" + // Put cursor back in position to insert again
"\x1b[4C\r\n", // Put cursor at the end of the line and newline.
},
}
func TestRender(t *testing.T) {
for i, test := range renderTests {
for j := 1; j < len(test.in); j++ {
c := &MockTerminal{
toSend: []byte(test.in),
bytesPerRead: j,
}
ss := NewTerminal(c, "> ")
_, err := ss.ReadLine()
if err != test.err {
t.Errorf("Error resulting from test %d (%d bytes per read) was '%v', expected '%v'", i, j, err, test.err)
break
}
if test.received != string(c.received) {
t.Errorf("Results rendered from test %d (%d bytes per read) was '%s', expected '%s'", i, j, c.received, test.received)
break
}
}
}
}
func TestPasswordNotSaved(t *testing.T) {
c := &MockTerminal{
toSend: []byte("password\r\x1b[A\r"),

View File

@ -64,13 +64,15 @@ func Restore(fd int, state *State) error {
return windows.SetConsoleMode(windows.Handle(fd), state.mode)
}
// GetSize returns the dimensions of the given terminal.
// GetSize returns the visible dimensions of the given terminal.
//
// These dimensions don't include any scrollback buffer height.
func GetSize(fd int) (width, height int, err error) {
var info windows.ConsoleScreenBufferInfo
if err := windows.GetConsoleScreenBufferInfo(windows.Handle(fd), &info); err != nil {
return 0, 0, err
}
return int(info.Size.X), int(info.Size.Y), nil
return int(info.Window.Right - info.Window.Left + 1), int(info.Window.Bottom - info.Window.Top + 1), nil
}
// ReadPassword reads a line of input from a terminal without local echo. This

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin dragonfly freebsd linux netbsd openbsd
// +build aix darwin dragonfly freebsd linux netbsd openbsd
package test

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin dragonfly freebsd linux netbsd openbsd
// +build aix darwin dragonfly freebsd linux netbsd openbsd
package test

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin dragonfly freebsd linux netbsd openbsd
// +build aix darwin dragonfly freebsd linux netbsd openbsd
package test

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !windows
// +build !windows,!solaris,!js
package test
@ -104,8 +104,8 @@ func (x *unixDialTester) TestServerConn(t *testing.T, c net.Conn) {
if c.LocalAddr().String() != x.listenAddr {
t.Fatalf("expected %q, got %q", x.listenAddr, c.LocalAddr().String())
}
if c.RemoteAddr().String() != "@" {
t.Fatalf("expected \"@\", got %q", c.RemoteAddr().String())
if c.RemoteAddr().String() != "@" && c.RemoteAddr().String() != "" {
t.Fatalf("expected \"@\" or \"\", got %q", c.RemoteAddr().String())
}
}

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin dragonfly freebsd linux netbsd openbsd
// +build aix darwin dragonfly freebsd linux netbsd openbsd
package test

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !windows
// +build !windows,!solaris,!js
package test
@ -13,6 +13,7 @@ import (
"errors"
"fmt"
"io"
"runtime"
"strings"
"testing"
@ -217,6 +218,11 @@ func TestKeyChange(t *testing.T) {
}
func TestInvalidTerminalMode(t *testing.T) {
if runtime.GOOS == "aix" {
// On AIX, sshd cannot acquire /dev/pts/* if launched as
// a non-root user.
t.Skipf("skipping on %s", runtime.GOOS)
}
server := newServer(t)
defer server.Shutdown()
conn := server.Dial(clientConfig())
@ -234,6 +240,11 @@ func TestInvalidTerminalMode(t *testing.T) {
}
func TestValidTerminalMode(t *testing.T) {
if runtime.GOOS == "aix" {
// On AIX, sshd cannot acquire /dev/pts/* if launched as
// a non-root user.
t.Skipf("skipping on %s", runtime.GOOS)
}
server := newServer(t)
defer server.Shutdown()
conn := server.Dial(clientConfig())
@ -278,6 +289,11 @@ func TestValidTerminalMode(t *testing.T) {
}
func TestWindowChange(t *testing.T) {
if runtime.GOOS == "aix" {
// On AIX, sshd cannot acquire /dev/pts/* if launched as
// a non-root user.
t.Skipf("skipping on %s", runtime.GOOS)
}
server := newServer(t)
defer server.Shutdown()
conn := server.Dial(clientConfig())
@ -351,7 +367,7 @@ func testOneCipher(t *testing.T, cipher string, cipherOrder []string) {
t.Fatalf("NewSession: %v", err)
}
out, err := session.Output(fmt.Sprintf("dd if=/dev/zero of=/dev/stdout bs=%d count=1", numBytes))
out, err := session.Output(fmt.Sprintf("dd if=/dev/zero bs=%d count=1", numBytes))
if err != nil {
t.Fatalf("Output: %v", err)
}
@ -384,17 +400,19 @@ func TestMACs(t *testing.T) {
macOrder := config.MACs
for _, mac := range macOrder {
server := newServer(t)
defer server.Shutdown()
conf := clientConfig()
conf.MACs = []string{mac}
// Don't fail if sshd doesn't have the MAC.
conf.MACs = append(conf.MACs, macOrder...)
if conn, err := server.TryDial(conf); err == nil {
conn.Close()
} else {
t.Fatalf("failed for MAC %q", mac)
}
t.Run(mac, func(t *testing.T) {
server := newServer(t)
defer server.Shutdown()
conf := clientConfig()
conf.MACs = []string{mac}
// Don't fail if sshd doesn't have the MAC.
conf.MACs = append(conf.MACs, macOrder...)
if conn, err := server.TryDial(conf); err == nil {
conn.Close()
} else {
t.Fatalf("failed for MAC %q", mac)
}
})
}
}
@ -403,17 +421,19 @@ func TestKeyExchanges(t *testing.T) {
config.SetDefaults()
kexOrder := config.KeyExchanges
for _, kex := range kexOrder {
server := newServer(t)
defer server.Shutdown()
conf := clientConfig()
// Don't fail if sshd doesn't have the kex.
conf.KeyExchanges = append([]string{kex}, kexOrder...)
conn, err := server.TryDial(conf)
if err == nil {
conn.Close()
} else {
t.Errorf("failed for kex %q", kex)
}
t.Run(kex, func(t *testing.T) {
server := newServer(t)
defer server.Shutdown()
conf := clientConfig()
// Don't fail if sshd doesn't have the kex.
conf.KeyExchanges = append([]string{kex}, kexOrder...)
conn, err := server.TryDial(conf)
if err == nil {
conn.Close()
} else {
t.Errorf("failed for kex %q", kex)
}
})
}
}
@ -424,20 +444,22 @@ func TestClientAuthAlgorithms(t *testing.T) {
"ecdsa",
"ed25519",
} {
server := newServer(t)
conf := clientConfig()
conf.SetDefaults()
conf.Auth = []ssh.AuthMethod{
ssh.PublicKeys(testSigners[key]),
}
t.Run(key, func(t *testing.T) {
server := newServer(t)
conf := clientConfig()
conf.SetDefaults()
conf.Auth = []ssh.AuthMethod{
ssh.PublicKeys(testSigners[key]),
}
conn, err := server.TryDial(conf)
if err == nil {
conn.Close()
} else {
t.Errorf("failed for key %q", key)
}
conn, err := server.TryDial(conf)
if err == nil {
conn.Close()
} else {
t.Errorf("failed for key %q", key)
}
server.Shutdown()
server.Shutdown()
})
}
}

View File

@ -1,46 +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 !windows
package test
// direct-tcpip functional tests
import (
"io"
"net"
"testing"
)
func TestDial(t *testing.T) {
server := newServer(t)
defer server.Shutdown()
sshConn := server.Dial(clientConfig())
defer sshConn.Close()
l, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Fatalf("Listen: %v", err)
}
defer l.Close()
go func() {
for {
c, err := l.Accept()
if err != nil {
break
}
io.WriteString(c, c.RemoteAddr().String())
c.Close()
}
}()
conn, err := sshConn.Dial("tcp", l.Addr().String())
if err != nil {
t.Fatalf("Dial: %v", err)
}
defer conn.Close()
}

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin dragonfly freebsd linux netbsd openbsd plan9
// +build aix darwin dragonfly freebsd linux netbsd openbsd plan9
package test
@ -306,7 +306,13 @@ func newServerForConfig(t *testing.T, config string, configVars map[string]strin
if err != nil {
t.Fatalf("user.Current: %v", err)
}
if u.Name == "root" {
uname := u.Name
if uname == "" {
// Check the value of u.Username as u.Name
// can be "" on some OSes like AIX.
uname = u.Username
}
if uname == "root" {
t.Skip("skipping test because current user is root")
}
dir, err := ioutil.TempDir("", "sshtest")

View File

@ -53,14 +53,14 @@ type transport struct {
// packetCipher represents a combination of SSH encryption/MAC
// protocol. A single instance should be used for one direction only.
type packetCipher interface {
// writePacket encrypts the packet and writes it to w. The
// writeCipherPacket encrypts the packet and writes it to w. The
// contents of the packet are generally scrambled.
writePacket(seqnum uint32, w io.Writer, rand io.Reader, packet []byte) error
writeCipherPacket(seqnum uint32, w io.Writer, rand io.Reader, packet []byte) error
// readPacket reads and decrypts a packet of data. The
// readCipherPacket reads and decrypts a packet of data. The
// returned packet may be overwritten by future calls of
// readPacket.
readPacket(seqnum uint32, r io.Reader) ([]byte, error)
readCipherPacket(seqnum uint32, r io.Reader) ([]byte, error)
}
// connectionState represents one side (read or write) of the
@ -127,7 +127,7 @@ func (t *transport) readPacket() (p []byte, err error) {
}
func (s *connectionState) readPacket(r *bufio.Reader) ([]byte, error) {
packet, err := s.packetCipher.readPacket(s.seqNum, r)
packet, err := s.packetCipher.readCipherPacket(s.seqNum, r)
s.seqNum++
if err == nil && len(packet) == 0 {
err = errors.New("ssh: zero length packet")
@ -175,7 +175,7 @@ func (t *transport) writePacket(packet []byte) error {
func (s *connectionState) writePacket(w *bufio.Writer, rand io.Reader, packet []byte) error {
changeKeys := len(packet) > 0 && packet[0] == msgNewKeys
err := s.packetCipher.writePacket(s.seqNum, w, rand, packet)
err := s.packetCipher.writeCipherPacket(s.seqNum, w, rand, packet)
if err != nil {
return err
}

View File

@ -5,6 +5,14 @@
// Package tea implements the TEA algorithm, as defined in Needham and
// Wheeler's 1994 technical report, “TEA, a Tiny Encryption Algorithm”. See
// http://www.cix.co.uk/~klockstone/tea.pdf for details.
//
// TEA is a legacy cipher and its short block size makes it vulnerable to
// birthday bound attacks (see https://sweet32.info). It should only be used
// where compatibility with legacy systems, not security, is the goal.
//
// Deprecated: any new system should use AES (from crypto/aes, if necessary in
// an AEAD mode like crypto/cipher.NewGCM) or XChaCha20-Poly1305 (from
// golang.org/x/crypto/chacha20poly1305).
package tea
import (

View File

@ -3,6 +3,12 @@
// license that can be found in the LICENSE file.
// Package twofish implements Bruce Schneier's Twofish encryption algorithm.
//
// Deprecated: Twofish is a legacy cipher and should not be used for new
// applications. Also, this package does not and will not provide an optimized
// implementation. Instead, use AES (from crypto/aes, if necessary in an AEAD
// mode like crypto/cipher.NewGCM) or XChaCha20-Poly1305 (from
// golang.org/x/crypto/chacha20poly1305).
package twofish // import "golang.org/x/crypto/twofish"
// Twofish is defined in https://www.schneier.com/paper-twofish-paper.pdf [TWOFISH]

View File

@ -4,6 +4,14 @@
// Package xtea implements XTEA encryption, as defined in Needham and Wheeler's
// 1997 technical report, "Tea extensions."
//
// XTEA is a legacy cipher and its short block size makes it vulnerable to
// birthday bound attacks (see https://sweet32.info). It should only be used
// where compatibility with legacy systems, not security, is the goal.
//
// Deprecated: any new system should use AES (from crypto/aes, if necessary in
// an AEAD mode like crypto/cipher.NewGCM) or XChaCha20-Poly1305 (from
// golang.org/x/crypto/chacha20poly1305).
package xtea // import "golang.org/x/crypto/xtea"
// For details, see http://www.cix.co.uk/~klockstone/xtea.pdf

View File

@ -15,22 +15,25 @@
// effectively create a unique key for each sector.
//
// XTS does not provide any authentication. An attacker can manipulate the
// ciphertext and randomise a block (16 bytes) of the plaintext.
// ciphertext and randomise a block (16 bytes) of the plaintext. This package
// does not implement ciphertext-stealing so sectors must be a multiple of 16
// bytes.
//
// (Note: this package does not implement ciphertext-stealing so sectors must
// be a multiple of 16 bytes.)
// Note that XTS is usually not appropriate for any use besides disk encryption.
// Most users should use an AEAD mode like GCM (from crypto/cipher.NewGCM) instead.
package xts // import "golang.org/x/crypto/xts"
import (
"crypto/cipher"
"encoding/binary"
"errors"
"sync"
"golang.org/x/crypto/internal/subtle"
)
// Cipher contains an expanded key structure. It doesn't contain mutable state
// and therefore can be used concurrently.
// Cipher contains an expanded key structure. It is safe for concurrent use if
// the underlying block cipher is safe for concurrent use.
type Cipher struct {
k1, k2 cipher.Block
}
@ -39,6 +42,12 @@ type Cipher struct {
// only defined for 16-byte ciphers.
const blockSize = 16
var tweakPool = sync.Pool{
New: func() interface{} {
return new([blockSize]byte)
},
}
// NewCipher creates a Cipher given a function for creating the underlying
// block cipher (which must have a block size of 16 bytes). The key must be
// twice the length of the underlying cipher's key.
@ -70,7 +79,10 @@ func (c *Cipher) Encrypt(ciphertext, plaintext []byte, sectorNum uint64) {
panic("xts: invalid buffer overlap")
}
var tweak [blockSize]byte
tweak := tweakPool.Get().(*[blockSize]byte)
for i := range tweak {
tweak[i] = 0
}
binary.LittleEndian.PutUint64(tweak[:8], sectorNum)
c.k2.Encrypt(tweak[:], tweak[:])
@ -86,8 +98,10 @@ func (c *Cipher) Encrypt(ciphertext, plaintext []byte, sectorNum uint64) {
plaintext = plaintext[blockSize:]
ciphertext = ciphertext[blockSize:]
mul2(&tweak)
mul2(tweak)
}
tweakPool.Put(tweak)
}
// Decrypt decrypts a sector of ciphertext and puts the result into plaintext.
@ -104,7 +118,10 @@ func (c *Cipher) Decrypt(plaintext, ciphertext []byte, sectorNum uint64) {
panic("xts: invalid buffer overlap")
}
var tweak [blockSize]byte
tweak := tweakPool.Get().(*[blockSize]byte)
for i := range tweak {
tweak[i] = 0
}
binary.LittleEndian.PutUint64(tweak[:8], sectorNum)
c.k2.Encrypt(tweak[:], tweak[:])
@ -120,8 +137,10 @@ func (c *Cipher) Decrypt(plaintext, ciphertext []byte, sectorNum uint64) {
plaintext = plaintext[blockSize:]
ciphertext = ciphertext[blockSize:]
mul2(&tweak)
mul2(tweak)
}
tweakPool.Put(tweak)
}
// mul2 multiplies tweak by 2 in GF(2¹²⁸) with an irreducible polynomial of

View File

@ -103,3 +103,19 @@ func TestShorterCiphertext(t *testing.T) {
t.Errorf("En/Decryption is not inverse")
}
}
func BenchmarkXTS(b *testing.B) {
b.ReportAllocs()
c, err := NewCipher(aes.NewCipher, make([]byte, 32))
if err != nil {
b.Fatalf("NewCipher failed: %s", err)
}
plaintext := make([]byte, 32)
encrypted := make([]byte, 48)
decrypted := make([]byte, 48)
for i := 0; i < b.N; i++ {
c.Encrypt(encrypted, plaintext, 0)
c.Decrypt(decrypted, encrypted[:len(plaintext)], 0)
}
}

2
x/exp

@ -1 +1 @@
Subproject commit 7d6377eee41ff45f3c44dfa30e3c2275066a5cf6
Subproject commit 475c5042d3f1a54a7b90cb8b1efb6697946e1107

@ -1 +1 @@
Subproject commit ca3c58166ed802c9810ffc499b01bc1cd2e0153a
Subproject commit 3e0bab5405d63a8f5dd9d9764a24c8e5ac4997fa

View File

@ -1,3 +0,0 @@
# Add no patterns to .hgignore except for files generated by the build.
syntax:glob
last-change

View File

@ -1,3 +0,0 @@
This repository holds supplementary Go networking libraries.
To submit changes to this repository, see http://golang.org/doc/contribute.html.

View File

@ -12,6 +12,8 @@ import (
"golang.org/x/net/bpf"
"golang.org/x/net/ipv4"
"golang.org/x/net/ipv6"
"golang.org/x/net/nettest"
)
// A virtualMachine is a BPF virtual machine which can process an
@ -137,7 +139,7 @@ type osVirtualMachine struct {
// testOSVM creates a virtualMachine which uses the OS's BPF VM by injecting
// packets into a UDP listener with a BPF program attached to it.
func testOSVM(t *testing.T, filter []bpf.Instruction) (virtualMachine, func()) {
l, err := net.ListenPacket("udp4", "127.0.0.1:0")
l, err := nettest.NewLocalPacketListener("udp")
if err != nil {
t.Fatalf("failed to open OS VM UDP listener: %v", err)
}
@ -147,12 +149,17 @@ func testOSVM(t *testing.T, filter []bpf.Instruction) (virtualMachine, func()) {
t.Fatalf("failed to compile BPF program: %v", err)
}
p := ipv4.NewPacketConn(l)
if err = p.SetBPF(prog); err != nil {
ip := l.LocalAddr().(*net.UDPAddr).IP
if ip.To4() != nil && ip.To16() == nil {
err = ipv4.NewPacketConn(l).SetBPF(prog)
} else {
err = ipv6.NewPacketConn(l).SetBPF(prog)
}
if err != nil {
t.Fatalf("failed to attach BPF program to listener: %v", err)
}
s, err := net.Dial("udp4", l.LocalAddr().String())
s, err := net.Dial(l.LocalAddr().Network(), l.LocalAddr().String())
if err != nil {
t.Fatalf("failed to dial connection to listener: %v", err)
}

View File

@ -1,28 +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 !plan9,go1.7
package ctxhttp
import (
"io"
"net/http"
"net/http/httptest"
"testing"
"context"
)
func TestGo17Context(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, "ok")
}))
ctx := context.Background()
resp, err := Get(ctx, http.DefaultClient, ts.URL)
if resp == nil || err != nil {
t.Fatalf("error received from client: %v %v", err, resp)
}
resp.Body.Close()
}

View File

@ -1,147 +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 !go1.7
package ctxhttp // import "golang.org/x/net/context/ctxhttp"
import (
"io"
"net/http"
"net/url"
"strings"
"golang.org/x/net/context"
)
func nop() {}
var (
testHookContextDoneBeforeHeaders = nop
testHookDoReturned = nop
testHookDidBodyClose = nop
)
// Do sends an HTTP request with the provided http.Client and returns an HTTP response.
// If the client is nil, http.DefaultClient is used.
// If the context is canceled or times out, ctx.Err() will be returned.
func Do(ctx context.Context, client *http.Client, req *http.Request) (*http.Response, error) {
if client == nil {
client = http.DefaultClient
}
// TODO(djd): Respect any existing value of req.Cancel.
cancel := make(chan struct{})
req.Cancel = cancel
type responseAndError struct {
resp *http.Response
err error
}
result := make(chan responseAndError, 1)
// Make local copies of test hooks closed over by goroutines below.
// Prevents data races in tests.
testHookDoReturned := testHookDoReturned
testHookDidBodyClose := testHookDidBodyClose
go func() {
resp, err := client.Do(req)
testHookDoReturned()
result <- responseAndError{resp, err}
}()
var resp *http.Response
select {
case <-ctx.Done():
testHookContextDoneBeforeHeaders()
close(cancel)
// Clean up after the goroutine calling client.Do:
go func() {
if r := <-result; r.resp != nil {
testHookDidBodyClose()
r.resp.Body.Close()
}
}()
return nil, ctx.Err()
case r := <-result:
var err error
resp, err = r.resp, r.err
if err != nil {
return resp, err
}
}
c := make(chan struct{})
go func() {
select {
case <-ctx.Done():
close(cancel)
case <-c:
// The response's Body is closed.
}
}()
resp.Body = &notifyingReader{resp.Body, c}
return resp, nil
}
// Get issues a GET request via the Do function.
func Get(ctx context.Context, client *http.Client, url string) (*http.Response, error) {
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return nil, err
}
return Do(ctx, client, req)
}
// Head issues a HEAD request via the Do function.
func Head(ctx context.Context, client *http.Client, url string) (*http.Response, error) {
req, err := http.NewRequest("HEAD", url, nil)
if err != nil {
return nil, err
}
return Do(ctx, client, req)
}
// Post issues a POST request via the Do function.
func Post(ctx context.Context, client *http.Client, url string, bodyType string, body io.Reader) (*http.Response, error) {
req, err := http.NewRequest("POST", url, body)
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", bodyType)
return Do(ctx, client, req)
}
// PostForm issues a POST request via the Do function.
func PostForm(ctx context.Context, client *http.Client, url string, data url.Values) (*http.Response, error) {
return Post(ctx, client, url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
}
// notifyingReader is an io.ReadCloser that closes the notify channel after
// Close is called or a Read fails on the underlying ReadCloser.
type notifyingReader struct {
io.ReadCloser
notify chan<- struct{}
}
func (r *notifyingReader) Read(p []byte) (int, error) {
n, err := r.ReadCloser.Read(p)
if err != nil && r.notify != nil {
close(r.notify)
r.notify = nil
}
return n, err
}
func (r *notifyingReader) Close() error {
err := r.ReadCloser.Close()
if r.notify != nil {
close(r.notify)
r.notify = nil
}
return err
}

Some files were not shown because too many files have changed in this diff Show More