This commit is contained in:
MXi4oyu 2019-05-17 19:29:43 +08:00
commit 809362e16e
900 changed files with 185840 additions and 65920 deletions

View File

@ -128,11 +128,15 @@ func (c *Client) Discover(ctx context.Context) (Directory, error) {
return *c.dir, nil return *c.dir, nil
} }
<<<<<<< HEAD
dirURL := c.DirectoryURL dirURL := c.DirectoryURL
if dirURL == "" { if dirURL == "" {
dirURL = LetsEncryptURL dirURL = LetsEncryptURL
} }
res, err := c.get(ctx, dirURL, wantStatus(http.StatusOK)) res, err := c.get(ctx, dirURL, wantStatus(http.StatusOK))
=======
res, err := c.get(ctx, c.directoryURL(), wantStatus(http.StatusOK))
>>>>>>> bd25a1f6d07d2d464980e6a8576c1ed59bb3950a
if err != nil { if err != nil {
return Directory{}, err return Directory{}, err
} }
@ -165,6 +169,13 @@ func (c *Client) Discover(ctx context.Context) (Directory, error) {
return *c.dir, nil 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. // 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 // The exp argument indicates the desired certificate validity duration. CA may issue a certificate
// with a different duration. // with a different duration.
@ -323,6 +334,20 @@ func (c *Client) UpdateReg(ctx context.Context, a *Account) (*Account, error) {
// a valid authorization (Authorization.Status is StatusValid). If so, the caller // a valid authorization (Authorization.Status is StatusValid). If so, the caller
// need not fulfill any challenge and can proceed to requesting a certificate. // need not fulfill any challenge and can proceed to requesting a certificate.
func (c *Client) Authorize(ctx context.Context, domain string) (*Authorization, error) { 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 { if _, err := c.Discover(ctx); err != nil {
return nil, err return nil, err
} }
@ -336,7 +361,7 @@ func (c *Client) Authorize(ctx context.Context, domain string) (*Authorization,
Identifier authzID `json:"identifier"` Identifier authzID `json:"identifier"`
}{ }{
Resource: "new-authz", 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)) res, err := c.post(ctx, c.Key, c.dir.AuthzURL, req, wantStatus(http.StatusCreated))
if err != nil { if err != nil {
@ -697,12 +722,18 @@ func (c *Client) doReg(ctx context.Context, url string, typ string, acct *Accoun
} }
// popNonce returns a nonce value previously stored with c.addNonce // 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) { func (c *Client) popNonce(ctx context.Context, url string) (string, error) {
c.noncesMu.Lock() c.noncesMu.Lock()
defer c.noncesMu.Unlock() defer c.noncesMu.Unlock()
if len(c.nonces) == 0 { 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 var nonce string
for nonce = range c.nonces { for nonce = range c.nonces {

View File

@ -75,6 +75,10 @@ func TestDiscover(t *testing.T) {
) )
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
<<<<<<< HEAD
=======
w.Header().Set("Replay-Nonce", "testnonce")
>>>>>>> bd25a1f6d07d2d464980e6a8576c1ed59bb3950a
fmt.Fprintf(w, `{ fmt.Fprintf(w, `{
"new-reg": %q, "new-reg": %q,
"new-authz": %q, "new-authz": %q,
@ -100,6 +104,9 @@ func TestDiscover(t *testing.T) {
if dir.RevokeURL != revoke { if dir.RevokeURL != revoke {
t.Errorf("dir.RevokeURL = %q; want %q", 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) { func TestRegister(t *testing.T) {
@ -147,7 +154,11 @@ func TestRegister(t *testing.T) {
return false 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} a := &Account{Contact: contacts}
var err error var err error
if a, err = c.Register(context.Background(), a, prompt); err != nil { if a, err = c.Register(context.Background(), a, prompt); err != nil {
@ -288,6 +299,7 @@ func TestGetReg(t *testing.T) {
} }
func TestAuthorize(t *testing.T) { func TestAuthorize(t *testing.T) {
<<<<<<< HEAD
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method == "HEAD" { if r.Method == "HEAD" {
w.Header().Set("Replay-Nonce", "test-nonce") w.Header().Set("Replay-Nonce", "test-nonce")
@ -296,73 +308,117 @@ func TestAuthorize(t *testing.T) {
if r.Method != "POST" { if r.Method != "POST" {
t.Errorf("r.Method = %q; want POST", r.Method) t.Errorf("r.Method = %q; want POST", r.Method)
} }
=======
var j struct { tt := []struct{ typ, value string }{
Resource string {"dns", "example.com"},
Identifier struct { {"ip", "1.2.3.4"},
Type string }
Value string for _, test := range tt {
} t.Run(test.typ, func(t *testing.T) {
} ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
decodeJWSRequest(t, &j, r) if r.Method == "HEAD" {
w.Header().Set("Replay-Nonce", "test-nonce")
// Test request return
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"
} }
], if r.Method != "POST" {
"combinations":[[0],[1]]}`) t.Errorf("r.Method = %q; want POST", r.Method)
})) }
defer ts.Close() >>>>>>> bd25a1f6d07d2d464980e6a8576c1ed59bb3950a
cl := Client{Key: testKeyEC, dir: &Directory{AuthzURL: ts.URL}} var j struct {
auth, err := cl.Authorize(context.Background(), "example.com") Resource string
if err != nil { Identifier struct {
t.Fatal(err) Type string
} Value string
}
}
decodeJWSRequest(t, &j, r)
if auth.URI != "https://ca.tld/acme/auth/1" { // Test request
t.Errorf("URI = %q; want https://ca.tld/acme/auth/1", auth.URI) if j.Resource != "new-authz" {
} t.Errorf("j.Resource = %q; want new-authz", j.Resource)
if auth.Status != "pending" { }
t.Errorf("Status = %q; want pending", auth.Status) if j.Identifier.Type != test.typ {
} t.Errorf("j.Identifier.Type = %q; want %q", j.Identifier.Type, test.typ)
if auth.Identifier.Type != "dns" { }
t.Errorf("Identifier.Type = %q; want dns", auth.Identifier.Type) if j.Identifier.Value != test.value {
} t.Errorf("j.Identifier.Value = %q; want %q", j.Identifier.Value, test.value)
if auth.Identifier.Value != "example.com" { }
t.Errorf("Identifier.Value = %q; want example.com", auth.Identifier.Value)
}
if n := len(auth.Challenges); n != 2 { w.Header().Set("Location", "https://ca.tld/acme/auth/1")
t.Fatalf("len(auth.Challenges) = %d; want 2", n) 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()
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)
}
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)
}
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)
}
<<<<<<< HEAD
c := auth.Challenges[0] c := auth.Challenges[0]
if c.Type != "http-01" { if c.Type != "http-01" {
t.Errorf("c.Type = %q; want http-01", c.Type) t.Errorf("c.Type = %q; want http-01", c.Type)
@ -384,10 +440,25 @@ func TestAuthorize(t *testing.T) {
if c.Token != "token2" { if c.Token != "token2" {
t.Errorf("c.Token = %q; want token2", c.Token) t.Errorf("c.Token = %q; want token2", 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}} combs := [][]int{{0}, {1}}
if !reflect.DeepEqual(auth.Combinations, combs) { if !reflect.DeepEqual(auth.Combinations, combs) {
t.Errorf("auth.Combinations: %+v\nwant: %+v\n", auth.Combinations, combs) t.Errorf("auth.Combinations: %+v\nwant: %+v\n", auth.Combinations, combs)
}
>>>>>>> bd25a1f6d07d2d464980e6a8576c1ed59bb3950a
})
} }
} }
@ -401,7 +472,11 @@ func TestAuthorizeValid(t *testing.T) {
w.Write([]byte(`{"status":"valid"}`)) w.Write([]byte(`{"status":"valid"}`))
})) }))
defer ts.Close() 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") _, err := client.Authorize(context.Background(), "example.com")
if err != nil { if err != nil {
t.Errorf("err = %v", err) t.Errorf("err = %v", err)
@ -501,6 +576,7 @@ func TestWaitAuthorization(t *testing.T) {
} }
if authz == nil { if authz == nil {
t.Fatal("authz is nil") t.Fatal("authz is nil")
<<<<<<< HEAD
} }
}) })
t.Run("invalid status", func(t *testing.T) { t.Run("invalid status", func(t *testing.T) {
@ -524,6 +600,31 @@ func TestWaitAuthorization(t *testing.T) {
t.Errorf("res.StatusCode = %d; want %d", res.StatusCode, code) t.Errorf("res.StatusCode = %d; want %d", res.StatusCode, code)
} }
}) })
=======
}
})
t.Run("invalid status", func(t *testing.T) {
_, err := runWaitAuthorization(context.Background(), t, func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, `{"status":"invalid"}`)
})
if _, ok := err.(*AuthorizationError); !ok {
t.Errorf("err is %v (%T); want non-nil *AuthorizationError", err, err)
}
})
t.Run("non-retriable error", func(t *testing.T) {
const code = http.StatusBadRequest
_, err := runWaitAuthorization(context.Background(), t, func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(code)
})
res, ok := err.(*Error)
if !ok {
t.Fatalf("err is %v (%T); want a non-nil *Error", err, err)
}
if res.StatusCode != code {
t.Errorf("res.StatusCode = %d; want %d", res.StatusCode, code)
}
})
>>>>>>> bd25a1f6d07d2d464980e6a8576c1ed59bb3950a
for _, code := range []int{http.StatusTooManyRequests, http.StatusInternalServerError} { for _, code := range []int{http.StatusTooManyRequests, http.StatusInternalServerError} {
t.Run(fmt.Sprintf("retriable %d error", code), func(t *testing.T) { t.Run(fmt.Sprintf("retriable %d error", code), func(t *testing.T) {
var count int var count int
@ -1016,6 +1117,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) { func TestNonce_postJWS(t *testing.T) {
var count int var count int
seen := make(map[string]bool) seen := make(map[string]bool)
@ -1049,7 +1197,11 @@ func TestNonce_postJWS(t *testing.T) {
})) }))
defer ts.Close() 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 { if _, err := client.Authorize(context.Background(), "example.com"); err != nil {
t.Errorf("client.Authorize 1: %v", err) t.Errorf("client.Authorize 1: %v", err)
} }

View File

@ -32,6 +32,7 @@ import (
"time" "time"
"golang.org/x/crypto/acme" "golang.org/x/crypto/acme"
"golang.org/x/net/idna"
) )
// createCertRetryAfter is how much time to wait before removing a failed state // 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. // HostWhitelist returns a policy where only the specified host names are allowed.
// Only exact matches are currently supported. Subdomains, regexp or wildcard // Only exact matches are currently supported. Subdomains, regexp or wildcard
// will not match. // 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 { func HostWhitelist(hosts ...string) HostPolicy {
whitelist := make(map[string]bool, len(hosts)) whitelist := make(map[string]bool, len(hosts))
for _, h := range 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 { return func(_ context.Context, host string) error {
if !whitelist[host] { if !whitelist[host] {
@ -243,7 +250,21 @@ func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate,
if !strings.Contains(strings.Trim(name, "."), ".") { if !strings.Contains(strings.Trim(name, "."), ".") {
return nil, errors.New("acme/autocert: server name component count invalid") return nil, errors.New("acme/autocert: server name component count invalid")
} }
<<<<<<< HEAD
if strings.ContainsAny(name, `+/\`) { 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 {
>>>>>>> bd25a1f6d07d2d464980e6a8576c1ed59bb3950a
return nil, errors.New("acme/autocert: server name contains invalid character") return nil, errors.New("acme/autocert: server name contains invalid character")
} }
@ -801,6 +822,7 @@ func (m *Manager) putCertToken(ctx context.Context, name string, cert *tls.Certi
defer m.tokensMu.Unlock() defer m.tokensMu.Unlock()
if m.certTokens == nil { if m.certTokens == nil {
m.certTokens = make(map[string]*tls.Certificate) m.certTokens = make(map[string]*tls.Certificate)
<<<<<<< HEAD
} }
m.certTokens[name] = cert m.certTokens[name] = cert
m.cachePut(ctx, certKey{domain: name, isToken: true}, cert) m.cachePut(ctx, certKey{domain: name, isToken: true}, cert)
@ -832,6 +854,39 @@ func (m *Manager) httpToken(ctx context.Context, tokenPath string) ([]byte, erro
return m.Cache.Get(ctx, httpTokenCacheKey(tokenPath)) return m.Cache.Get(ctx, httpTokenCacheKey(tokenPath))
} }
=======
}
m.certTokens[name] = cert
m.cachePut(ctx, certKey{domain: name, isToken: true}, cert)
}
// deleteCertToken removes the token certificate with the specified name
// from both m.certTokens map and m.Cache.
func (m *Manager) deleteCertToken(name string) {
m.tokensMu.Lock()
defer m.tokensMu.Unlock()
delete(m.certTokens, name)
if m.Cache != nil {
ck := certKey{domain: name, isToken: true}
m.Cache.Delete(context.Background(), ck.String())
}
}
// httpToken retrieves an existing http-01 token value from an in-memory map
// or the optional cache.
func (m *Manager) httpToken(ctx context.Context, tokenPath string) ([]byte, error) {
m.tokensMu.RLock()
defer m.tokensMu.RUnlock()
if v, ok := m.httpTokens[tokenPath]; ok {
return v, nil
}
if m.Cache == nil {
return nil, fmt.Errorf("acme/autocert: no token at %q", tokenPath)
}
return m.Cache.Get(ctx, httpTokenCacheKey(tokenPath))
}
>>>>>>> bd25a1f6d07d2d464980e6a8576c1ed59bb3950a
// putHTTPToken stores an http-01 token value using tokenPath as key // putHTTPToken stores an http-01 token value using tokenPath as key
// in both in-memory map and the optional Cache. // in both in-memory map and the optional Cache.
// //

View File

@ -206,6 +206,31 @@ func TestGetCertificate_trailingDot(t *testing.T) {
man := &Manager{Prompt: AcceptTOS} man := &Manager{Prompt: AcceptTOS}
defer man.stopRenew() defer man.stopRenew()
hello := clientHelloInfo("example.org.", true) hello := clientHelloInfo("example.org.", true)
<<<<<<< HEAD
=======
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)
>>>>>>> bd25a1f6d07d2d464980e6a8576c1ed59bb3950a
testGetCertificate(t, man, "example.org", hello) testGetCertificate(t, man, "example.org", hello)
} }
@ -858,11 +883,19 @@ func TestCache(t *testing.T) {
cert, err := dummyCert(ecdsaKey.Public(), exampleDomain) cert, err := dummyCert(ecdsaKey.Public(), exampleDomain)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
<<<<<<< HEAD
} }
ecdsaCert := &tls.Certificate{ ecdsaCert := &tls.Certificate{
Certificate: [][]byte{cert}, Certificate: [][]byte{cert},
PrivateKey: ecdsaKey, PrivateKey: ecdsaKey,
} }
=======
}
ecdsaCert := &tls.Certificate{
Certificate: [][]byte{cert},
PrivateKey: ecdsaKey,
}
>>>>>>> bd25a1f6d07d2d464980e6a8576c1ed59bb3950a
rsaKey, err := rsa.GenerateKey(rand.Reader, 512) rsaKey, err := rsa.GenerateKey(rand.Reader, 512)
if err != nil { if err != nil {
@ -882,6 +915,7 @@ func TestCache(t *testing.T) {
ctx := context.Background() ctx := context.Background()
if err := man.cachePut(ctx, exampleCertKey, ecdsaCert); err != nil { if err := man.cachePut(ctx, exampleCertKey, ecdsaCert); err != nil {
<<<<<<< HEAD
t.Fatalf("man.cachePut: %v", err) t.Fatalf("man.cachePut: %v", err)
} }
if err := man.cachePut(ctx, exampleCertKeyRSA, rsaCert); err != nil { if err := man.cachePut(ctx, exampleCertKeyRSA, rsaCert); err != nil {
@ -900,19 +934,40 @@ func TestCache(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("man.cacheGet: %v", err) t.Fatalf("man.cacheGet: %v", err)
} }
=======
t.Fatalf("man.cachePut: %v", err)
}
if err := man.cachePut(ctx, exampleCertKeyRSA, rsaCert); err != nil {
t.Fatalf("man.cachePut: %v", err)
}
res, err := man.cacheGet(ctx, exampleCertKey)
if err != nil {
t.Fatalf("man.cacheGet: %v", err)
}
if res == nil || !bytes.Equal(res.Certificate[0], ecdsaCert.Certificate[0]) {
t.Errorf("man.cacheGet = %+v; want %+v", res, ecdsaCert)
}
res, err = man.cacheGet(ctx, exampleCertKeyRSA)
if err != nil {
t.Fatalf("man.cacheGet: %v", err)
}
>>>>>>> bd25a1f6d07d2d464980e6a8576c1ed59bb3950a
if res == nil || !bytes.Equal(res.Certificate[0], rsaCert.Certificate[0]) { if res == nil || !bytes.Equal(res.Certificate[0], rsaCert.Certificate[0]) {
t.Errorf("man.cacheGet = %+v; want %+v", res, rsaCert) t.Errorf("man.cacheGet = %+v; want %+v", res, rsaCert)
} }
} }
func TestHostWhitelist(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 { tt := []struct {
host string host string
allow bool allow bool
}{ }{
{"example.com", true}, {"example.com", true},
{"example.org", true}, {"example.org", true},
{"xn--4xaaa.com", true},
{"one.example.com", false}, {"one.example.com", false},
{"two.example.org", false}, {"two.example.org", false},
{"three.example.net", false}, {"three.example.net", false},

View File

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

View File

@ -75,19 +75,23 @@ func Sum256(data []byte) [Size256]byte {
} }
// New512 returns a new hash.Hash computing the BLAKE2b-512 checksum. A non-nil // 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) } 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 // 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) } 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 // 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) } 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. // New returns a new hash.Hash computing the BLAKE2b checksum with a custom length.
<<<<<<< HEAD
// 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 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.
>>>>>>> bd25a1f6d07d2d464980e6a8576c1ed59bb3950a
// The hash size can be a value between 1 and 64 but it is highly recommended to use // The hash size can be a value between 1 and 64 but it is highly recommended to use
// values equal or greater than: // values equal or greater than:
// - 32 if BLAKE2b is used as a hash function (The key is zero bytes long). // - 32 if BLAKE2b is used as a hash function (The key is zero bytes long).

View File

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

View File

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

View File

@ -3,6 +3,14 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// Package blowfish implements Bruce Schneier's Blowfish encryption algorithm. // 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" package blowfish // import "golang.org/x/crypto/blowfish"
// The code is a port of Bruce Schneier's C implementation. // The code is a port of Bruce Schneier's C implementation.

View File

@ -15,9 +15,20 @@
// http://cryptojedi.org/papers/dclxvi-20100714.pdf. Its output is compatible // http://cryptojedi.org/papers/dclxvi-20100714.pdf. Its output is compatible
// with the implementation described in that paper. // with the implementation described in that paper.
// //
<<<<<<< HEAD
// (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 // 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.)
=======
// 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.
//
// 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.
>>>>>>> bd25a1f6d07d2d464980e6a8576c1ed59bb3950a
package bn256 // import "golang.org/x/crypto/bn256" package bn256 // import "golang.org/x/crypto/bn256"
import ( import (
@ -26,9 +37,6 @@ import (
"math/big" "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 // 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. // output of an operation, but cannot be used as an input.
type G1 struct { type G1 struct {
@ -54,6 +62,12 @@ func RandomG1(r io.Reader) (*big.Int, *G1, error) {
} }
func (e *G1) String() string { func (e *G1) String() string {
<<<<<<< HEAD
=======
if e.p == nil {
return "bn256.G1" + newCurvePoint(nil).String()
}
>>>>>>> bd25a1f6d07d2d464980e6a8576c1ed59bb3950a
return "bn256.G1" + e.p.String() return "bn256.G1" + e.p.String()
} }
@ -77,7 +91,8 @@ func (e *G1) ScalarMult(a *G1, k *big.Int) *G1 {
} }
// Add sets e to a+b and then returns e. // 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 { func (e *G1) Add(a, b *G1) *G1 {
if e.p == nil { if e.p == nil {
e.p = newCurvePoint(nil) e.p = newCurvePoint(nil)
@ -175,6 +190,12 @@ func RandomG2(r io.Reader) (*big.Int, *G2, error) {
} }
func (e *G2) String() string { func (e *G2) String() string {
<<<<<<< HEAD
=======
if e.p == nil {
return "bn256.G2" + newTwistPoint(nil).String()
}
>>>>>>> bd25a1f6d07d2d464980e6a8576c1ed59bb3950a
return "bn256.G2" + e.p.String() return "bn256.G2" + e.p.String()
} }
@ -198,7 +219,8 @@ func (e *G2) ScalarMult(a *G2, k *big.Int) *G2 {
} }
// Add sets e to a+b and then returns e. // 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 { func (e *G2) Add(a, b *G2) *G2 {
if e.p == nil { if e.p == nil {
e.p = newTwistPoint(nil) e.p = newTwistPoint(nil)
@ -277,8 +299,11 @@ type GT struct {
p *gfP12 p *gfP12
} }
func (g *GT) String() string { func (e *GT) String() string {
return "bn256.GT" + g.p.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. // 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 { func (e *gfP12) MulScalar(a *gfP12, b *gfP6, pool *bnPool) *gfP12 {
e.x.Mul(e.x, b, pool) e.x.Mul(a.x, b, pool)
e.y.Mul(e.y, b, pool) e.y.Mul(a.y, b, pool)
return e return e
} }

View File

@ -2,8 +2,15 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// Package cast5 implements CAST5, as defined in RFC 2144. CAST5 is a common // Package cast5 implements CAST5, as defined in RFC 2144.
// OpenPGP cipher. //
// 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" package cast5 // import "golang.org/x/crypto/cast5"
import "errors" 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 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 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 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 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 #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 ADDQ itr2, adp
hashADTailLoop: hashADTailLoop:
SHLQ $8, t1:t0 SHLQ $8, t0, t1
SHLQ $8, t0 SHLQ $8, t0
MOVB -1(adp), t2 MOVB -1(adp), t2
XORQ t2, t0 XORQ t2, t0

View File

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

View File

@ -5,6 +5,8 @@
package curve25519 package curve25519
import ( import (
"bytes"
"crypto/rand"
"fmt" "fmt"
"testing" "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) { func BenchmarkScalarBaseMult(b *testing.B) {
var in, out [32]byte var in, out [32]byte
in[0] = 1 in[0] = 1

View File

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

View File

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

View File

@ -87,18 +87,18 @@ TEXT ·square(SB),7,$0-16
ADDQ AX,R13 ADDQ AX,R13
ADCQ DX,R14 ADCQ DX,R14
MOVQ $REDMASK51,SI MOVQ $REDMASK51,SI
SHLQ $13,R8:CX SHLQ $13,CX,R8
ANDQ SI,CX ANDQ SI,CX
SHLQ $13,R10:R9 SHLQ $13,R9,R10
ANDQ SI,R9 ANDQ SI,R9
ADDQ R8,R9 ADDQ R8,R9
SHLQ $13,R12:R11 SHLQ $13,R11,R12
ANDQ SI,R11 ANDQ SI,R11
ADDQ R10,R11 ADDQ R10,R11
SHLQ $13,R14:R13 SHLQ $13,R13,R14
ANDQ SI,R13 ANDQ SI,R13
ADDQ R12,R13 ADDQ R12,R13
SHLQ $13,BX:R15 SHLQ $13,R15,BX
ANDQ SI,R15 ANDQ SI,R15
ADDQ R14,R15 ADDQ R14,R15
IMUL3Q $19,BX,DX 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,11 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
<<<<<<< HEAD
// +build !s390x gccgo appengine // +build !s390x gccgo appengine
=======
// +build !arm64,!s390x arm64,!go1.11 gccgo appengine
>>>>>>> bd25a1f6d07d2d464980e6a8576c1ed59bb3950a
package chacha20 package chacha20

View File

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

View File

@ -258,6 +258,7 @@ tail:
MOVD R8, R3 MOVD R8, R3
MOVD $0, R4 MOVD $0, R4
JMP continue JMP continue
<<<<<<< HEAD
// func hasVectorFacility() bool // func hasVectorFacility() bool
TEXT ·hasVectorFacility(SB), NOSPLIT, $24-1 TEXT ·hasVectorFacility(SB), NOSPLIT, $24-1
@ -281,3 +282,5 @@ vectorinstalled:
novector: novector:
MOVB $0, ret+0(FP) // no vx MOVB $0, ret+0(FP) // no vx
RET RET
=======
>>>>>>> bd25a1f6d07d2d464980e6a8576c1ed59bb3950a

View File

@ -3,6 +3,10 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// Package md4 implements the MD4 hash algorithm as defined in RFC 1320. // 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" package md4 // import "golang.org/x/crypto/md4"
import ( import (

View File

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

View File

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

View File

@ -18,6 +18,7 @@ import (
"io" "io"
"net/textproto" "net/textproto"
"strconv" "strconv"
"strings"
"golang.org/x/crypto/openpgp/armor" "golang.org/x/crypto/openpgp/armor"
"golang.org/x/crypto/openpgp/errors" "golang.org/x/crypto/openpgp/errors"
@ -27,7 +28,7 @@ import (
// A Block represents a clearsigned message. A signature on a Block can // A Block represents a clearsigned message. A signature on a Block can
// be checked by passing Bytes into openpgp.CheckDetachedSignature. // be checked by passing Bytes into openpgp.CheckDetachedSignature.
type Block struct { type Block struct {
Headers textproto.MIMEHeader // Optional message headers Headers textproto.MIMEHeader // Optional unverified Hash headers
Plaintext []byte // The original message text Plaintext []byte // The original message text
Bytes []byte // The signed message Bytes []byte // The signed message
ArmoredSignature *armor.Block // The signature block ArmoredSignature *armor.Block // The signature block
@ -69,8 +70,13 @@ func getLine(data []byte) (line, rest []byte) {
return data[0:i], data[j:] return data[0:i], data[j:]
} }
// Decode finds the first clearsigned message in data and returns it, as well // Decode finds the first clearsigned message in data and returns it, as well as
// as the suffix of data which remains after the message. // 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) { func Decode(data []byte) (b *Block, rest []byte) {
// start begins with a newline. However, at the very beginning of // start begins with a newline. However, at the very beginning of
// the byte array, we'll accept the start string without it. // 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 return nil, data
} }
// Consume the start line. // Consume the start line and check it does not have a suffix.
_, rest = getLine(rest) suffix, rest := getLine(rest)
if len(suffix) != 0 {
return nil, data
}
var line []byte var line []byte
b = &Block{ b = &Block{
@ -103,15 +112,25 @@ func Decode(data []byte) (b *Block, rest []byte) {
break 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{':'}) i := bytes.Index(line, []byte{':'})
if i == -1 { if i == -1 {
return nil, data return nil, data
} }
key, val := line[0:i], line[i+1:] key, val := string(line[0:i]), string(line[i+1:])
key = bytes.TrimSpace(key) key = strings.TrimSpace(key)
val = bytes.TrimSpace(val) if key != "Hash" {
b.Headers.Add(string(key), string(val)) return nil, data
}
val = strings.TrimSpace(val)
b.Headers.Add(key, val)
} }
firstLine := true 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") 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) { func TestParseWithNoNewlineAtEnd(t *testing.T) {
input := clearsignInput input := clearsignInput
input = input[:len(input)-len("trailing")-1] input = input[:len(input)-len("trailing")-1]
@ -140,6 +134,13 @@ func (qr *quickRand) Read(p []byte) (int, error) {
} }
func TestMultiSign(t *testing.T) { func TestMultiSign(t *testing.T) {
<<<<<<< HEAD
=======
if testing.Short() {
t.Skip("skipping long test in -short mode")
}
>>>>>>> bd25a1f6d07d2d464980e6a8576c1ed59bb3950a
zero := quickRand(0) zero := quickRand(0)
config := packet.Config{Rand: &zero} config := packet.Config{Rand: &zero}
@ -193,6 +194,62 @@ func TestMultiSign(t *testing.T) {
} }
} }
<<<<<<< HEAD
=======
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)
}
}
}
>>>>>>> bd25a1f6d07d2d464980e6a8576c1ed59bb3950a
var clearsignInput = []byte(` var clearsignInput = []byte(`
;lasjlkfdsa ;lasjlkfdsa
@ -235,13 +292,6 @@ qZg6BaTvOxepqOxnhVU=
trailing`) trailing`)
var clearsignInput3 = []byte(`
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256
(This message was truncated.)
`)
var signingKey = `-----BEGIN PGP PRIVATE KEY BLOCK----- var signingKey = `-----BEGIN PGP PRIVATE KEY BLOCK-----
Version: GnuPG v1.4.10 (GNU/Linux) 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". // which may be empty but must not contain any of "()<>\x00".
// If config is nil, sensible defaults will be used. // If config is nil, sensible defaults will be used.
func NewEntity(name, comment, email string, config *packet.Config) (*Entity, error) { func NewEntity(name, comment, email string, config *packet.Config) (*Entity, error) {
currentTime := config.Now() creationTime := config.Now()
bits := defaultRSAKeyBits bits := defaultRSAKeyBits
if config != nil && config.RSABits != 0 { if config != nil && config.RSABits != 0 {
@ -525,8 +525,8 @@ func NewEntity(name, comment, email string, config *packet.Config) (*Entity, err
} }
e := &Entity{ e := &Entity{
PrimaryKey: packet.NewRSAPublicKey(currentTime, &signingPriv.PublicKey), PrimaryKey: packet.NewRSAPublicKey(creationTime, &signingPriv.PublicKey),
PrivateKey: packet.NewRSAPrivateKey(currentTime, signingPriv), PrivateKey: packet.NewRSAPrivateKey(creationTime, signingPriv),
Identities: make(map[string]*Identity), Identities: make(map[string]*Identity),
} }
isPrimaryId := true isPrimaryId := true
@ -534,7 +534,7 @@ func NewEntity(name, comment, email string, config *packet.Config) (*Entity, err
Name: uid.Id, Name: uid.Id,
UserId: uid, UserId: uid,
SelfSignature: &packet.Signature{ SelfSignature: &packet.Signature{
CreationTime: currentTime, CreationTime: creationTime,
SigType: packet.SigTypePositiveCert, SigType: packet.SigTypePositiveCert,
PubKeyAlgo: packet.PubKeyAlgoRSA, PubKeyAlgo: packet.PubKeyAlgoRSA,
Hash: config.Hash(), 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 = make([]Subkey, 1)
e.Subkeys[0] = Subkey{ e.Subkeys[0] = Subkey{
PublicKey: packet.NewRSAPublicKey(currentTime, &encryptingPriv.PublicKey), PublicKey: packet.NewRSAPublicKey(creationTime, &encryptingPriv.PublicKey),
PrivateKey: packet.NewRSAPrivateKey(currentTime, encryptingPriv), PrivateKey: packet.NewRSAPrivateKey(creationTime, encryptingPriv),
Sig: &packet.Signature{ Sig: &packet.Signature{
CreationTime: currentTime, CreationTime: creationTime,
SigType: packet.SigTypeSubkeyBinding, SigType: packet.SigTypeSubkeyBinding,
PubKeyAlgo: packet.PubKeyAlgoRSA, PubKeyAlgo: packet.PubKeyAlgoRSA,
Hash: config.Hash(), Hash: config.Hash(),

View File

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

View File

@ -36,49 +36,57 @@ type PrivateKey struct {
iv []byte iv []byte
} }
func NewRSAPrivateKey(currentTime time.Time, priv *rsa.PrivateKey) *PrivateKey { func NewRSAPrivateKey(creationTime time.Time, priv *rsa.PrivateKey) *PrivateKey {
pk := new(PrivateKey) pk := new(PrivateKey)
pk.PublicKey = *NewRSAPublicKey(currentTime, &priv.PublicKey) pk.PublicKey = *NewRSAPublicKey(creationTime, &priv.PublicKey)
pk.PrivateKey = priv pk.PrivateKey = priv
return pk return pk
} }
func NewDSAPrivateKey(currentTime time.Time, priv *dsa.PrivateKey) *PrivateKey { func NewDSAPrivateKey(creationTime time.Time, priv *dsa.PrivateKey) *PrivateKey {
pk := new(PrivateKey) pk := new(PrivateKey)
pk.PublicKey = *NewDSAPublicKey(currentTime, &priv.PublicKey) pk.PublicKey = *NewDSAPublicKey(creationTime, &priv.PublicKey)
pk.PrivateKey = priv pk.PrivateKey = priv
return pk return pk
} }
func NewElGamalPrivateKey(currentTime time.Time, priv *elgamal.PrivateKey) *PrivateKey { func NewElGamalPrivateKey(creationTime time.Time, priv *elgamal.PrivateKey) *PrivateKey {
pk := new(PrivateKey) pk := new(PrivateKey)
pk.PublicKey = *NewElGamalPublicKey(currentTime, &priv.PublicKey) pk.PublicKey = *NewElGamalPublicKey(creationTime, &priv.PublicKey)
pk.PrivateKey = priv pk.PrivateKey = priv
return pk return pk
} }
func NewECDSAPrivateKey(currentTime time.Time, priv *ecdsa.PrivateKey) *PrivateKey { func NewECDSAPrivateKey(creationTime time.Time, priv *ecdsa.PrivateKey) *PrivateKey {
pk := new(PrivateKey) pk := new(PrivateKey)
pk.PublicKey = *NewECDSAPublicKey(currentTime, &priv.PublicKey) pk.PublicKey = *NewECDSAPublicKey(creationTime, &priv.PublicKey)
pk.PrivateKey = priv pk.PrivateKey = priv
return pk return pk
} }
// NewSignerPrivateKey creates a PrivateKey from a crypto.Signer that // NewSignerPrivateKey creates a PrivateKey from a crypto.Signer that
// implements RSA or ECDSA. // 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) pk := new(PrivateKey)
// In general, the public Keys should be used as pointers. We still // In general, the public Keys should be used as pointers. We still
// type-switch on the values, for backwards-compatibility. // type-switch on the values, for backwards-compatibility.
switch pubkey := signer.Public().(type) { switch pubkey := signer.Public().(type) {
case *rsa.PublicKey: case *rsa.PublicKey:
<<<<<<< HEAD
pk.PublicKey = *NewRSAPublicKey(currentTime, pubkey) pk.PublicKey = *NewRSAPublicKey(currentTime, pubkey)
case rsa.PublicKey: case rsa.PublicKey:
pk.PublicKey = *NewRSAPublicKey(currentTime, &pubkey) pk.PublicKey = *NewRSAPublicKey(currentTime, &pubkey)
case *ecdsa.PublicKey: case *ecdsa.PublicKey:
pk.PublicKey = *NewECDSAPublicKey(currentTime, pubkey) pk.PublicKey = *NewECDSAPublicKey(currentTime, pubkey)
=======
pk.PublicKey = *NewRSAPublicKey(creationTime, pubkey)
case rsa.PublicKey:
pk.PublicKey = *NewRSAPublicKey(creationTime, &pubkey)
case *ecdsa.PublicKey:
pk.PublicKey = *NewECDSAPublicKey(creationTime, pubkey)
>>>>>>> bd25a1f6d07d2d464980e6a8576c1ed59bb3950a
case ecdsa.PublicKey: case ecdsa.PublicKey:
pk.PublicKey = *NewECDSAPublicKey(currentTime, &pubkey) pk.PublicKey = *NewECDSAPublicKey(creationTime, &pubkey)
default: default:
panic("openpgp: unknown crypto.Signer type in NewSignerPrivateKey") 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 // Package otr implements the Off The Record protocol as specified in
// http://www.cypherpunks.ca/otr/Protocol-v2-3.1.0.html // 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" package otr // import "golang.org/x/crypto/otr"
import ( import (
@ -637,7 +641,7 @@ func (c *Conversation) serializeDHKey() []byte {
} }
func (c *Conversation) processDHKey(in []byte) (isSame bool, err error) { func (c *Conversation) processDHKey(in []byte) (isSame bool, err error) {
gy, in, ok := getMPI(in) gy, _, ok := getMPI(in)
if !ok { if !ok {
err = errors.New("otr: corrupt DH key message") err = errors.New("otr: corrupt DH key message")
return return

View File

@ -7,6 +7,9 @@
// This implementation is distilled from https://tools.ietf.org/html/rfc7292 // This implementation is distilled from https://tools.ietf.org/html/rfc7292
// and referenced documents. It is intended for decoding P12/PFX-stored // and referenced documents. It is intended for decoding P12/PFX-stored
// certificates and keys for use with the crypto/tls package. // 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 package pkcs12
import ( import (
@ -100,7 +103,7 @@ func unmarshal(in []byte, out interface{}) error {
return nil 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) { func ToPEM(pfxData []byte, password string) ([]*pem.Block, error) {
encodedPassword, err := bmpString(password) encodedPassword, err := bmpString(password)
if err != nil { 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 // 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 // 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) { func Decode(pfxData []byte, password string) (privateKey interface{}, certificate *x509.Certificate, err error) {
encodedPassword, err := bmpString(password) encodedPassword, err := bmpString(password)
if err != nil { if err != nil {

View File

@ -0,0 +1,11 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !amd64 gccgo appengine
package poly1305
type mac struct{ macGeneric }
func newMAC(key *[32]byte) mac { return mac{newMACGeneric(key)} }

View File

@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
<<<<<<< HEAD
/* /*
Package poly1305 implements Poly1305 one-time message authentication code as Package poly1305 implements Poly1305 one-time message authentication code as
specified in https://cr.yp.to/mac/poly1305-20050329.pdf. specified in https://cr.yp.to/mac/poly1305-20050329.pdf.
@ -17,6 +18,21 @@ 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 However, in this package AES isn't used and the one-time key is specified
directly. 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.
>>>>>>> bd25a1f6d07d2d464980e6a8576c1ed59bb3950a
package poly1305 // import "golang.org/x/crypto/poly1305" package poly1305 // import "golang.org/x/crypto/poly1305"
import "crypto/subtle" import "crypto/subtle"
@ -31,3 +47,55 @@ func Verify(mac *[16]byte, m []byte, key *[32]byte) bool {
Sum(&tmp, m, key) Sum(&tmp, m, key)
return subtle.ConstantTimeCompare(tmp[:], mac[:]) == 1 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 TestSumGeneric(t *testing.T) { testSum(t, false, sumGeneric) }
func TestSumGenericUnaligned(t *testing.T) { testSum(t, true, 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 out [16]byte
var key [32]byte var key [32]byte
in := make([]byte, size) in := make([]byte, size)
@ -114,11 +157,41 @@ func benchmark(b *testing.B, size int, unaligned bool) {
} }
} }
<<<<<<< HEAD
func Benchmark64(b *testing.B) { benchmark(b, 64, false) } func Benchmark64(b *testing.B) { benchmark(b, 64, false) }
func Benchmark1K(b *testing.B) { benchmark(b, 1024, false) } func Benchmark1K(b *testing.B) { benchmark(b, 1024, false) }
func Benchmark64Unaligned(b *testing.B) { benchmark(b, 64, true) } func Benchmark64Unaligned(b *testing.B) { benchmark(b, 64, true) }
func Benchmark1KUnaligned(b *testing.B) { benchmark(b, 1024, true) } func Benchmark1KUnaligned(b *testing.B) { benchmark(b, 1024, true) }
func Benchmark2M(b *testing.B) { benchmark(b, 2097152, 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) }
>>>>>>> bd25a1f6d07d2d464980e6a8576c1ed59bb3950a
func unalignBytes(in []byte) []byte { func unalignBytes(in []byte) []byte {
out := make([]byte, len(in)+1) out := make([]byte, len(in)+1)

View File

@ -6,17 +6,63 @@
package poly1305 package poly1305
// This function is implemented in sum_amd64.s
//go:noescape //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 // 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 // 16-byte result into out. Authenticating two different messages with the same
// key allows an attacker to forge messages at will. // key allows an attacker to forge messages at will.
func Sum(out *[16]byte, m []byte, key *[32]byte) { func Sum(out *[16]byte, m []byte, key *[32]byte) {
var mPtr *byte h := newMAC(key)
if len(m) > 0 { h.Write(m)
mPtr = &m[0] h.Sum(out)
} }
poly1305(out, mPtr, uint64(len(m)), key)
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 DATA ·poly1305Mask<>+0x08(SB)/8, $0x0FFFFFFC0FFFFFFC
GLOBL ·poly1305Mask<>(SB), RODATA, $16 GLOBL ·poly1305Mask<>(SB), RODATA, $16
// func poly1305(out *[16]byte, m *byte, mlen uint64, key *[32]key) // func update(state *[7]uint64, msg []byte)
TEXT ·poly1305(SB), $0-32 TEXT ·update(SB), $0-32
MOVQ out+0(FP), DI MOVQ state+0(FP), DI
MOVQ m+8(FP), SI MOVQ msg_base+8(FP), SI
MOVQ mlen+16(FP), R15 MOVQ msg_len+16(FP), R15
MOVQ key+24(FP), AX
MOVQ 0(AX), R11 MOVQ 0(DI), R8 // h0
MOVQ 8(AX), R12 MOVQ 8(DI), R9 // h1
ANDQ ·poly1305Mask<>(SB), R11 // r0 MOVQ 16(DI), R10 // h2
ANDQ ·poly1305Mask<>+8(SB), R12 // r1 MOVQ 24(DI), R11 // r0
XORQ R8, R8 // h0 MOVQ 32(DI), R12 // r1
XORQ R9, R9 // h1
XORQ R10, R10 // h2
CMPQ R15, $16 CMPQ R15, $16
JB bytes_between_0_and_15 JB bytes_between_0_and_15
@ -109,16 +106,42 @@ flush_buffer:
JMP multiply JMP multiply
done: done:
MOVQ R8, AX MOVQ R8, 0(DI)
MOVQ R9, BX 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 SUBQ $0xFFFFFFFFFFFFFFFB, AX
SBBQ $0xFFFFFFFFFFFFFFFF, BX SBBQ $0xFFFFFFFFFFFFFFFF, BX
SBBQ $3, R10 SBBQ $3, CX
CMOVQCS R8, AX CMOVQCS R8, AX
CMOVQCS R9, BX CMOVQCS R9, BX
MOVQ key+24(FP), R8 ADDQ 40(SI), AX
ADDQ 16(R8), AX ADCQ 48(SI), BX
ADCQ 24(R8), BX
MOVQ AX, 0(DI) MOVQ AX, 0(DI)
MOVQ BX, 8(DI) MOVQ BX, 8(DI)

View File

@ -0,0 +1,172 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package poly1305
import "encoding/binary"
const (
msgBlock = uint32(1 << 24)
finalBlock = uint32(0)
)
// sumGeneric generates an authenticator for msg using a one-time key and
// puts the 16-byte result into out. This is the generic implementation of
// Sum and should be called if no assembly implementation is available.
func sumGeneric(out *[TagSize]byte, msg []byte, key *[32]byte) {
h := newMACGeneric(key)
h.Write(msg)
h.Sum(out)
}
func newMACGeneric(key *[32]byte) (h macGeneric) {
h.r[0] = binary.LittleEndian.Uint32(key[0:]) & 0x3ffffff
h.r[1] = (binary.LittleEndian.Uint32(key[3:]) >> 2) & 0x3ffff03
h.r[2] = (binary.LittleEndian.Uint32(key[6:]) >> 4) & 0x3ffc0ff
h.r[3] = (binary.LittleEndian.Uint32(key[9:]) >> 6) & 0x3f03fff
h.r[4] = (binary.LittleEndian.Uint32(key[12:]) >> 8) & 0x00fffff
h.s[0] = binary.LittleEndian.Uint32(key[16:])
h.s[1] = binary.LittleEndian.Uint32(key[20:])
h.s[2] = binary.LittleEndian.Uint32(key[24:])
h.s[3] = binary.LittleEndian.Uint32(key[28:])
return
}
type macGeneric struct {
h, r [5]uint32
s [4]uint32
buffer [TagSize]byte
offset int
}
func (h *macGeneric) Write(p []byte) (n int, err error) {
n = len(p)
if h.offset > 0 {
remaining := TagSize - h.offset
if n < remaining {
h.offset += copy(h.buffer[h.offset:], p)
return n, nil
}
copy(h.buffer[h.offset:], p[:remaining])
p = p[remaining:]
h.offset = 0
updateGeneric(h.buffer[:], msgBlock, &(h.h), &(h.r))
}
if nn := len(p) - (len(p) % TagSize); nn > 0 {
updateGeneric(p, msgBlock, &(h.h), &(h.r))
p = p[nn:]
}
if len(p) > 0 {
h.offset += copy(h.buffer[h.offset:], p)
}
return n, nil
}
func (h *macGeneric) Sum(out *[16]byte) {
H, R := h.h, h.r
if h.offset > 0 {
var buffer [TagSize]byte
copy(buffer[:], h.buffer[:h.offset])
buffer[h.offset] = 1 // invariant: h.offset < TagSize
updateGeneric(buffer[:], finalBlock, &H, &R)
}
finalizeGeneric(out, &H, &(h.s))
}
func updateGeneric(msg []byte, flag uint32, h, r *[5]uint32) {
h0, h1, h2, h3, h4 := h[0], h[1], h[2], h[3], h[4]
r0, r1, r2, r3, r4 := uint64(r[0]), uint64(r[1]), uint64(r[2]), uint64(r[3]), uint64(r[4])
R1, R2, R3, R4 := r1*5, r2*5, r3*5, r4*5
for len(msg) >= TagSize {
// h += msg
h0 += binary.LittleEndian.Uint32(msg[0:]) & 0x3ffffff
h1 += (binary.LittleEndian.Uint32(msg[3:]) >> 2) & 0x3ffffff
h2 += (binary.LittleEndian.Uint32(msg[6:]) >> 4) & 0x3ffffff
h3 += (binary.LittleEndian.Uint32(msg[9:]) >> 6) & 0x3ffffff
h4 += (binary.LittleEndian.Uint32(msg[12:]) >> 8) | flag
// h *= r
d0 := (uint64(h0) * r0) + (uint64(h1) * R4) + (uint64(h2) * R3) + (uint64(h3) * R2) + (uint64(h4) * R1)
d1 := (d0 >> 26) + (uint64(h0) * r1) + (uint64(h1) * r0) + (uint64(h2) * R4) + (uint64(h3) * R3) + (uint64(h4) * R2)
d2 := (d1 >> 26) + (uint64(h0) * r2) + (uint64(h1) * r1) + (uint64(h2) * r0) + (uint64(h3) * R4) + (uint64(h4) * R3)
d3 := (d2 >> 26) + (uint64(h0) * r3) + (uint64(h1) * r2) + (uint64(h2) * r1) + (uint64(h3) * r0) + (uint64(h4) * R4)
d4 := (d3 >> 26) + (uint64(h0) * r4) + (uint64(h1) * r3) + (uint64(h2) * r2) + (uint64(h3) * r1) + (uint64(h4) * r0)
// h %= p
h0 = uint32(d0) & 0x3ffffff
h1 = uint32(d1) & 0x3ffffff
h2 = uint32(d2) & 0x3ffffff
h3 = uint32(d3) & 0x3ffffff
h4 = uint32(d4) & 0x3ffffff
h0 += uint32(d4>>26) * 5
h1 += h0 >> 26
h0 = h0 & 0x3ffffff
msg = msg[TagSize:]
}
h[0], h[1], h[2], h[3], h[4] = h0, h1, h2, h3, h4
}
func finalizeGeneric(out *[TagSize]byte, h *[5]uint32, s *[4]uint32) {
h0, h1, h2, h3, h4 := h[0], h[1], h[2], h[3], h[4]
// h %= p reduction
h2 += h1 >> 26
h1 &= 0x3ffffff
h3 += h2 >> 26
h2 &= 0x3ffffff
h4 += h3 >> 26
h3 &= 0x3ffffff
h0 += 5 * (h4 >> 26)
h4 &= 0x3ffffff
h1 += h0 >> 26
h0 &= 0x3ffffff
// h - p
t0 := h0 + 5
t1 := h1 + (t0 >> 26)
t2 := h2 + (t1 >> 26)
t3 := h3 + (t2 >> 26)
t4 := h4 + (t3 >> 26) - (1 << 26)
t0 &= 0x3ffffff
t1 &= 0x3ffffff
t2 &= 0x3ffffff
t3 &= 0x3ffffff
// select h if h < p else h - p
t_mask := (t4 >> 31) - 1
h_mask := ^t_mask
h0 = (h0 & h_mask) | (t0 & t_mask)
h1 = (h1 & h_mask) | (t1 & t_mask)
h2 = (h2 & h_mask) | (t2 & t_mask)
h3 = (h3 & h_mask) | (t3 & t_mask)
h4 = (h4 & h_mask) | (t4 & t_mask)
// h %= 2^128
h0 |= h1 << 26
h1 = ((h1 >> 6) | (h2 << 20))
h2 = ((h2 >> 12) | (h3 << 14))
h3 = ((h3 >> 18) | (h4 << 8))
// s: the s part of the key
// tag = (h + s) % (2^128)
t := uint64(h0) + uint64(s[0])
h0 = uint32(t)
t = uint64(h1) + uint64(s[1]) + (t >> 32)
h1 = uint32(t)
t = uint64(h2) + uint64(s[2]) + (t >> 32)
h2 = uint32(t)
t = uint64(h3) + uint64(s[3]) + (t >> 32)
h3 = uint32(t)
binary.LittleEndian.PutUint32(out[0:], h0)
binary.LittleEndian.PutUint32(out[4:], h1)
binary.LittleEndian.PutUint32(out[8:], h2)
binary.LittleEndian.PutUint32(out[12:], h3)
}

View File

@ -10,5 +10,11 @@ package poly1305
// 16-byte result into out. Authenticating two different messages with the same // 16-byte result into out. Authenticating two different messages with the same
// key allows an attacker to forge messages at will. // key allows an attacker to forge messages at will.
func Sum(out *[TagSize]byte, msg []byte, key *[32]byte) { func Sum(out *[TagSize]byte, msg []byte, key *[32]byte) {
<<<<<<< HEAD
sumGeneric(out, msg, key) sumGeneric(out, msg, key)
=======
h := newMAC(key)
h.Write(msg)
h.Sum(out)
>>>>>>> bd25a1f6d07d2d464980e6a8576c1ed59bb3950a
} }

View File

@ -6,6 +6,7 @@
package poly1305 package poly1305
<<<<<<< HEAD
// hasVectorFacility reports whether the machine supports // hasVectorFacility reports whether the machine supports
// the vector facility (vx). // the vector facility (vx).
func hasVectorFacility() bool func hasVectorFacility() bool
@ -16,6 +17,11 @@ func hasVMSLFacility() bool
var hasVX = hasVectorFacility() var hasVX = hasVectorFacility()
var hasVMSL = hasVMSLFacility() var hasVMSL = hasVMSLFacility()
=======
import (
"golang.org/x/sys/cpu"
)
>>>>>>> bd25a1f6d07d2d464980e6a8576c1ed59bb3950a
// poly1305vx is an assembly implementation of Poly1305 that uses vector // poly1305vx is an assembly implementation of Poly1305 that uses vector
// instructions. It must only be called if the vector facility (vx) is // instructions. It must only be called if the vector facility (vx) is
@ -33,12 +39,20 @@ func poly1305vmsl(out *[16]byte, m *byte, mlen uint64, key *[32]byte)
// 16-byte result into out. Authenticating two different messages with the same // 16-byte result into out. Authenticating two different messages with the same
// key allows an attacker to forge messages at will. // key allows an attacker to forge messages at will.
func Sum(out *[16]byte, m []byte, key *[32]byte) { func Sum(out *[16]byte, m []byte, key *[32]byte) {
<<<<<<< HEAD
if hasVX { if hasVX {
=======
if cpu.S390X.HasVX {
>>>>>>> bd25a1f6d07d2d464980e6a8576c1ed59bb3950a
var mPtr *byte var mPtr *byte
if len(m) > 0 { if len(m) > 0 {
mPtr = &m[0] mPtr = &m[0]
} }
<<<<<<< HEAD
if hasVMSL && len(m) > 256 { if hasVMSL && len(m) > 256 {
=======
if cpu.S390X.HasVXE && len(m) > 256 {
>>>>>>> bd25a1f6d07d2d464980e6a8576c1ed59bb3950a
poly1305vmsl(out, mPtr, uint64(len(m)), key) poly1305vmsl(out, mPtr, uint64(len(m)), key)
} else { } else {
poly1305vx(out, mPtr, uint64(len(m)), key) poly1305vx(out, mPtr, uint64(len(m)), key)

View File

@ -376,6 +376,7 @@ b1:
MOVD $0, R3 MOVD $0, R3
BR multiply BR multiply
<<<<<<< HEAD
TEXT ·hasVectorFacility(SB), NOSPLIT, $24-1 TEXT ·hasVectorFacility(SB), NOSPLIT, $24-1
MOVD $x-24(SP), R1 MOVD $x-24(SP), R1
@ -398,3 +399,5 @@ vectorinstalled:
novector: novector:
MOVB $0, ret+0(FP) // no vx MOVB $0, ret+0(FP) // no vx
RET RET
=======
>>>>>>> bd25a1f6d07d2d464980e6a8576c1ed59bb3950a

View File

@ -907,6 +907,7 @@ 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) 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) REDUCE2(H0_0, H1_0, H2_0, M0, M1, M2, M3, M4, T_9, T_10, H0_1, M5)
BR next BR next
<<<<<<< HEAD
TEXT ·hasVMSLFacility(SB), NOSPLIT, $24-1 TEXT ·hasVMSLFacility(SB), NOSPLIT, $24-1
MOVD $x-24(SP), R1 MOVD $x-24(SP), R1
@ -929,3 +930,5 @@ vectorinstalled:
novmsl: novmsl:
MOVB $0, ret+0(FP) // no vx MOVB $0, ret+0(FP) // no vx
RET RET
=======
>>>>>>> bd25a1f6d07d2d464980e6a8576c1ed59bb3950a

View File

@ -3,6 +3,10 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// Package ripemd160 implements the RIPEMD-160 hash algorithm. // 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" package ripemd160 // import "golang.org/x/crypto/ripemd160"
// RIPEMD-160 is designed by Hans Dobbertin, Antoon Bosselaers, and Bart // RIPEMD-160 is designed by Hans Dobbertin, Antoon Bosselaers, and Bart

View File

@ -6,10 +6,9 @@
package salsa package salsa
// This function is implemented in salsa2020_amd64.s.
//go:noescape //go:noescape
// salsa2020XORKeyStream is implemented in salsa20_amd64.s.
func salsa2020XORKeyStream(out, in *byte, n uint64, nonce, key *byte) func salsa2020XORKeyStream(out, in *byte, n uint64, nonce, key *byte)
// XORKeyStream crypts bytes from in to out using the given key and counters. // 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 36 (SP),CX
MOVL DX,288(SP) MOVL DX,288(SP)
MOVL CX,304(SP) MOVL CX,304(SP)
ADDQ $1,DX
SHLQ $32,CX SHLQ $32,CX
ADDQ CX,DX ADDQ CX,DX
ADDQ $1,DX
MOVQ DX,CX MOVQ DX,CX
SHRQ $32,CX SHRQ $32,CX
MOVL DX, 292 (SP) MOVL DX, 292 (SP)
MOVL CX, 308 (SP) MOVL CX, 308 (SP)
ADDQ $1,DX ADDQ $1,DX
SHLQ $32,CX
ADDQ CX,DX
MOVQ DX,CX MOVQ DX,CX
SHRQ $32,CX SHRQ $32,CX
MOVL DX, 296 (SP) MOVL DX, 296 (SP)
MOVL CX, 312 (SP) MOVL CX, 312 (SP)
ADDQ $1,DX ADDQ $1,DX
SHLQ $32,CX
ADDQ CX,DX
MOVQ DX,CX MOVQ DX,CX
SHRQ $32,CX SHRQ $32,CX
MOVL DX, 300 (SP) MOVL DX, 300 (SP)
MOVL CX, 316 (SP) MOVL CX, 316 (SP)
ADDQ $1,DX ADDQ $1,DX
SHLQ $32,CX
ADDQ CX,DX
MOVQ DX,CX MOVQ DX,CX
SHRQ $32,CX SHRQ $32,CX
MOVL DX,16(SP) 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 // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !amd64 appengine gccgo
package salsa package salsa
const rounds = 20 const rounds = 20
@ -202,10 +200,16 @@ func core(out *[64]byte, in *[16]byte, k *[32]byte, c *[16]byte) {
out[63] = byte(x15 >> 24) out[63] = byte(x15 >> 24)
} }
<<<<<<< HEAD
// XORKeyStream crypts bytes from in to out using the given key and counters. // XORKeyStream crypts bytes from in to out using the given key and counters.
// In and out must overlap entirely or not at all. Counter // In and out must overlap entirely or not at all. Counter
// contains the raw salsa20 counter bytes (both nonce and block counter). // contains the raw salsa20 counter bytes (both nonce and block counter).
func XORKeyStream(out, in []byte, counter *[16]byte, key *[32]byte) { 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) {
>>>>>>> bd25a1f6d07d2d464980e6a8576c1ed59bb3950a
var block [64]byte var block [64]byte
var counterCopy [16]byte var counterCopy [16]byte
copy(counterCopy[:], counter[:]) copy(counterCopy[:], counter[:])

View File

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

View File

@ -57,6 +57,15 @@ func New512() hash.Hash {
// Only use this function if you require compatibility with an existing cryptosystem // Only use this function if you require compatibility with an existing cryptosystem
// that uses non-standard padding. All other users should use New256 instead. // that uses non-standard padding. All other users should use New256 instead.
func NewLegacyKeccak256() hash.Hash { return &state{rate: 136, outputLen: 32, dsbyte: 0x01} } func NewLegacyKeccak256() hash.Hash { return &state{rate: 136, outputLen: 32, dsbyte: 0x01} }
<<<<<<< HEAD
=======
// 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} }
>>>>>>> bd25a1f6d07d2d464980e6a8576c1ed59bb3950a
// Sum224 returns the SHA3-224 digest of the data. // Sum224 returns the SHA3-224 digest of the data.
func Sum224(data []byte) (digest [28]byte) { func Sum224(data []byte) (digest [28]byte) {

View File

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

View File

@ -6,6 +6,7 @@
#include "textflag.h" #include "textflag.h"
<<<<<<< HEAD
TEXT ·hasMSA6(SB), NOSPLIT, $16-1 TEXT ·hasMSA6(SB), NOSPLIT, $16-1
MOVD $0, R0 // KIMD-Query function code MOVD $0, R0 // KIMD-Query function code
MOVD $tmp-16(SP), R1 // parameter block MOVD $tmp-16(SP), R1 // parameter block
@ -26,6 +27,12 @@ yes:
TEXT ·kimd(SB), NOFRAME|NOSPLIT, $0-40 TEXT ·kimd(SB), NOFRAME|NOSPLIT, $0-40
MOVD function+0(FP), R0 MOVD function+0(FP), R0
MOVD params+8(FP), R1 MOVD params+8(FP), R1
=======
// func kimd(function code, chain *[200]byte, src []byte)
TEXT ·kimd(SB), NOFRAME|NOSPLIT, $0-40
MOVD function+0(FP), R0
MOVD chain+8(FP), R1
>>>>>>> bd25a1f6d07d2d464980e6a8576c1ed59bb3950a
LMG src+16(FP), R2, R3 // R2=base, R3=len LMG src+16(FP), R2, R3 // R2=base, R3=len
continue: continue:
@ -34,11 +41,19 @@ continue:
MOVD $0, R0 // reset R0 for pre-go1.8 compilers MOVD $0, R0 // reset R0 for pre-go1.8 compilers
RET RET
<<<<<<< HEAD
// func klmd(function code, params *[200]byte, dst, src []byte) // func klmd(function code, params *[200]byte, dst, src []byte)
TEXT ·klmd(SB), NOFRAME|NOSPLIT, $0-64 TEXT ·klmd(SB), NOFRAME|NOSPLIT, $0-64
// TODO: SHAKE support // TODO: SHAKE support
MOVD function+0(FP), R0 MOVD function+0(FP), R0
MOVD params+8(FP), R1 MOVD params+8(FP), R1
=======
// 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 chain+8(FP), R1
>>>>>>> bd25a1f6d07d2d464980e6a8576c1ed59bb3950a
LMG dst+16(FP), R2, R3 // R2=base, R3=len LMG dst+16(FP), R2, R3 // R2=base, R3=len
LMG src+40(FP), R4, R5 // R4=base, R5=len LMG src+40(FP), R4, R5 // R4=base, R5=len

View File

@ -27,14 +27,6 @@ const (
katFilename = "testdata/keccakKats.json.deflate" 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 // testDigests contains functions returning hash.Hash instances
// with output-length equal to the KAT length for SHA-3, Keccak // with output-length equal to the KAT length for SHA-3, Keccak
// and SHAKE instances. // and SHAKE instances.
@ -44,15 +36,26 @@ var testDigests = map[string]func() hash.Hash{
"SHA3-384": New384, "SHA3-384": New384,
"SHA3-512": New512, "SHA3-512": New512,
"Keccak-256": NewLegacyKeccak256, "Keccak-256": NewLegacyKeccak256,
<<<<<<< HEAD
"SHAKE128": newHashShake128, "SHAKE128": newHashShake128,
"SHAKE256": newHashShake256, "SHAKE256": newHashShake256,
=======
"Keccak-512": NewLegacyKeccak512,
>>>>>>> bd25a1f6d07d2d464980e6a8576c1ed59bb3950a
} }
// testShakes contains functions that return ShakeHash instances for // testShakes contains functions that return sha3.ShakeHash instances for
// testing the ShakeHash-specific interface. // with output-length equal to the KAT length.
var testShakes = map[string]func() ShakeHash{ var testShakes = map[string]struct {
"SHAKE128": NewShake128, constructor func(N []byte, S []byte) ShakeHash
"SHAKE256": NewShake256, 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. // decodeHex converts a hex-encoded string into a raw byte string.
@ -70,6 +73,10 @@ type KeccakKats struct {
Digest string `json:"digest"` Digest string `json:"digest"`
Length int64 `json:"length"` Length int64 `json:"length"`
Message string `json:"message"` Message string `json:"message"`
// Defined only for cSHAKE
N string `json:"N"`
S string `json:"S"`
} }
} }
@ -102,10 +109,9 @@ func TestKeccakKats(t *testing.T) {
t.Errorf("error decoding KATs: %s", err) t.Errorf("error decoding KATs: %s", err)
} }
// Do the KATs. for algo, function := range testDigests {
for functionName, kats := range katSet.Kats { d := function()
d := testDigests[functionName]() for _, kat := range katSet.Kats[algo] {
for _, kat := range kats {
d.Reset() d.Reset()
in, err := hex.DecodeString(kat.Message) in, err := hex.DecodeString(kat.Message)
if err != nil { if err != nil {
@ -114,8 +120,39 @@ func TestKeccakKats(t *testing.T) {
d.Write(in[:kat.Length/8]) d.Write(in[:kat.Length/8])
got := strings.ToUpper(hex.EncodeToString(d.Sum(nil))) got := strings.ToUpper(hex.EncodeToString(d.Sum(nil)))
if got != kat.Digest { if got != kat.Digest {
t.Errorf("function=%s, implementation=%s, length=%d\nmessage:\n %s\ngot:\n %s\nwanted:\n %s", 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) 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.Logf("wanted %+v", kat)
t.FailNow() t.FailNow()
} }
@ -137,6 +174,14 @@ func TestKeccak(t *testing.T) {
[]byte("abc"), []byte("abc"),
"4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45", "4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45",
}, },
<<<<<<< HEAD
=======
{
NewLegacyKeccak512,
[]byte("abc"),
"18587dc2ea106b9a1563e32b3312421ca164c7f1f07bc922a9c83d77cea3a1e5d0c69910739025372dc14ac9642629379540c17e2a65b19d77aa511a9d00bb96",
},
>>>>>>> bd25a1f6d07d2d464980e6a8576c1ed59bb3950a
} }
for _, u := range tests { for _, u := range tests {
@ -178,6 +223,34 @@ func TestUnalignedWrite(t *testing.T) {
t.Errorf("Unaligned writes, implementation=%s, alg=%s\ngot %q, want %q", impl, alg, got, want) 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 +292,13 @@ func TestAppendNoRealloc(t *testing.T) {
// the same output as repeatedly squeezing the instance. // the same output as repeatedly squeezing the instance.
func TestSqueezing(t *testing.T) { func TestSqueezing(t *testing.T) {
testUnalignedAndGeneric(t, func(impl string) { testUnalignedAndGeneric(t, func(impl string) {
for functionName, newShakeHash := range testShakes { for algo, v := range testShakes {
d0 := newShakeHash() d0 := v.constructor([]byte(v.defAlgoName), []byte(v.defCustomStr))
d0.Write([]byte(testString)) d0.Write([]byte(testString))
ref := make([]byte, 32) ref := make([]byte, 32)
d0.Read(ref) d0.Read(ref)
d1 := newShakeHash() d1 := v.constructor([]byte(v.defAlgoName), []byte(v.defCustomStr))
d1.Write([]byte(testString)) d1.Write([]byte(testString))
var multiple []byte var multiple []byte
for range ref { for range ref {
@ -234,7 +307,7 @@ func TestSqueezing(t *testing.T) {
multiple = append(multiple, one...) multiple = append(multiple, one...)
} }
if !bytes.Equal(ref, multiple) { 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 +322,50 @@ func sequentialBytes(size int) []byte {
return result 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 // BenchmarkPermutationFunction measures the speed of the permutation function
// with no input data. // with no input data.
func BenchmarkPermutationFunction(b *testing.B) { func BenchmarkPermutationFunction(b *testing.B) {
@ -334,4 +451,41 @@ func Example_mac() {
d.Read(h) d.Read(h)
fmt.Printf("%x\n", h) fmt.Printf("%x\n", h)
// Output: 78de2974bd2711d5549ffd32b753ef0f5fa80a0db2556db60f0987eb8a9218ff // Output: 78de2974bd2711d5549ffd32b753ef0f5fa80a0db2556db60f0987eb8a9218ff
<<<<<<< HEAD
=======
}
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
>>>>>>> bd25a1f6d07d2d464980e6a8576c1ed59bb3950a
} }

View File

@ -5,10 +5,18 @@
package sha3 package sha3
// This file defines the ShakeHash interface, and provides // 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. // 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 ( import (
"encoding/binary"
"io" "io"
) )
@ -31,8 +39,77 @@ type ShakeHash interface {
Reset() Reset()
} }
func (d *state) Clone() ShakeHash { // cSHAKE specific context
return d.clone() 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. // NewShake128 creates a new SHAKE128 variable-output-length ShakeHash.
@ -42,7 +119,11 @@ func NewShake128() ShakeHash {
if h := newShake128Asm(); h != nil { if h := newShake128Asm(); h != nil {
return h return h
} }
<<<<<<< HEAD
return &state{rate: 168, dsbyte: 0x1f} return &state{rate: 168, dsbyte: 0x1f}
=======
return &state{rate: rate128, dsbyte: dsbyteShake}
>>>>>>> bd25a1f6d07d2d464980e6a8576c1ed59bb3950a
} }
// NewShake256 creates a new SHAKE256 variable-output-length ShakeHash. // NewShake256 creates a new SHAKE256 variable-output-length ShakeHash.
@ -52,7 +133,37 @@ func NewShake256() ShakeHash {
if h := newShake256Asm(); h != nil { if h := newShake256Asm(); h != nil {
return h return h
} }
<<<<<<< HEAD
return &state{rate: 136, dsbyte: 0x1f} 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)
>>>>>>> bd25a1f6d07d2d464980e6a8576c1ed59bb3950a
} }
// ShakeSum128 writes an arbitrary-length digest of data into hash. // ShakeSum128 writes an arbitrary-length digest of data into hash.

Binary file not shown.

View File

@ -8,11 +8,13 @@ import (
"bytes" "bytes"
"crypto/rand" "crypto/rand"
"errors" "errors"
"io"
"net" "net"
"os" "os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
"strconv" "strconv"
"sync"
"testing" "testing"
"time" "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) { func TestAgent(t *testing.T) {
for _, keyType := range []string{"rsa", "dsa", "ecdsa", "ed25519"} { for _, keyType := range []string{"rsa", "dsa", "ecdsa", "ed25519"} {
testOpenSSHAgent(t, testPrivateKeys[keyType], nil, 0) testOpenSSHAgent(t, testPrivateKeys[keyType], nil, 0)
@ -215,17 +274,26 @@ func TestCert(t *testing.T) {
testKeyringAgent(t, testPrivateKeys["rsa"], cert, 0) testKeyringAgent(t, testPrivateKeys["rsa"], cert, 0)
} }
// netPipe is analogous to net.Pipe, but it uses a real net.Conn, and // netListener creates a localhost network listener.
// therefore is buffered (net.Pipe deadlocks if both sides start with func netListener() (net.Listener, error) {
// a write.)
func netPipe() (net.Conn, net.Conn, error) {
listener, err := net.Listen("tcp", "127.0.0.1:0") listener, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil { if err != nil {
listener, err = net.Listen("tcp", "[::1]:0") listener, err = net.Listen("tcp", "[::1]:0")
if err != nil { 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() defer listener.Close()
c1, err := net.Dial("tcp", listener.Addr().String()) c1, err := net.Dial("tcp", listener.Addr().String())
if err != nil { if err != nil {
@ -444,14 +512,22 @@ func (r *keyringExtended) Extension(extensionType string, contents []byte) ([]by
func TestAgentExtensions(t *testing.T) { func TestAgentExtensions(t *testing.T) {
agent, _, cleanup := startOpenSSHAgent(t) agent, _, cleanup := startOpenSSHAgent(t)
defer cleanup() defer cleanup()
<<<<<<< HEAD
result, err := agent.Extension("my-extension@example.com", []byte{0x00, 0x01, 0x02}) result, err := agent.Extension("my-extension@example.com", []byte{0x00, 0x01, 0x02})
=======
_, err := agent.Extension("my-extension@example.com", []byte{0x00, 0x01, 0x02})
>>>>>>> bd25a1f6d07d2d464980e6a8576c1ed59bb3950a
if err == nil { if err == nil {
t.Fatal("should have gotten agent extension failure") t.Fatal("should have gotten agent extension failure")
} }
agent, cleanup = startAgent(t, &keyringExtended{}) agent, cleanup = startAgent(t, &keyringExtended{})
defer cleanup() defer cleanup()
<<<<<<< HEAD
result, err = agent.Extension("my-extension@example.com", []byte{0x00, 0x01, 0x02}) result, err = agent.Extension("my-extension@example.com", []byte{0x00, 0x01, 0x02})
=======
result, err := agent.Extension("my-extension@example.com", []byte{0x00, 0x01, 0x02})
>>>>>>> bd25a1f6d07d2d464980e6a8576c1ed59bb3950a
if err != nil { if err != nil {
t.Fatalf("agent extension failure: %v", err) t.Fatalf("agent extension failure: %v", err)
} }
@ -459,7 +535,11 @@ func TestAgentExtensions(t *testing.T) {
t.Fatalf("agent extension result invalid: %v", result) t.Fatalf("agent extension result invalid: %v", result)
} }
<<<<<<< HEAD
result, err = agent.Extension("bad-extension@example.com", []byte{0x00, 0x01, 0x02}) result, err = agent.Extension("bad-extension@example.com", []byte{0x00, 0x01, 0x02})
=======
_, err = agent.Extension("bad-extension@example.com", []byte{0x00, 0x01, 0x02})
>>>>>>> bd25a1f6d07d2d464980e6a8576c1ed59bb3950a
if err == nil { if err == nil {
t.Fatal("should have gotten agent extension failure") t.Fatal("should have gotten agent extension failure")
} }

View File

@ -541,6 +541,9 @@ func ServeAgent(agent Agent, c io.ReadWriter) error {
return err return err
} }
l := binary.BigEndian.Uint32(length[:]) l := binary.BigEndian.Uint32(length[:])
if l == 0 {
return fmt.Errorf("agent: request size is 0")
}
if l > maxAgentResponseBytes { if l > maxAgentResponseBytes {
// We also cap requests. // We also cap requests.
return fmt.Errorf("agent: request too large: %d", l) 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) b.Fatalf("Client: %v", err)
} }
ch, incoming, err := newCh.Accept() ch, incoming, err := newCh.Accept()
if err != nil {
b.Fatalf("Accept: %v", err)
}
go DiscardRequests(incoming) go DiscardRequests(incoming)
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
if _, err := io.ReadFull(ch, output); err != nil { if _, err := io.ReadFull(ch, output); err != nil {

View File

@ -149,8 +149,8 @@ type streamPacketCipher struct {
macResult []byte macResult []byte
} }
// readPacket reads and decrypt a single packet from the reader argument. // readCipherPacket reads and decrypt a single packet from the reader argument.
func (s *streamPacketCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) { func (s *streamPacketCipher) readCipherPacket(seqNum uint32, r io.Reader) ([]byte, error) {
if _, err := io.ReadFull(r, s.prefix[:]); err != nil { if _, err := io.ReadFull(r, s.prefix[:]); err != nil {
return nil, err 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 return s.packetData[:length-paddingLength-1], nil
} }
// writePacket encrypts and sends a packet of data to the writer argument // writeCipherPacket 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 { func (s *streamPacketCipher) writeCipherPacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error {
if len(packet) > maxPacket { if len(packet) > maxPacket {
return errors.New("ssh: packet too large") return errors.New("ssh: packet too large")
} }
@ -327,7 +327,7 @@ func newGCMCipher(key, iv, unusedMacKey []byte, unusedAlgs directionAlgorithms)
const gcmTagSize = 16 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 // Pad out to multiple of 16 bytes. This is different from the
// stream cipher because that encrypts the length too. // stream cipher because that encrypts the length too.
padding := byte(packetSizeMultiple - (1+len(packet))%packetSizeMultiple) 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 { if _, err := io.ReadFull(r, c.prefix[:]); err != nil {
return nil, err return nil, err
} }
@ -486,8 +486,8 @@ type cbcError string
func (e cbcError) Error() string { return string(e) } func (e cbcError) Error() string { return string(e) }
func (c *cbcCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) { func (c *cbcCipher) readCipherPacket(seqNum uint32, r io.Reader) ([]byte, error) {
p, err := c.readPacketLeaky(seqNum, r) p, err := c.readCipherPacketLeaky(seqNum, r)
if err != nil { if err != nil {
if _, ok := err.(cbcError); ok { if _, ok := err.(cbcError); ok {
// Verification error: read a fixed amount of // 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 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() blockSize := c.decrypter.BlockSize()
// Read the header, which will include some of the subsequent data in the // 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 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()) effectiveBlockSize := maxUInt32(cbcMinPacketSizeMultiple, c.encrypter.BlockSize())
// Length of encrypted portion of the packet (header, payload, padding). // Length of encrypted portion of the packet (header, payload, padding).
@ -665,7 +665,11 @@ func newChaCha20Cipher(key, unusedIV, unusedMACKey []byte, unusedAlgs directionA
return c, nil return c, nil
} }
<<<<<<< HEAD
func (c *chacha20Poly1305Cipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) { func (c *chacha20Poly1305Cipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) {
=======
func (c *chacha20Poly1305Cipher) readCipherPacket(seqNum uint32, r io.Reader) ([]byte, error) {
>>>>>>> bd25a1f6d07d2d464980e6a8576c1ed59bb3950a
nonce := [3]uint32{0, 0, bits.ReverseBytes32(seqNum)} nonce := [3]uint32{0, 0, bits.ReverseBytes32(seqNum)}
s := chacha20.New(c.contentKey, nonce) s := chacha20.New(c.contentKey, nonce)
var polyKey [32]byte var polyKey [32]byte
@ -723,7 +727,11 @@ func (c *chacha20Poly1305Cipher) readPacket(seqNum uint32, r io.Reader) ([]byte,
return plain, nil return plain, nil
} }
<<<<<<< HEAD
func (c *chacha20Poly1305Cipher) writePacket(seqNum uint32, w io.Writer, rand io.Reader, payload []byte) error { 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 {
>>>>>>> bd25a1f6d07d2d464980e6a8576c1ed59bb3950a
nonce := [3]uint32{0, 0, bits.ReverseBytes32(seqNum)} nonce := [3]uint32{0, 0, bits.ReverseBytes32(seqNum)}
s := chacha20.New(c.contentKey, nonce) s := chacha20.New(c.contentKey, nonce)
var polyKey [32]byte var polyKey [32]byte

View File

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

View File

@ -10,6 +10,11 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
<<<<<<< HEAD
=======
"log"
"net"
>>>>>>> bd25a1f6d07d2d464980e6a8576c1ed59bb3950a
"os" "os"
"strings" "strings"
"testing" "testing"
@ -477,7 +482,7 @@ func TestRetryableAuth(t *testing.T) {
} }
} }
func ExampleRetryableAuthMethod(t *testing.T) { func ExampleRetryableAuthMethod() {
user := "testuser" user := "testuser"
NumberOfPrompts := 3 NumberOfPrompts := 3
@ -495,9 +500,17 @@ func ExampleRetryableAuthMethod(t *testing.T) {
}, },
} }
if err := tryAuth(t, config); err != nil { host := "mysshserver"
t.Fatalf("unable to dial remote side: %s", err) 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 // 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) 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 { type directionAlgorithms struct {
Cipher string Cipher string
MAC string MAC string
@ -137,7 +138,7 @@ type algorithms struct {
r directionAlgorithms 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 := &algorithms{}
result.kex, err = findCommon("key exchange", clientKexInit.KexAlgos, serverKexInit.KexAlgos) result.kex, err = findCommon("key exchange", clientKexInit.KexAlgos, serverKexInit.KexAlgos)
@ -150,32 +151,37 @@ func findAgreedAlgorithms(clientKexInit, serverKexInit *kexInitMsg) (algs *algor
return 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 { if err != nil {
return 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 { if err != nil {
return 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 { if err != nil {
return 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 { if err != nil {
return 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 { if err != nil {
return 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 { if err != nil {
return 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 // Every client must provide a host key check. Here is a
// simple-minded parse of OpenSSH's known_hosts file // simple-minded parse of OpenSSH's known_hosts file
host := "hostname" host := "hostname"

View File

@ -543,7 +543,8 @@ func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error {
clientInit := otherInit clientInit := otherInit
serverInit := t.sentInitMsg serverInit := t.sentInitMsg
if len(t.hostKeys) == 0 { isClient := len(t.hostKeys) == 0
if isClient {
clientInit, serverInit = serverInit, clientInit clientInit, serverInit = serverInit, clientInit
magics.clientKexInit = t.sentInitPacket magics.clientKexInit = t.sentInitPacket
@ -551,7 +552,7 @@ func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error {
} }
var err error var err error
t.algorithms, err = findAgreedAlgorithms(clientInit, serverInit) t.algorithms, err = findAgreedAlgorithms(isClient, clientInit, serverInit)
if err != nil { if err != nil {
return err 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) return db.checkAddr(hostToCheck, remoteKey)
} }
// checkAddrs checks if we can find the given public key for any of // checkAddr checks if we can find the given public key for the
// the given addresses. If we only find an entry for the IP address, // given address. If we only find an entry for the IP address,
// or only the hostname, then this still succeeds. // or only the hostname, then this still succeeds.
func (db *hostKeyDB) checkAddr(a addr, remoteKey ssh.PublicKey) error { func (db *hostKeyDB) checkAddr(a addr, remoteKey ssh.PublicKey) error {
// TODO(hanwen): are these the right semantics? What if there // 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 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"]) conf.AddHostKey(testSigners["rsa"])
_, chans, reqs, err := NewServerConn(c1, &conf) conn, chans, reqs, err := NewServerConn(c1, &conf)
if err != nil { if err != nil {
t.Fatalf("Unable to handshake: %v", err) t.Fatalf("Unable to handshake: %v", err)
} }
@ -56,6 +56,9 @@ func dial(handler serverType, t *testing.T) *Client {
handler(ch, inReqs, t) handler(ch, inReqs, t)
}() }()
} }
if err := conn.Wait(); err != io.EOF {
t.Logf("server exit reason: %v", err)
}
}() }()
config := &ClientConfig{ config := &ClientConfig{
@ -358,10 +361,9 @@ func TestServerWindow(t *testing.T) {
} }
written, err := copyNRandomly("stdin", serverStdin, origBuf, windowTestBytes) written, err := copyNRandomly("stdin", serverStdin, origBuf, windowTestBytes)
if err != nil { if err != nil {
t.Fatalf("failed to copy origBuf to serverStdin: %v", err) t.Errorf("failed to copy origBuf to serverStdin: %v", err)
} } else if written != windowTestBytes {
if written != windowTestBytes { t.Errorf("Wrote only %d of %d bytes to server", written, windowTestBytes)
t.Fatalf("Wrote only %d of %d bytes to server", written, windowTestBytes)
} }
echoedBytes := <-result echoedBytes := <-result

View File

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

View File

@ -91,6 +91,12 @@ var keyPressTests = []struct {
{ {
in: "\x1b[B\r", // down in: "\x1b[B\r", // down
}, },
{
in: "\016\r", // ^P
},
{
in: "\014\r", // ^N
},
{ {
in: "line\x1b[A\x1b[B\r", // up then down in: "line\x1b[A\x1b[B\r", // up then down
line: "line", 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) { func TestPasswordNotSaved(t *testing.T) {
c := &MockTerminal{ c := &MockTerminal{
toSend: []byte("password\r\x1b[A\r"), toSend: []byte("password\r\x1b[A\r"),

View File

@ -64,13 +64,19 @@ func Restore(fd int, state *State) error {
return windows.SetConsoleMode(windows.Handle(fd), state.mode) 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) { func GetSize(fd int) (width, height int, err error) {
var info windows.ConsoleScreenBufferInfo var info windows.ConsoleScreenBufferInfo
if err := windows.GetConsoleScreenBufferInfo(windows.Handle(fd), &info); err != nil { if err := windows.GetConsoleScreenBufferInfo(windows.Handle(fd), &info); err != nil {
return 0, 0, err return 0, 0, err
} }
<<<<<<< HEAD
return int(info.Size.X), int(info.Size.Y), nil 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
>>>>>>> bd25a1f6d07d2d464980e6a8576c1ed59bb3950a
} }
// ReadPassword reads a line of input from a terminal without local echo. This // 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 // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // 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 package test

View File

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

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // 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 package test

View File

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

View File

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

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // 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 package test
@ -306,7 +306,17 @@ func newServerForConfig(t *testing.T, config string, configVars map[string]strin
if err != nil { if err != nil {
t.Fatalf("user.Current: %v", err) t.Fatalf("user.Current: %v", err)
} }
<<<<<<< HEAD
if u.Name == "root" { 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" {
>>>>>>> bd25a1f6d07d2d464980e6a8576c1ed59bb3950a
t.Skip("skipping test because current user is root") t.Skip("skipping test because current user is root")
} }
dir, err := ioutil.TempDir("", "sshtest") dir, err := ioutil.TempDir("", "sshtest")

View File

@ -53,14 +53,14 @@ type transport struct {
// packetCipher represents a combination of SSH encryption/MAC // packetCipher represents a combination of SSH encryption/MAC
// protocol. A single instance should be used for one direction only. // protocol. A single instance should be used for one direction only.
type packetCipher interface { 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. // 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 // returned packet may be overwritten by future calls of
// readPacket. // 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 // 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) { 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++ s.seqNum++
if err == nil && len(packet) == 0 { if err == nil && len(packet) == 0 {
err = errors.New("ssh: zero length packet") 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 { func (s *connectionState) writePacket(w *bufio.Writer, rand io.Reader, packet []byte) error {
changeKeys := len(packet) > 0 && packet[0] == msgNewKeys 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 { if err != nil {
return err return err
} }

View File

@ -5,6 +5,17 @@
// Package tea implements the TEA algorithm, as defined in Needham and // Package tea implements the TEA algorithm, as defined in Needham and
// Wheeler's 1994 technical report, “TEA, a Tiny Encryption Algorithm”. See // Wheeler's 1994 technical report, “TEA, a Tiny Encryption Algorithm”. See
// http://www.cix.co.uk/~klockstone/tea.pdf for details. // http://www.cix.co.uk/~klockstone/tea.pdf for details.
<<<<<<< HEAD
=======
//
// 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).
>>>>>>> bd25a1f6d07d2d464980e6a8576c1ed59bb3950a
package tea package tea
import ( import (

View File

@ -3,6 +3,12 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// Package twofish implements Bruce Schneier's Twofish encryption algorithm. // 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" package twofish // import "golang.org/x/crypto/twofish"
// Twofish is defined in https://www.schneier.com/paper-twofish-paper.pdf [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 // Package xtea implements XTEA encryption, as defined in Needham and Wheeler's
// 1997 technical report, "Tea extensions." // 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" package xtea // import "golang.org/x/crypto/xtea"
// For details, see http://www.cix.co.uk/~klockstone/xtea.pdf // For details, see http://www.cix.co.uk/~klockstone/xtea.pdf

View File

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

View File

@ -103,3 +103,22 @@ func TestShorterCiphertext(t *testing.T) {
t.Errorf("En/Decryption is not inverse") t.Errorf("En/Decryption is not inverse")
} }
} }
<<<<<<< HEAD
=======
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)
}
}
>>>>>>> bd25a1f6d07d2d464980e6a8576c1ed59bb3950a

View File

@ -12,6 +12,8 @@ import (
"golang.org/x/net/bpf" "golang.org/x/net/bpf"
"golang.org/x/net/ipv4" "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 // 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 // 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. // packets into a UDP listener with a BPF program attached to it.
func testOSVM(t *testing.T, filter []bpf.Instruction) (virtualMachine, func()) { 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 { if err != nil {
t.Fatalf("failed to open OS VM UDP listener: %v", err) 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) t.Fatalf("failed to compile BPF program: %v", err)
} }
p := ipv4.NewPacketConn(l) ip := l.LocalAddr().(*net.UDPAddr).IP
if err = p.SetBPF(prog); err != nil { 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) 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 { if err != nil {
t.Fatalf("failed to dial connection to listener: %v", err) t.Fatalf("failed to dial connection to listener: %v", err)
} }

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

@ -0,0 +1,6 @@
module golang.org/x/net
require (
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2
golang.org/x/text v0.3.0
)

6
x/net/go.sum Normal file
View File

@ -0,0 +1,6 @@
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

View File

@ -177,7 +177,11 @@ func (s *nodeStack) index(n *Node) int {
// contains returns whether a is within s. // contains returns whether a is within s.
func (s *nodeStack) contains(a atom.Atom) bool { func (s *nodeStack) contains(a atom.Atom) bool {
for _, n := range *s { for _, n := range *s {
<<<<<<< HEAD
if n.DataAtom == a { if n.DataAtom == a {
=======
if n.DataAtom == a && n.Namespace == "" {
>>>>>>> bd25a1f6d07d2d464980e6a8576c1ed59bb3950a
return true return true
} }
} }

View File

@ -439,9 +439,12 @@ func (p *parser) resetInsertionMode() {
case a.Select: case a.Select:
if !last { if !last {
for ancestor, first := n, p.oe[0]; ancestor != first; { for ancestor, first := n, p.oe[0]; ancestor != first; {
<<<<<<< HEAD
if ancestor == first { if ancestor == first {
break break
} }
=======
>>>>>>> bd25a1f6d07d2d464980e6a8576c1ed59bb3950a
ancestor = p.oe[p.oe.index(ancestor)-1] ancestor = p.oe[p.oe.index(ancestor)-1]
switch ancestor.DataAtom { switch ancestor.DataAtom {
case a.Template: case a.Template:
@ -633,7 +636,16 @@ func inHeadIM(p *parser) bool {
p.oe.pop() p.oe.pop()
p.acknowledgeSelfClosingTag() p.acknowledgeSelfClosingTag()
return true return true
case a.Script, a.Title, a.Noscript, a.Noframes, a.Style: case a.Noscript:
p.addElement()
if p.scripting {
p.setOriginalIM()
p.im = textIM
} else {
p.im = inHeadNoscriptIM
}
return true
case a.Script, a.Title, a.Noframes, a.Style:
p.addElement() p.addElement()
p.setOriginalIM() p.setOriginalIM()
p.im = textIM p.im = textIM
@ -695,6 +707,52 @@ func inHeadIM(p *parser) bool {
return false return false
} }
<<<<<<< HEAD
=======
// 12.2.6.4.5.
func inHeadNoscriptIM(p *parser) bool {
switch p.tok.Type {
case DoctypeToken:
// Ignore the token.
return true
case StartTagToken:
switch p.tok.DataAtom {
case a.Html:
return inBodyIM(p)
case a.Basefont, a.Bgsound, a.Link, a.Meta, a.Noframes, a.Style:
return inHeadIM(p)
case a.Head, a.Noscript:
// Ignore the token.
return true
}
case EndTagToken:
switch p.tok.DataAtom {
case a.Noscript, a.Br:
default:
// Ignore the token.
return true
}
case TextToken:
s := strings.TrimLeft(p.tok.Data, whitespace)
if len(s) == 0 {
// It was all whitespace.
return inHeadIM(p)
}
case CommentToken:
return inHeadIM(p)
}
p.oe.pop()
if p.top().DataAtom != a.Head {
panic("html: the new current node will be a head element.")
}
p.im = inHeadIM
if p.tok.DataAtom == a.Noscript {
return true
}
return false
}
>>>>>>> bd25a1f6d07d2d464980e6a8576c1ed59bb3950a
// Section 12.2.6.4.6. // Section 12.2.6.4.6.
func afterHeadIM(p *parser) bool { func afterHeadIM(p *parser) bool {
switch p.tok.Type { switch p.tok.Type {
@ -904,7 +962,7 @@ func inBodyIM(p *parser) bool {
case a.A: case a.A:
for i := len(p.afe) - 1; i >= 0 && p.afe[i].Type != scopeMarkerNode; i-- { for i := len(p.afe) - 1; i >= 0 && p.afe[i].Type != scopeMarkerNode; i-- {
if n := p.afe[i]; n.Type == ElementNode && n.DataAtom == a.A { if n := p.afe[i]; n.Type == ElementNode && n.DataAtom == a.A {
p.inBodyEndTagFormatting(a.A) p.inBodyEndTagFormatting(a.A, "a")
p.oe.remove(n) p.oe.remove(n)
p.afe.remove(n) p.afe.remove(n)
break break
@ -918,7 +976,7 @@ func inBodyIM(p *parser) bool {
case a.Nobr: case a.Nobr:
p.reconstructActiveFormattingElements() p.reconstructActiveFormattingElements()
if p.elementInScope(defaultScope, a.Nobr) { if p.elementInScope(defaultScope, a.Nobr) {
p.inBodyEndTagFormatting(a.Nobr) p.inBodyEndTagFormatting(a.Nobr, "nobr")
p.reconstructActiveFormattingElements() p.reconstructActiveFormattingElements()
} }
p.addFormattingElement() p.addFormattingElement()
@ -1126,7 +1184,7 @@ func inBodyIM(p *parser) bool {
case a.H1, a.H2, a.H3, a.H4, a.H5, a.H6: case a.H1, a.H2, a.H3, a.H4, a.H5, a.H6:
p.popUntil(defaultScope, a.H1, a.H2, a.H3, a.H4, a.H5, a.H6) p.popUntil(defaultScope, a.H1, a.H2, a.H3, a.H4, a.H5, a.H6)
case a.A, a.B, a.Big, a.Code, a.Em, a.Font, a.I, a.Nobr, a.S, a.Small, a.Strike, a.Strong, a.Tt, a.U: case a.A, a.B, a.Big, a.Code, a.Em, a.Font, a.I, a.Nobr, a.S, a.Small, a.Strike, a.Strong, a.Tt, a.U:
p.inBodyEndTagFormatting(p.tok.DataAtom) p.inBodyEndTagFormatting(p.tok.DataAtom, p.tok.Data)
case a.Applet, a.Marquee, a.Object: case a.Applet, a.Marquee, a.Object:
if p.popUntil(defaultScope, p.tok.DataAtom) { if p.popUntil(defaultScope, p.tok.DataAtom) {
p.clearActiveFormattingElements() p.clearActiveFormattingElements()
@ -1137,7 +1195,7 @@ func inBodyIM(p *parser) bool {
case a.Template: case a.Template:
return inHeadIM(p) return inHeadIM(p)
default: default:
p.inBodyEndTagOther(p.tok.DataAtom) p.inBodyEndTagOther(p.tok.DataAtom, p.tok.Data)
} }
case CommentToken: case CommentToken:
p.addChild(&Node{ p.addChild(&Node{
@ -1164,7 +1222,7 @@ func inBodyIM(p *parser) bool {
return true return true
} }
func (p *parser) inBodyEndTagFormatting(tagAtom a.Atom) { func (p *parser) inBodyEndTagFormatting(tagAtom a.Atom, tagName string) {
// This is the "adoption agency" algorithm, described at // This is the "adoption agency" algorithm, described at
// https://html.spec.whatwg.org/multipage/syntax.html#adoptionAgency // https://html.spec.whatwg.org/multipage/syntax.html#adoptionAgency
@ -1186,7 +1244,7 @@ func (p *parser) inBodyEndTagFormatting(tagAtom a.Atom) {
} }
} }
if formattingElement == nil { if formattingElement == nil {
p.inBodyEndTagOther(tagAtom) p.inBodyEndTagOther(tagAtom, tagName)
return return
} }
feIndex := p.oe.index(formattingElement) feIndex := p.oe.index(formattingElement)
@ -1291,9 +1349,17 @@ func (p *parser) inBodyEndTagFormatting(tagAtom a.Atom) {
// inBodyEndTagOther performs the "any other end tag" algorithm for inBodyIM. // inBodyEndTagOther performs the "any other end tag" algorithm for inBodyIM.
// "Any other end tag" handling from 12.2.6.5 The rules for parsing tokens in foreign content // "Any other end tag" handling from 12.2.6.5 The rules for parsing tokens in foreign content
// https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inforeign // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inforeign
func (p *parser) inBodyEndTagOther(tagAtom a.Atom) { func (p *parser) inBodyEndTagOther(tagAtom a.Atom, tagName string) {
for i := len(p.oe) - 1; i >= 0; i-- { for i := len(p.oe) - 1; i >= 0; i-- {
if p.oe[i].DataAtom == tagAtom { // Two element nodes have the same tag if they have the same Data (a
// string-typed field). As an optimization, for common HTML tags, each
// Data string is assigned a unique, non-zero DataAtom (a uint32-typed
// field), since integer comparison is faster than string comparison.
// Uncommon (custom) tags get a zero DataAtom.
//
// The if condition here is equivalent to (p.oe[i].Data == tagName).
if (p.oe[i].DataAtom == tagAtom) &&
((tagAtom != 0) || (p.oe[i].Data == tagName)) {
p.oe = p.oe[:i] p.oe = p.oe[:i]
break break
} }
@ -1687,8 +1753,9 @@ func inCellIM(p *parser) bool {
return true return true
} }
// Close the cell and reprocess. // Close the cell and reprocess.
p.popUntil(tableScope, a.Td, a.Th) if p.popUntil(tableScope, a.Td, a.Th) {
p.clearActiveFormattingElements() p.clearActiveFormattingElements()
}
p.im = inRowIM p.im = inRowIM
return false return false
} }
@ -1719,8 +1786,12 @@ func inSelectIM(p *parser) bool {
} }
p.addElement() p.addElement()
case a.Select: case a.Select:
p.tok.Type = EndTagToken if p.popUntil(selectScope, a.Select) {
return false p.resetInsertionMode()
} else {
// Ignore the token.
return true
}
case a.Input, a.Keygen, a.Textarea: case a.Input, a.Keygen, a.Textarea:
if p.elementInScope(selectScope, a.Select) { if p.elementInScope(selectScope, a.Select) {
p.parseImpliedToken(EndTagToken, a.Select, a.Select.String()) p.parseImpliedToken(EndTagToken, a.Select, a.Select.String())
@ -1750,6 +1821,9 @@ func inSelectIM(p *parser) bool {
case a.Select: case a.Select:
if p.popUntil(selectScope, a.Select) { if p.popUntil(selectScope, a.Select) {
p.resetInsertionMode() p.resetInsertionMode()
} else {
// Ignore the token.
return true
} }
case a.Template: case a.Template:
return inHeadIM(p) return inHeadIM(p)
@ -1775,13 +1849,22 @@ func inSelectInTableIM(p *parser) bool {
case StartTagToken, EndTagToken: case StartTagToken, EndTagToken:
switch p.tok.DataAtom { switch p.tok.DataAtom {
case a.Caption, a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr, a.Td, a.Th: case a.Caption, a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr, a.Td, a.Th:
if p.tok.Type == StartTagToken || p.elementInScope(tableScope, p.tok.DataAtom) { if p.tok.Type == EndTagToken && !p.elementInScope(tableScope, p.tok.DataAtom) {
p.parseImpliedToken(EndTagToken, a.Select, a.Select.String())
return false
} else {
// Ignore the token. // Ignore the token.
return true return true
} }
// This is like p.popUntil(selectScope, a.Select), but it also
// matches <math select>, not just <select>. Matching the MathML
// tag is arguably incorrect (conceptually), but it mimics what
// Chromium does.
for i := len(p.oe) - 1; i >= 0; i-- {
if n := p.oe[i]; n.DataAtom == a.Select {
p.oe = p.oe[:i]
break
}
}
p.resetInsertionMode()
return false
} }
} }
return inSelectIM(p) return inSelectIM(p)
@ -2226,6 +2309,33 @@ func (p *parser) parse() error {
// //
// The input is assumed to be UTF-8 encoded. // The input is assumed to be UTF-8 encoded.
func Parse(r io.Reader) (*Node, error) { func Parse(r io.Reader) (*Node, error) {
return ParseWithOptions(r)
}
// ParseFragment parses a fragment of HTML and returns the nodes that were
// found. If the fragment is the InnerHTML for an existing element, pass that
// element in context.
//
// It has the same intricacies as Parse.
func ParseFragment(r io.Reader, context *Node) ([]*Node, error) {
return ParseFragmentWithOptions(r, context)
}
// ParseOption configures a parser.
type ParseOption func(p *parser)
// ParseOptionEnableScripting configures the scripting flag.
// https://html.spec.whatwg.org/multipage/webappapis.html#enabling-and-disabling-scripting
//
// By default, scripting is enabled.
func ParseOptionEnableScripting(enable bool) ParseOption {
return func(p *parser) {
p.scripting = enable
}
}
// ParseWithOptions is like Parse, with options.
func ParseWithOptions(r io.Reader, opts ...ParseOption) (*Node, error) {
p := &parser{ p := &parser{
tokenizer: NewTokenizer(r), tokenizer: NewTokenizer(r),
doc: &Node{ doc: &Node{
@ -2235,6 +2345,11 @@ func Parse(r io.Reader) (*Node, error) {
framesetOK: true, framesetOK: true,
im: initialIM, im: initialIM,
} }
for _, f := range opts {
f(p)
}
err := p.parse() err := p.parse()
if err != nil { if err != nil {
return nil, err return nil, err
@ -2242,12 +2357,17 @@ func Parse(r io.Reader) (*Node, error) {
return p.doc, nil return p.doc, nil
} }
<<<<<<< HEAD
// ParseFragment parses a fragment of HTML and returns the nodes that were // ParseFragment parses a fragment of HTML and returns the nodes that were
// found. If the fragment is the InnerHTML for an existing element, pass that // found. If the fragment is the InnerHTML for an existing element, pass that
// element in context. // element in context.
// //
// It has the same intricacies as Parse. // It has the same intricacies as Parse.
func ParseFragment(r io.Reader, context *Node) ([]*Node, error) { func ParseFragment(r io.Reader, context *Node) ([]*Node, error) {
=======
// ParseFragmentWithOptions is like ParseFragment, with options.
func ParseFragmentWithOptions(r io.Reader, context *Node, opts ...ParseOption) ([]*Node, error) {
>>>>>>> bd25a1f6d07d2d464980e6a8576c1ed59bb3950a
contextTag := "" contextTag := ""
if context != nil { if context != nil {
if context.Type != ElementNode { if context.Type != ElementNode {
@ -2271,6 +2391,10 @@ func ParseFragment(r io.Reader, context *Node) ([]*Node, error) {
context: context, context: context,
} }
for _, f := range opts {
f(p)
}
root := &Node{ root := &Node{
Type: ElementNode, Type: ElementNode,
DataAtom: a.Html, DataAtom: a.Html,

View File

@ -238,11 +238,30 @@ func TestParser(t *testing.T) {
} }
} }
// Issue 16318
func TestParserWithoutScripting(t *testing.T) {
text := `<noscript><img src='https://golang.org/doc/gopher/frontpage.png' /></noscript><p><img src='https://golang.org/doc/gopher/doc.png' /></p>`
want := `| <html>
| <head>
| <noscript>
| <body>
| "<img src='https://golang.org/doc/gopher/frontpage.png' />"
| <p>
| <img>
| src="https://golang.org/doc/gopher/doc.png"
`
err := testParseCase(text, want, "", ParseOptionEnableScripting(false))
if err != nil {
t.Errorf("test with scripting is disabled, %q, %s", text, err)
}
}
// testParseCase tests one test case from the test files. If the test does not // testParseCase tests one test case from the test files. If the test does not
// pass, it returns an error that explains the failure. // pass, it returns an error that explains the failure.
// text is the HTML to be parsed, want is a dump of the correct parse tree, // text is the HTML to be parsed, want is a dump of the correct parse tree,
// and context is the name of the context node, if any. // and context is the name of the context node, if any.
func testParseCase(text, want, context string) (err error) { func testParseCase(text, want, context string, opts ...ParseOption) (err error) {
defer func() { defer func() {
if x := recover(); x != nil { if x := recover(); x != nil {
switch e := x.(type) { switch e := x.(type) {
@ -256,7 +275,7 @@ func testParseCase(text, want, context string) (err error) {
var doc *Node var doc *Node
if context == "" { if context == "" {
doc, err = Parse(strings.NewReader(text)) doc, err = ParseWithOptions(strings.NewReader(text), opts...)
if err != nil { if err != nil {
return err return err
} }
@ -266,7 +285,7 @@ func testParseCase(text, want, context string) (err error) {
DataAtom: atom.Lookup([]byte(context)), DataAtom: atom.Lookup([]byte(context)),
Data: context, Data: context,
} }
nodes, err := ParseFragment(strings.NewReader(text), contextNode) nodes, err := ParseFragmentWithOptions(strings.NewReader(text), contextNode, opts...)
if err != nil { if err != nil {
return err return err
} }
@ -367,7 +386,8 @@ var renderTestBlacklist = map[string]bool{
`<script><!--<script </s`: true, `<script><!--<script </s`: true,
// Reconstructing the active formatting elements results in a <plaintext> // Reconstructing the active formatting elements results in a <plaintext>
// element that contains an <a> element. // element that contains an <a> element.
`<!doctype html><p><a><plaintext>b`: true, `<!doctype html><p><a><plaintext>b`: true,
`<table><math><select><mi><select></table>`: true,
} }
func TestNodeConsistency(t *testing.T) { func TestNodeConsistency(t *testing.T) {

View File

@ -0,0 +1,12 @@
#data
<table><math><th><mo><select></table>
#errors
#document
| <html>
| <head>
| <body>
| <math math>
| <math th>
| <math mo>
| <select>
| <table>

View File

@ -0,0 +1,11 @@
#data
<html><head></head><body><tag1><tag2 /><p></p></tag1><div></div></body></html>
#errors
#document
| <html>
| <head>
| <body>
| <tag1>
| <tag2>
| <p>
| <div>

12
x/net/html/testdata/go/select.dat vendored Normal file
View File

@ -0,0 +1,12 @@
#data
<table><math><select><mi><select></table>
#errors
#document
| <html>
| <head>
| <body>
| <math math>
| <math select>
| <math mi>
| <select>
| <table>

View File

@ -35,3 +35,31 @@
| <math mo> | <math mo>
| <template> | <template>
| content | content
<<<<<<< HEAD
=======
#data
<svg><template><desc><t><svg></template>
#errors
#document
| <html>
| <head>
| <body>
| <svg svg>
| <svg template>
| <svg desc>
| <t>
| <svg svg>
#data
<math><template><mn><b></template>
#errors
#document
| <html>
| <head>
| <body>
| <math math>
| <math template>
| <math mn>
| <b>
>>>>>>> bd25a1f6d07d2d464980e6a8576c1ed59bb3950a

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